diff --git a/parsifal/DESCR b/parsifal/DESCR new file mode 100644 index 0000000000..f333bc41ba --- /dev/null +++ b/parsifal/DESCR @@ -0,0 +1 @@ +Parsifal is minimal non-validating XML parser written in ANSI C. Parsifal implements the subset of SAX2 including namespace support. diff --git a/parsifal/Makefile b/parsifal/Makefile new file mode 100644 index 0000000000..7e19556f57 --- /dev/null +++ b/parsifal/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.1.1.1 2004/01/10 20:35:13 ora8_ Exp $ + +DISTNAME= libparsifal-0.7.3 +CATEGORIES= textproc +MASTER_SITES= http://www.saunalahti.fi/~samiuus/toni/xmlproc/ + +MAINTAINER= josediazfer@yahoo.es +HOMEPAGE= http://www.saunalahti.fi/~samiuus/toni/xmlproc/ +COMMENT= XML parser with implementation SAX2 + +HAS_CONFIGURE= YES + +CONFIGURE_ARGS+=--prefix=${LOCALBASE} + +.include "../../mk/bsd.pkg.mk" diff --git a/parsifal/PLIST b/parsifal/PLIST new file mode 100644 index 0000000000..81ab0b2ac2 --- /dev/null +++ b/parsifal/PLIST @@ -0,0 +1,12 @@ +@comment $NetBSD: PLIST,v 1.1.1.1 2004/01/10 20:35:13 ora8_ Exp $ +include/libparsifal/bistream.h +include/libparsifal/isrcmem.h +include/libparsifal/parsifal.h +include/libparsifal/xmlhash.h +include/libparsifal/xmlsbuf.h +include/libparsifal/xmlvect.h +lib/${PKGNAME}.so +lib/libparsifal.a +lib/libparsifal.la +lib/libparsifal.so +@dirrm include/libparsifal diff --git a/parsifal/README b/parsifal/README new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/parsifal/README @@ -0,0 +1 @@ + diff --git a/parsifal/distinfo b/parsifal/distinfo new file mode 100644 index 0000000000..17294c183e --- /dev/null +++ b/parsifal/distinfo @@ -0,0 +1,5 @@ +$NetBSD: distinfo,v 1.1.1.1 2004/01/10 20:35:13 ora8_ Exp $ + +SHA1 (libparsifal-0.7.3.tar.gz) = 2faea72256929cdb98304ab473c55a06c760a04b +Size (libparsifal-0.7.3.tar.gz) = 385775 bytes +SHA1 (patch-aa) = 2a2d3e427b6252d55f7d099a3acf724524193e1a diff --git a/parsifal/patches/patch-aa b/parsifal/patches/patch-aa new file mode 100644 index 0000000000..5304cc2bc5 --- /dev/null +++ b/parsifal/patches/patch-aa @@ -0,0 +1,12015 @@ +Only in .: Makefile +Only in .: config.log +Only in .: config.status +Only in ./include: Makefile +Only in ./include/libparsifal: Makefile +diff -r ../src.orig/include/libparsifal/bistream.h ./include/libparsifal/bistream.h +--- ../src.orig/include/libparsifal/bistream.h Thu Oct 2 20:05:06 2003 ++++ ./include/libparsifal/bistream.h Wed Jan 7 23:43:23 2004 +@@ -1,99 +1,99 @@ +-/*=========================================================================== +- bistream.h +- see parsifal.h for copyright info +-===========================================================================*/ +- +-#ifndef BISTREAM__H +-#define BISTREAM__H +- +-#ifndef NULL +- #define NULL ((void *) 0) +-#endif +- +-#ifndef BYTE +- #define BYTE unsigned char +-#endif +- +-#ifndef COUNTBUFSIZE +-#define COUNTBUFSIZE(cBytes, blocksize) \ +-((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) +-#endif +- +-#define BISFIXBUF(size) \ +-if (r->buf == (BYTE*)NULL) { \ +- r->bytesavail = 0; \ +- if (NULL == (r->buf = (BYTE*)malloc(r->blocksize*sizeof(BYTE)))) \ +- return BIS_ERR_MEMALLOC; \ +- r->bufsize = r->blocksize; \ +-} \ +-else if ((NewBufSize = COUNTBUFSIZE((size), r->blocksize))!= r->bufsize) { \ +- if (NewBufSize > r->maxbufsize) return BIS_ERR_MAXBUF; \ +- if (NULL == (r->buf = (BYTE*)realloc(r->buf, NewBufSize*sizeof(BYTE)))) { \ +- r->bytesavail = 0; \ +- return BIS_ERR_MEMALLOC; \ +- } \ +- r->bufsize = NewBufSize; \ +-} +- +-#define BIS_DEFAULT_MAXBUFSIZE INT_MAX +-#define BIS_DEFAULT_BLOCKSIZE 512 +- +-enum BIS_ERRORS { BIS_ERR_MEMALLOC = -40, +- BIS_ERR_MAXBUF, +- BIS_ERR_INVALIDARG, +- BIS_ERR_ENCODING, +- BIS_ERR_USER, +- BIS_BREAKCHAR = -2 }; +- +-typedef int (*LPFNINPUTSRC)(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); +- +-typedef struct tagBUFFEREDISTREAM +-{ +- BYTE *buf; +- BYTE *ubuf; +- int bufsize; +- int maxbufsize; +- int blocksize; +- int bytesavail; +- int pos; +- int eof; +- int err; +- int usererr; +- void *userdata; +- void *inputData; +- LPFNINPUTSRC inputsrc; +- int (*encode)(struct tagBUFFEREDISTREAM *reader, BYTE *buf, int *cBytes); +-} BUFFEREDISTREAM, *LPBUFFEREDISTREAM; +- +-typedef int (*LPFNENCODE)(LPBUFFEREDISTREAM reader, BYTE *buf, int *cBytes); +-/* +-int BufferedIStream_Read(LPBUFFEREDISTREAM r, +- const BYTE *tok, +- int len, +- int offset, +- int readType, +- void *varParam, +- int varParamType); +-*/ +-int BufferedIStream_EncodeBuffer(LPBUFFEREDISTREAM r, +- int offset); +- +-int BufferedIStream_Peek(LPBUFFEREDISTREAM r, +- const BYTE *tok, +- int len, +- int offset); +- +-int BufferedIStream_ResetBuf(LPBUFFEREDISTREAM r, +- int numBytes); +-/* +-BYTE* BufferedIStream_ToString(LPBUFFEREDISTREAM r, +- int startPos, +- int endPos); +-*/ +-LPBUFFEREDISTREAM BufferedIStream_Init(LPBUFFEREDISTREAM r, +- int blocksize); +- +-void BufferedIStream_Free(LPBUFFEREDISTREAM r); +- +-#endif /* BISTREAM__H */ +- ++/*=========================================================================== ++ bistream.h ++ see parsifal.h for copyright info ++===========================================================================*/ ++ ++#ifndef BISTREAM__H ++#define BISTREAM__H ++ ++#ifndef NULL ++ #define NULL ((void *) 0) ++#endif ++ ++#ifndef BYTE ++ #define BYTE unsigned char ++#endif ++ ++#ifndef COUNTBUFSIZE ++#define COUNTBUFSIZE(cBytes, blocksize) \ ++((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) ++#endif ++ ++#define BISFIXBUF(size) \ ++if (r->buf == (BYTE*)NULL) { \ ++ r->bytesavail = 0; \ ++ if (NULL == (r->buf = (BYTE*)malloc(r->blocksize*sizeof(BYTE)))) \ ++ return BIS_ERR_MEMALLOC; \ ++ r->bufsize = r->blocksize; \ ++} \ ++else if ((NewBufSize = COUNTBUFSIZE((size), r->blocksize))!= r->bufsize) { \ ++ if (NewBufSize > r->maxbufsize) return BIS_ERR_MAXBUF; \ ++ if (NULL == (r->buf = (BYTE*)realloc(r->buf, NewBufSize*sizeof(BYTE)))) { \ ++ r->bytesavail = 0; \ ++ return BIS_ERR_MEMALLOC; \ ++ } \ ++ r->bufsize = NewBufSize; \ ++} ++ ++#define BIS_DEFAULT_MAXBUFSIZE INT_MAX ++#define BIS_DEFAULT_BLOCKSIZE 512 ++ ++enum BIS_ERRORS { BIS_ERR_MEMALLOC = -40, ++ BIS_ERR_MAXBUF, ++ BIS_ERR_INVALIDARG, ++ BIS_ERR_ENCODING, ++ BIS_ERR_USER, ++ BIS_BREAKCHAR = -2 }; ++ ++typedef int (*LPFNINPUTSRC)(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); ++ ++typedef struct tagBUFFEREDISTREAM ++{ ++ BYTE *buf; ++ BYTE *ubuf; ++ int bufsize; ++ int maxbufsize; ++ int blocksize; ++ int bytesavail; ++ int pos; ++ int eof; ++ int err; ++ int usererr; ++ void *userdata; ++ void *inputData; ++ LPFNINPUTSRC inputsrc; ++ int (*encode)(struct tagBUFFEREDISTREAM *reader, BYTE *buf, int *cBytes); ++} BUFFEREDISTREAM, *LPBUFFEREDISTREAM; ++ ++typedef int (*LPFNENCODE)(LPBUFFEREDISTREAM reader, BYTE *buf, int *cBytes); ++/* ++int BufferedIStream_Read(LPBUFFEREDISTREAM r, ++ const BYTE *tok, ++ int len, ++ int offset, ++ int readType, ++ void *varParam, ++ int varParamType); ++*/ ++int BufferedIStream_EncodeBuffer(LPBUFFEREDISTREAM r, ++ int offset); ++ ++int BufferedIStream_Peek(LPBUFFEREDISTREAM r, ++ const BYTE *tok, ++ int len, ++ int offset); ++ ++int BufferedIStream_ResetBuf(LPBUFFEREDISTREAM r, ++ int numBytes); ++/* ++BYTE* BufferedIStream_ToString(LPBUFFEREDISTREAM r, ++ int startPos, ++ int endPos); ++*/ ++LPBUFFEREDISTREAM BufferedIStream_Init(LPBUFFEREDISTREAM r, ++ int blocksize); ++ ++void BufferedIStream_Free(LPBUFFEREDISTREAM r); ++ ++#endif /* BISTREAM__H */ ++ +diff -r ../src.orig/include/libparsifal/isrcmem.h ./include/libparsifal/isrcmem.h +--- ../src.orig/include/libparsifal/isrcmem.h Thu Oct 2 20:04:58 2003 ++++ ./include/libparsifal/isrcmem.h Wed Jan 7 23:43:23 2004 +@@ -1,60 +1,60 @@ +-/*=========================================================================== +- isrcmem.h +- Provides helper macros and typedefs for parsing memory buffers +- see parsifal.h for copyright info +- +- USAGE +- declare inputsource handler function (note param names +- must be exactly buf, cBytes etc.): +- +- int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); +- int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) +- { +- XMLMEMINPUTSRC_HANDLE +- } +- +- ..... +- +- LPXMLPARSER parser; +- XMLMEMINPUTSRC meminput; +- char *xml = "text"; +- +- XMLMEMINPUTSRC_INIT(&meminput, xml, strlen(xml)); +- XMLParser_Create(&parser); +- XMLParser_Parse(parser, MemInputsrc, &meminput, NULL); +- +- ..... +-===========================================================================*/ +- +-#ifndef ISRCMEM__H +-#define ISRCMEM__H +- +-typedef struct tagXMLMEMINPUTSRC +-{ +- BYTE *pBuf; +- unsigned long cTotal; +- unsigned long cBytes; +-} XMLMEMINPUTSRC, *LPXMLMEMINPUTSRC; +- +-#define XMLMEMINPUTSRC_INIT(lpMemISrc,buf,size) \ +- (((LPXMLMEMINPUTSRC)lpMemISrc)->cTotal=(size), \ +- ((LPXMLMEMINPUTSRC)lpMemISrc)->cBytes=0, \ +- ((LPXMLMEMINPUTSRC)lpMemISrc)->pBuf=(buf)) +- +-#define XMLMEMINPUTSRC_HANDLE \ +- if ((((LPXMLMEMINPUTSRC)inputData)->cBytes + cBytes) < ((LPXMLMEMINPUTSRC)inputData)->cTotal) { \ +- memcpy(buf, ((LPXMLMEMINPUTSRC)inputData)->pBuf+((LPXMLMEMINPUTSRC)inputData)->cBytes, cBytes); \ +- *cBytesActual = cBytes; \ +- ((LPXMLMEMINPUTSRC)inputData)->cBytes += cBytes; \ +- return 0; \ +- } \ +- else { \ +- *cBytesActual = ((LPXMLMEMINPUTSRC)inputData)->cTotal - ((LPXMLMEMINPUTSRC)inputData)->cBytes; \ +- if (*cBytesActual) { \ +- memcpy(buf, ((LPXMLMEMINPUTSRC)inputData)->pBuf+((LPXMLMEMINPUTSRC)inputData)->cBytes, *cBytesActual); \ +- ((LPXMLMEMINPUTSRC)inputData)->cBytes += *cBytesActual; } \ +- return 1; \ +- } +- +-#endif /* ISRCMEM__H */ +- ++/*=========================================================================== ++ isrcmem.h ++ Provides helper macros and typedefs for parsing memory buffers ++ see parsifal.h for copyright info ++ ++ USAGE ++ declare inputsource handler function (note param names ++ must be exactly buf, cBytes etc.): ++ ++ int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); ++ int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) ++ { ++ XMLMEMINPUTSRC_HANDLE ++ } ++ ++ ..... ++ ++ LPXMLPARSER parser; ++ XMLMEMINPUTSRC meminput; ++ char *xml = "text"; ++ ++ XMLMEMINPUTSRC_INIT(&meminput, xml, strlen(xml)); ++ XMLParser_Create(&parser); ++ XMLParser_Parse(parser, MemInputsrc, &meminput, NULL); ++ ++ ..... ++===========================================================================*/ ++ ++#ifndef ISRCMEM__H ++#define ISRCMEM__H ++ ++typedef struct tagXMLMEMINPUTSRC ++{ ++ BYTE *pBuf; ++ unsigned long cTotal; ++ unsigned long cBytes; ++} XMLMEMINPUTSRC, *LPXMLMEMINPUTSRC; ++ ++#define XMLMEMINPUTSRC_INIT(lpMemISrc,buf,size) \ ++ (((LPXMLMEMINPUTSRC)lpMemISrc)->cTotal=(size), \ ++ ((LPXMLMEMINPUTSRC)lpMemISrc)->cBytes=0, \ ++ ((LPXMLMEMINPUTSRC)lpMemISrc)->pBuf=(buf)) ++ ++#define XMLMEMINPUTSRC_HANDLE \ ++ if ((((LPXMLMEMINPUTSRC)inputData)->cBytes + cBytes) < ((LPXMLMEMINPUTSRC)inputData)->cTotal) { \ ++ memcpy(buf, ((LPXMLMEMINPUTSRC)inputData)->pBuf+((LPXMLMEMINPUTSRC)inputData)->cBytes, cBytes); \ ++ *cBytesActual = cBytes; \ ++ ((LPXMLMEMINPUTSRC)inputData)->cBytes += cBytes; \ ++ return 0; \ ++ } \ ++ else { \ ++ *cBytesActual = ((LPXMLMEMINPUTSRC)inputData)->cTotal - ((LPXMLMEMINPUTSRC)inputData)->cBytes; \ ++ if (*cBytesActual) { \ ++ memcpy(buf, ((LPXMLMEMINPUTSRC)inputData)->pBuf+((LPXMLMEMINPUTSRC)inputData)->cBytes, *cBytesActual); \ ++ ((LPXMLMEMINPUTSRC)inputData)->cBytes += *cBytesActual; } \ ++ return 1; \ ++ } ++ ++#endif /* ISRCMEM__H */ ++ +diff -r ../src.orig/include/libparsifal/nametab.h ./include/libparsifal/nametab.h +--- ../src.orig/include/libparsifal/nametab.h Thu Oct 2 20:04:50 2003 ++++ ./include/libparsifal/nametab.h Wed Jan 7 23:43:23 2004 +@@ -1,254 +1,254 @@ +-/*=========================================================================== +- nametab.h +- this header contains ASCII and UTF-8 tables for qualified +- name checking + macros for comparing multibyte UTF-8 sequences: +- UTF8_GET_NAMING2 and UTF8_GET_NAMING3 +- +- UTF8_GET_NAMING... and UTF-8 tables are stolen from EXPAT +- note: DO NOT increment parameters in these macro calls i.e. +- ISMAPCH(whitespace, *c++) will return invalid value +- +- memory usage: +- +- namingBitmap (16x80): 1280 bytes +- nmstrtPages & namePages (2x8x32) 512 bytes +- 4 ascii tables (4x32) 128 bytes +- --------------------------------------------------- +- total 1920 bytes +- +- TODO: fix ascii tables (separate to pages to save space) +- +- see parsifal.h for copyright info +-===========================================================================*/ +- +-#ifndef NAMETAB__H +-#define NAMETAB__H +- +-/* ascii tables generated by GENMAPS.C */ +-static const XMLCH nameStartAscii[32] = { +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x04, +-0xFE, 0xFF, 0xFF, 0x87, +-0xFE, 0xFF, 0xFF, 0x07, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00 +-}; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_: +- +-static const XMLCH nameAscii[32] = { +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x60, 0xFF, 0x07, +-0xFE, 0xFF, 0xFF, 0x87, +-0xFE, 0xFF, 0xFF, 0x07, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00 +-}; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_:0123456789.- +- +-static const XMLCH whitespace[32] = { +-0x00, 0x26, 0x00, 0x00, +-0x01, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00 +-}; +- +-/* global for both parsifal and encoding module: */ +-const XMLCH illByte[32] = { +-0xFF, 0xD9, 0xFF, 0xFF, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00 +-}; // from \0x0 to \0x1f excluding whitespace chars 0x9, 0xA, 0xD +- +-#define utf8_isName2(c) (UTF8_GET_NAMING2(namePages, (c))) +-#define utf8_isName3(c) (UTF8_GET_NAMING3(namePages, (c))) +-#define utf8_isNmstrt2(c) (UTF8_GET_NAMING2(nmstrtPages, (c))) +-#define utf8_isNmstrt3(c) (UTF8_GET_NAMING3(nmstrtPages, (c))) +- +-/* the rest is stolen from EXPAT: */ +- +-/* A 2 byte UTF-8 representation splits the characters 11 bits +-between the bottom 5 and 6 bits of the bytes. +-We need 8 bits to index into pages, 3 bits to add to that index and +-5 bits to generate the mask. */ +-#define UTF8_GET_NAMING2(pages, byte) \ +- (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ +- + ((((byte)[0]) & 3) << 1) \ +- + ((((byte)[1]) >> 5) & 1)] \ +- & (1 << (((byte)[1]) & 0x1F))) +- +-/* A 3 byte UTF-8 representation splits the characters 16 bits +-between the bottom 4, 6 and 6 bits of the bytes. +-We need 8 bits to index into pages, 3 bits to add to that index and +-5 bits to generate the mask. */ +-#define UTF8_GET_NAMING3(pages, byte) \ +- (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ +- + ((((byte)[1]) >> 2) & 0xF)] \ +- << 3) \ +- + ((((byte)[1]) & 3) << 1) \ +- + ((((byte)[2]) >> 5) & 1)] \ +- & (1 << (((byte)[2]) & 0x1F))) +- +-static const unsigned namingBitmap[] = { +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +-0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +-0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +-0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +-0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +-0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +-0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +-0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +-0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +-0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +-0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +-0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +-0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +-0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +-0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +-0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +-0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +-0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +-0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +-0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +-0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +-0x40000000, 0xF580C900, 0x00000007, 0x02010800, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +-0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +-0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +-0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +-0x00000000, 0x00004C40, 0x00000000, 0x00000000, +-0x00000007, 0x00000000, 0x00000000, 0x00000000, +-0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +-0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +-0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +-0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +-0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +-0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +-0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +-0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +-0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +-0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +-0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +-0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +-0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +-0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +-0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +-0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +-0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +-0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +-0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +-0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +-0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +-0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +-0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +-0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +-0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +-0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +-0x00000000, 0x00000000, 0x00000000, 0x00000000, +-0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +-0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +-0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +-}; +-static const unsigned char nmstrtPages[] = { +-0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +-0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +-0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-}; +-static const unsigned char namePages[] = { +-0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +-0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +-0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-}; +- +-#endif /* NAMETAB__H */ +- ++/*=========================================================================== ++ nametab.h ++ this header contains ASCII and UTF-8 tables for qualified ++ name checking + macros for comparing multibyte UTF-8 sequences: ++ UTF8_GET_NAMING2 and UTF8_GET_NAMING3 ++ ++ UTF8_GET_NAMING... and UTF-8 tables are stolen from EXPAT ++ note: DO NOT increment parameters in these macro calls i.e. ++ ISMAPCH(whitespace, *c++) will return invalid value ++ ++ memory usage: ++ ++ namingBitmap (16x80): 1280 bytes ++ nmstrtPages & namePages (2x8x32) 512 bytes ++ 4 ascii tables (4x32) 128 bytes ++ --------------------------------------------------- ++ total 1920 bytes ++ ++ TODO: fix ascii tables (separate to pages to save space) ++ ++ see parsifal.h for copyright info ++===========================================================================*/ ++ ++#ifndef NAMETAB__H ++#define NAMETAB__H ++ ++/* ascii tables generated by GENMAPS.C */ ++static const XMLCH nameStartAscii[32] = { ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, ++0xFE, 0xFF, 0xFF, 0x87, ++0xFE, 0xFF, 0xFF, 0x07, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00 ++}; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_: ++ ++static const XMLCH nameAscii[32] = { ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x60, 0xFF, 0x07, ++0xFE, 0xFF, 0xFF, 0x87, ++0xFE, 0xFF, 0xFF, 0x07, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00 ++}; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_:0123456789.- ++ ++static const XMLCH whitespace[32] = { ++0x00, 0x26, 0x00, 0x00, ++0x01, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00 ++}; ++ ++/* global for both parsifal and encoding module: */ ++const XMLCH illByte[32] = { ++0xFF, 0xD9, 0xFF, 0xFF, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00 ++}; // from \0x0 to \0x1f excluding whitespace chars 0x9, 0xA, 0xD ++ ++#define utf8_isName2(c) (UTF8_GET_NAMING2(namePages, (c))) ++#define utf8_isName3(c) (UTF8_GET_NAMING3(namePages, (c))) ++#define utf8_isNmstrt2(c) (UTF8_GET_NAMING2(nmstrtPages, (c))) ++#define utf8_isNmstrt3(c) (UTF8_GET_NAMING3(nmstrtPages, (c))) ++ ++/* the rest is stolen from EXPAT: */ ++ ++/* A 2 byte UTF-8 representation splits the characters 11 bits ++between the bottom 5 and 6 bits of the bytes. ++We need 8 bits to index into pages, 3 bits to add to that index and ++5 bits to generate the mask. */ ++#define UTF8_GET_NAMING2(pages, byte) \ ++ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ ++ + ((((byte)[0]) & 3) << 1) \ ++ + ((((byte)[1]) >> 5) & 1)] \ ++ & (1 << (((byte)[1]) & 0x1F))) ++ ++/* A 3 byte UTF-8 representation splits the characters 16 bits ++between the bottom 4, 6 and 6 bits of the bytes. ++We need 8 bits to index into pages, 3 bits to add to that index and ++5 bits to generate the mask. */ ++#define UTF8_GET_NAMING3(pages, byte) \ ++ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ ++ + ((((byte)[1]) >> 2) & 0xF)] \ ++ << 3) \ ++ + ((((byte)[1]) & 3) << 1) \ ++ + ((((byte)[2]) >> 5) & 1)] \ ++ & (1 << (((byte)[2]) & 0x1F))) ++ ++static const unsigned namingBitmap[] = { ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ++0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, ++0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, ++0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, ++0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, ++0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, ++0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, ++0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, ++0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, ++0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, ++0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, ++0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, ++0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, ++0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, ++0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, ++0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, ++0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, ++0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, ++0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, ++0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, ++0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, ++0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, ++0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, ++0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, ++0x40000000, 0xF580C900, 0x00000007, 0x02010800, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ++0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, ++0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, ++0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, ++0x00000000, 0x00004C40, 0x00000000, 0x00000000, ++0x00000007, 0x00000000, 0x00000000, 0x00000000, ++0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, ++0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, ++0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ++0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, ++0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, ++0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, ++0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, ++0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, ++0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, ++0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, ++0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, ++0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, ++0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, ++0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, ++0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, ++0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, ++0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, ++0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, ++0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, ++0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, ++0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, ++0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, ++0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, ++0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, ++0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, ++0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, ++0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, ++0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, ++0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, ++0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, ++0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, ++0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, ++}; ++static const unsigned char nmstrtPages[] = { ++0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, ++0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, ++0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++static const unsigned char namePages[] = { ++0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, ++0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, ++0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, ++0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++#endif /* NAMETAB__H */ ++ +diff -r ../src.orig/include/libparsifal/parsifal.h ./include/libparsifal/parsifal.h +--- ../src.orig/include/libparsifal/parsifal.h Fri Oct 3 00:16:17 2003 ++++ ./include/libparsifal/parsifal.h Wed Jan 7 23:43:23 2004 +@@ -1,211 +1,211 @@ +-/*=========================================================================== +- Parsifal XML Parser +- Copyright (c) 2002-2003 Toni Uusitalo +- released to the public domain 2002-11-15 +- +- Parsifal is free for both commercial and non-commercial use and +- redistribution, provided that author's copyright and disclaimer are +- retained intact. You are free to modify Parsifal for your own use and +- to redistribute Parsifal with your modifications, provided that the +- modifications are clearly documented. +- +- DISCLAIMER +- ---------- +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- Merchantability or fitness for a particular purpose. Please use it AT +- YOUR OWN RISK. +-===========================================================================*/ +- +-#ifndef PARSIFAL__H +-#define PARSIFAL__H +- +-#ifdef __cplusplus +- extern "C" { +-#endif +- +-#include "bistream.h" +-#include "xmlhash.h" +-#include "xmlvect.h" +-#include "xmlsbuf.h" +- +-#ifndef XMLCH_DEFINED +- #define XMLCH_DEFINED +- typedef unsigned char XMLCH; +-#endif +- +-typedef struct tagXMLRUNTIMETAG +-{ +- XMLCH *qname; +- XMLCH *uri; +- XMLCH *localName; +- XMLCH *prefix; +- LPXMLHTABLE Scope; +- LPXMLHTABLE prevScope; +- XMLSTRINGBUF nameBuf; +-} XMLRUNTIMETAG, *LPXMLRUNTIMETAG; +- +-typedef struct tagXMLRUNTIMEATT +-{ +- XMLCH *qname; +- XMLCH *value; +- XMLCH *uri; +- XMLCH *localName; +- XMLCH *prefix; +- XMLSTRINGBUF nameBuf; +- XMLSTRINGBUF valBuf; +-} XMLRUNTIMEATT, *LPXMLRUNTIMEATT; +- +-typedef struct tagXMLPARSERRUNTIME +-{ +- LPXMLHTABLE nsScope; +- LPXMLHTABLE namedAtts; +- LPXMLHTABLE entitiesTable; +- LPXMLVECTOR atts; +- LPXMLVECTOR tagstack; +- LPXMLVECTOR entities; +- LPBUFFEREDISTREAM refReader; +- XMLCH *doctypeName; +- XMLSTRINGBUF charsBuf; +-} XMLPARSERRUNTIME, *LPXMLPARSERRUNTIME; +- +-enum tagXMLERRCODE { +- ERR_XMLP_MEMORY_ALLOC = 1, +- ERR_XMLP_READER_FATAL, +- ERR_XMLP_INVALID_TOKEN, +- ERR_XMLP_INVALID_NAME, +- ERR_XMLP_INVALID_END_TAG, +- ERR_XMLP_UNDEF_ENTITY, +- ERR_XMLP_WS_NOT_ALLOWED, +- ERR_XMLP_WS_REQUIRED, +- ERR_XMLP_UNCLOSED_TAG, +- ERR_XMLP_EXPECTED_FOUND, +- ERR_XMLP_EXPECTED_TOKEN, +- ERR_XMLP_MULTIPLE_TOP, +- ERR_XMLP_INVALID_AT_TOP, +- ERR_XMLP_UNDEF_NSPREFIX, +- ERR_XMLP_DUPL_ATTRIBUTE, +- ERR_XMLP_ENCODING, +- ERR_XMLP_UNSUP_ENCODING, +- ERR_XMLP_INVALID_DECL, +- ERR_XMLP_INVALID_ATT_VALUE, +- ERR_XMLP_ABORT, +- ERR_XMLP_ILLEGAL_CHAR, +- ERR_XMLP_RECURSIVE_ENTITY_REF +-}; +-typedef enum tagXMLERRCODE XMLERRCODE; +- +-enum tagXMLENTITYTYPE { +- XML_ENTITY_INT_PARAM = 1, +- XML_ENTITY_INT_GEN, +- XML_ENTITY_EXT_PARAM, +- XML_ENTITY_EXT_GEN, +- XML_ENTITY_UNPARSED, +- XML_ENTITY_DOCTYPE +-}; +-typedef enum tagXMLENTITYTYPE XMLENTITYTYPE; +- +-#define XMLFLAG_NAMESPACES 0x1 /* http://xml.org/sax/features/namespaces */ +-#define XMLFLAG_NAMESPACE_PREFIXES 0x2 /* http://xml.org/sax/features/namespace-prefixes */ +-#define XMLFLAG_EXTERNAL_GENERAL_ENTITIES 0x4 /* http://xml.org/sax/features/external-general-entities */ +-#define XMLFLAG_PRESERVE_GENERAL_ENTITIES 0x8 +-#define XMLFLAG_UNDEF_GENERAL_ENTITIES 0x10 +-#define XMLFLAG_PRESERVE_WS_ATTRIBUTES 0x20 +-#define XMLFLAG_CONVERT_EOL 0x40 +- +-typedef struct tagXMLENTITY +-{ +- XMLENTITYTYPE type; +- int len; +- int open; +- XMLCH *name; +- XMLCH *value; +- XMLCH *publicID; +- XMLCH *systemID; +- XMLCH *notation; +-} XMLENTITY, *LPXMLENTITY; +- +-typedef int (*XML_EVENT_HANDLER)(void *UserData); +-typedef int (*XML_START_ELEMENT_HANDLER)(void *UserData, const XMLCH *uri, +- const XMLCH *localName, const XMLCH *qName, +- LPXMLVECTOR atts); +-typedef int (*XML_END_ELEMENT_HANDLER)(void *UserData, const XMLCH *uri, +- const XMLCH *localName, const XMLCH *qName); +-typedef int (*XML_CHARACTERS_HANDLER)(void *UserData, const XMLCH *chars, int cbSize); +-typedef int (*XML_PI_HANDLER)(void *UserData, const XMLCH *target, const XMLCH *data); +-typedef int (*XML_START_DTD_HANDLER)(void *UserData, const XMLCH *name, +- const XMLCH *publicId, const XMLCH *systemId, +- int hasInternalSubset); +-typedef int (*XML_XMLDECL_HANDLER)(void *UserData, const XMLCH *version, +- const XMLCH *encoding, const XMLCH *standalone); +-typedef int (*XML_RESOLVE_ENTITY_HANDLER)(void *UserData, LPXMLENTITY entity, +- LPBUFFEREDISTREAM reader); +-typedef int (*XML_SKIPPED_ENTITY_HANDLER)(void *UserData, const XMLCH *name); +-typedef int (*XML_ENTITY_EVENT_HANDLER)(void *UserData, LPXMLENTITY entity); +- +-typedef struct tagXMLPARSER +-{ +- LPBUFFEREDISTREAM reader; +- LPXMLPARSERRUNTIME prt; +- XMLCH *DocumentElement; +- XMLCH ErrorString[128]; +- int ErrorCode; +- int ErrorLine; +- int ErrorColumn; +- void *UserData; +- unsigned long XMLFlags; +- XML_EVENT_HANDLER startDocumentHandler; +- XML_EVENT_HANDLER endDocumentHandler; +- XML_EVENT_HANDLER startCDATAHandler; +- XML_EVENT_HANDLER endCDATAHandler; +- XML_EVENT_HANDLER endDTDHandler; +- XML_CHARACTERS_HANDLER charactersHandler; +- XML_CHARACTERS_HANDLER ignorableWhitespaceHandler; +- XML_CHARACTERS_HANDLER commentHandler; +- XML_CHARACTERS_HANDLER defaultHandler; +- XML_START_ELEMENT_HANDLER startElementHandler; +- XML_END_ELEMENT_HANDLER endElementHandler; +- XML_PI_HANDLER processingInstructionHandler; +- XML_START_DTD_HANDLER startDTDHandler; +- XML_XMLDECL_HANDLER xmlDeclHandler; +- XML_SKIPPED_ENTITY_HANDLER skippedEntityHandler; +- XML_ENTITY_EVENT_HANDLER startEntityHandler; +- XML_ENTITY_EVENT_HANDLER endEntityHandler; +- XML_RESOLVE_ENTITY_HANDLER resolveEntityHandler; +- XML_RESOLVE_ENTITY_HANDLER externalEntityParsedHandler; +- /*XML_ERROR_HANDLER */ void (*errorHandler)(struct tagXMLPARSER *parser); +-} XMLPARSER, *LPXMLPARSER; +- +-typedef void (*XML_ERROR_HANDLER)(LPXMLPARSER parser); +- +-#ifndef XMLAPI +-#define XMLAPI +-#endif +- +-#define XML_OK 0 +-#define XML_ABORT 1 +- +-#define _XMLParser_SetFlag(parser,flag,valBool) \ +- ((valBool) ? (((LPXMLPARSER)parser)->XMLFlags |= (flag)) : \ +- (((LPXMLPARSER)parser)->XMLFlags &= ~(flag)) ) +- +-#define _XMLParser_GetFlag(parser,flag) \ +- ((((LPXMLPARSER)parser)->XMLFlags & (flag)) == (flag)) +- +-LPXMLPARSER XMLAPI XMLParser_Create(LPXMLPARSER *parser); +-int XMLAPI XMLParser_Parse(LPXMLPARSER parser, LPFNINPUTSRC inputSrc, void *inputData, const XMLCH *encoding); +-void XMLAPI XMLParser_Free(LPXMLPARSER parser); +-LPXMLRUNTIMEATT XMLAPI XMLParser_GetNamedItem(LPXMLPARSER parser, const XMLCH *name); +-XMLCH XMLAPI *XMLParser_GetSystemID(LPXMLPARSER parser); +-XMLCH XMLAPI *XMLParser_GetPublicID(LPXMLPARSER parser); +-XMLCH XMLAPI *XMLParser_GetPrefixMapping(LPXMLPARSER parser, const XMLCH *prefix); +-int XMLAPI XMLParser_GetCurrentLine(LPXMLPARSER parser); +-int XMLAPI XMLParser_GetCurrentColumn(LPXMLPARSER parser); +-int XMLAPI XMLNormalizeBuf(XMLCH *buf, int len); +- +-#ifdef __cplusplus +- } +-#endif /* __cplusplus */ +-#endif /* PARSIFAL__H */ +- ++/*=========================================================================== ++ Parsifal XML Parser ++ Copyright (c) 2002-2003 Toni Uusitalo ++ released to the public domain 2002-11-15 ++ ++ Parsifal is free for both commercial and non-commercial use and ++ redistribution, provided that author's copyright and disclaimer are ++ retained intact. You are free to modify Parsifal for your own use and ++ to redistribute Parsifal with your modifications, provided that the ++ modifications are clearly documented. ++ ++ DISCLAIMER ++ ---------- ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ Merchantability or fitness for a particular purpose. Please use it AT ++ YOUR OWN RISK. ++===========================================================================*/ ++ ++#ifndef PARSIFAL__H ++#define PARSIFAL__H ++ ++#ifdef __cplusplus ++ extern "C" { ++#endif ++ ++#include "bistream.h" ++#include "xmlhash.h" ++#include "xmlvect.h" ++#include "xmlsbuf.h" ++ ++#ifndef XMLCH_DEFINED ++ #define XMLCH_DEFINED ++ typedef unsigned char XMLCH; ++#endif ++ ++typedef struct tagXMLRUNTIMETAG ++{ ++ XMLCH *qname; ++ XMLCH *uri; ++ XMLCH *localName; ++ XMLCH *prefix; ++ LPXMLHTABLE Scope; ++ LPXMLHTABLE prevScope; ++ XMLSTRINGBUF nameBuf; ++} XMLRUNTIMETAG, *LPXMLRUNTIMETAG; ++ ++typedef struct tagXMLRUNTIMEATT ++{ ++ XMLCH *qname; ++ XMLCH *value; ++ XMLCH *uri; ++ XMLCH *localName; ++ XMLCH *prefix; ++ XMLSTRINGBUF nameBuf; ++ XMLSTRINGBUF valBuf; ++} XMLRUNTIMEATT, *LPXMLRUNTIMEATT; ++ ++typedef struct tagXMLPARSERRUNTIME ++{ ++ LPXMLHTABLE nsScope; ++ LPXMLHTABLE namedAtts; ++ LPXMLHTABLE entitiesTable; ++ LPXMLVECTOR atts; ++ LPXMLVECTOR tagstack; ++ LPXMLVECTOR entities; ++ LPBUFFEREDISTREAM refReader; ++ XMLCH *doctypeName; ++ XMLSTRINGBUF charsBuf; ++} XMLPARSERRUNTIME, *LPXMLPARSERRUNTIME; ++ ++enum tagXMLERRCODE { ++ ERR_XMLP_MEMORY_ALLOC = 1, ++ ERR_XMLP_READER_FATAL, ++ ERR_XMLP_INVALID_TOKEN, ++ ERR_XMLP_INVALID_NAME, ++ ERR_XMLP_INVALID_END_TAG, ++ ERR_XMLP_UNDEF_ENTITY, ++ ERR_XMLP_WS_NOT_ALLOWED, ++ ERR_XMLP_WS_REQUIRED, ++ ERR_XMLP_UNCLOSED_TAG, ++ ERR_XMLP_EXPECTED_FOUND, ++ ERR_XMLP_EXPECTED_TOKEN, ++ ERR_XMLP_MULTIPLE_TOP, ++ ERR_XMLP_INVALID_AT_TOP, ++ ERR_XMLP_UNDEF_NSPREFIX, ++ ERR_XMLP_DUPL_ATTRIBUTE, ++ ERR_XMLP_ENCODING, ++ ERR_XMLP_UNSUP_ENCODING, ++ ERR_XMLP_INVALID_DECL, ++ ERR_XMLP_INVALID_ATT_VALUE, ++ ERR_XMLP_ABORT, ++ ERR_XMLP_ILLEGAL_CHAR, ++ ERR_XMLP_RECURSIVE_ENTITY_REF ++}; ++typedef enum tagXMLERRCODE XMLERRCODE; ++ ++enum tagXMLENTITYTYPE { ++ XML_ENTITY_INT_PARAM = 1, ++ XML_ENTITY_INT_GEN, ++ XML_ENTITY_EXT_PARAM, ++ XML_ENTITY_EXT_GEN, ++ XML_ENTITY_UNPARSED, ++ XML_ENTITY_DOCTYPE ++}; ++typedef enum tagXMLENTITYTYPE XMLENTITYTYPE; ++ ++#define XMLFLAG_NAMESPACES 0x1 /* http://xml.org/sax/features/namespaces */ ++#define XMLFLAG_NAMESPACE_PREFIXES 0x2 /* http://xml.org/sax/features/namespace-prefixes */ ++#define XMLFLAG_EXTERNAL_GENERAL_ENTITIES 0x4 /* http://xml.org/sax/features/external-general-entities */ ++#define XMLFLAG_PRESERVE_GENERAL_ENTITIES 0x8 ++#define XMLFLAG_UNDEF_GENERAL_ENTITIES 0x10 ++#define XMLFLAG_PRESERVE_WS_ATTRIBUTES 0x20 ++#define XMLFLAG_CONVERT_EOL 0x40 ++ ++typedef struct tagXMLENTITY ++{ ++ XMLENTITYTYPE type; ++ int len; ++ int open; ++ XMLCH *name; ++ XMLCH *value; ++ XMLCH *publicID; ++ XMLCH *systemID; ++ XMLCH *notation; ++} XMLENTITY, *LPXMLENTITY; ++ ++typedef int (*XML_EVENT_HANDLER)(void *UserData); ++typedef int (*XML_START_ELEMENT_HANDLER)(void *UserData, const XMLCH *uri, ++ const XMLCH *localName, const XMLCH *qName, ++ LPXMLVECTOR atts); ++typedef int (*XML_END_ELEMENT_HANDLER)(void *UserData, const XMLCH *uri, ++ const XMLCH *localName, const XMLCH *qName); ++typedef int (*XML_CHARACTERS_HANDLER)(void *UserData, const XMLCH *chars, int cbSize); ++typedef int (*XML_PI_HANDLER)(void *UserData, const XMLCH *target, const XMLCH *data); ++typedef int (*XML_START_DTD_HANDLER)(void *UserData, const XMLCH *name, ++ const XMLCH *publicId, const XMLCH *systemId, ++ int hasInternalSubset); ++typedef int (*XML_XMLDECL_HANDLER)(void *UserData, const XMLCH *version, ++ const XMLCH *encoding, const XMLCH *standalone); ++typedef int (*XML_RESOLVE_ENTITY_HANDLER)(void *UserData, LPXMLENTITY entity, ++ LPBUFFEREDISTREAM reader); ++typedef int (*XML_SKIPPED_ENTITY_HANDLER)(void *UserData, const XMLCH *name); ++typedef int (*XML_ENTITY_EVENT_HANDLER)(void *UserData, LPXMLENTITY entity); ++ ++typedef struct tagXMLPARSER ++{ ++ LPBUFFEREDISTREAM reader; ++ LPXMLPARSERRUNTIME prt; ++ XMLCH *DocumentElement; ++ XMLCH ErrorString[128]; ++ int ErrorCode; ++ int ErrorLine; ++ int ErrorColumn; ++ void *UserData; ++ unsigned long XMLFlags; ++ XML_EVENT_HANDLER startDocumentHandler; ++ XML_EVENT_HANDLER endDocumentHandler; ++ XML_EVENT_HANDLER startCDATAHandler; ++ XML_EVENT_HANDLER endCDATAHandler; ++ XML_EVENT_HANDLER endDTDHandler; ++ XML_CHARACTERS_HANDLER charactersHandler; ++ XML_CHARACTERS_HANDLER ignorableWhitespaceHandler; ++ XML_CHARACTERS_HANDLER commentHandler; ++ XML_CHARACTERS_HANDLER defaultHandler; ++ XML_START_ELEMENT_HANDLER startElementHandler; ++ XML_END_ELEMENT_HANDLER endElementHandler; ++ XML_PI_HANDLER processingInstructionHandler; ++ XML_START_DTD_HANDLER startDTDHandler; ++ XML_XMLDECL_HANDLER xmlDeclHandler; ++ XML_SKIPPED_ENTITY_HANDLER skippedEntityHandler; ++ XML_ENTITY_EVENT_HANDLER startEntityHandler; ++ XML_ENTITY_EVENT_HANDLER endEntityHandler; ++ XML_RESOLVE_ENTITY_HANDLER resolveEntityHandler; ++ XML_RESOLVE_ENTITY_HANDLER externalEntityParsedHandler; ++ /*XML_ERROR_HANDLER */ void (*errorHandler)(struct tagXMLPARSER *parser); ++} XMLPARSER, *LPXMLPARSER; ++ ++typedef void (*XML_ERROR_HANDLER)(LPXMLPARSER parser); ++ ++#ifndef XMLAPI ++#define XMLAPI ++#endif ++ ++#define XML_OK 0 ++#define XML_ABORT 1 ++ ++#define _XMLParser_SetFlag(parser,flag,valBool) \ ++ ((valBool) ? (((LPXMLPARSER)parser)->XMLFlags |= (flag)) : \ ++ (((LPXMLPARSER)parser)->XMLFlags &= ~(flag)) ) ++ ++#define _XMLParser_GetFlag(parser,flag) \ ++ ((((LPXMLPARSER)parser)->XMLFlags & (flag)) == (flag)) ++ ++LPXMLPARSER XMLAPI XMLParser_Create(LPXMLPARSER *parser); ++int XMLAPI XMLParser_Parse(LPXMLPARSER parser, LPFNINPUTSRC inputSrc, void *inputData, const XMLCH *encoding); ++void XMLAPI XMLParser_Free(LPXMLPARSER parser); ++LPXMLRUNTIMEATT XMLAPI XMLParser_GetNamedItem(LPXMLPARSER parser, const XMLCH *name); ++XMLCH XMLAPI *XMLParser_GetSystemID(LPXMLPARSER parser); ++XMLCH XMLAPI *XMLParser_GetPublicID(LPXMLPARSER parser); ++XMLCH XMLAPI *XMLParser_GetPrefixMapping(LPXMLPARSER parser, const XMLCH *prefix); ++int XMLAPI XMLParser_GetCurrentLine(LPXMLPARSER parser); ++int XMLAPI XMLParser_GetCurrentColumn(LPXMLPARSER parser); ++int XMLAPI XMLNormalizeBuf(XMLCH *buf, int len); ++ ++#ifdef __cplusplus ++ } ++#endif /* __cplusplus */ ++#endif /* PARSIFAL__H */ ++ +diff -r ../src.orig/include/libparsifal/xmldef.h ./include/libparsifal/xmldef.h +--- ../src.orig/include/libparsifal/xmldef.h Thu Oct 2 20:04:33 2003 ++++ ./include/libparsifal/xmldef.h Wed Jan 7 23:43:23 2004 +@@ -1,106 +1,106 @@ +-/*=========================================================================== +- xmldef.h +- common definitions and macros for parsifal.c and encoding.c +- see parsifal.h for copyright info +-===========================================================================*/ +- +-#ifndef XMLDEF__H +-#define XMLDEF__H +- +-#define TOK_LT "<" +-#define TOK_GT ">" +-#define TOK_END_PI "?>" +-#define TOK_END_COMMENT "--" +-#define TOK_END_CDATA "]]>" +-#define TOK_DOCTYPE "!DOCTYPE" +-#define TOK_XMLNS "xmlns" +-#define TOK_XML "xml" +- +-#define UTF8_2BYTES 0xc0 +-#define UTF8_3BYTES 0xe0 +-#define UTF8_4BYTES 0xf0 +- +-#define UTF8LEN(c,o) \ +-if (!(*c & 0x80)) o = 1; \ +-else if ((unsigned int)*c <= 0xdf) o = 2; \ +-else if ((unsigned int)*c <= 0xef) o = 3; \ +-else if ((unsigned int)*c <= 0xf7) o = 4; \ +-else if ((unsigned int)*c <= 0xfb) o = 5; \ +-else o = 6; +- +-typedef struct tagSTDENTITIES +-{ +- const XMLCH *szEntity; +- const XMLCH chExpanded; +- int len; +-} STDENTITIES; +- +-enum tagXMLATTRIBUTETYPE { +- XMLATT_NORMAL, +- XMLATT_WITHNS, +- XMLATT_PREFIXDECL, +- XMLATT_DEFAULTDECL, +- XMLATT_XMLPREFIXDECL +-}; +-typedef enum tagXMLATTRIBUTETYPE XMLATTRIBUTETYPE; +- +-/* isspace gives us trouble trimming some utf-8 trailbytes... */ +-#ifdef isspace +-#undef isspace +-#endif +-#define isspace(c) (ISMAPCH(whitespace, (c))) +- +-#define ISNULLSTR(str) ((str)==(XMLCH*)NULL) +-#define SAFE_FREESTR(s) \ +- if (!ISNULLSTR(s)) { free(s); s = (XMLCH*)NULL; } +- +-/* BUFTOSTR. similar to BufferedIStream_ToString, but modifies +-(nul terminates) actual buffer. There's no bounds checking like in _ToString, +-also must be sure that returned string stays valid (no _Read operations) +-Note that like in _ToString, last param is endPos, not length. +-macro can be used when BufferedIStream is in pos ?> for example +-and we can replace ? with \0 and use buffer as a string and +-avoid memory/time consuming _ToString call. */ +-#define BUFTOSTR(buf,startPos,endPos) \ +- ((!(startPos)) ? (*((buf)+(endPos))='\0', (buf)) : \ +- (*((buf)+(endPos))='\0', ((buf)+(startPos))) ) +- +-#define RESIZEBUFPOS(buf,size,p,pos) \ +- (buf = (void*)realloc(buf, (size)), p = buf+(pos), buf) +- +-/* ISMAPCH macro for comparing ascii map char */ +-#define ISMAPCH(map, byte) ((map)[(byte) >> 3] & (1 << ((byte) & 7))) +-#define ISILLBYTE(c) (ISMAPCH(illByte, (c))) +-#define ISILL2BYTE(c) ((c > 0xD7FF && c < 0xE000) || c == 0xFFFE || c == 0xFFFF) +- +-/* BISREADERDATA is put into parser->reader->userdata. +-Each parsed entity has its own reader and its own +-BISREADERDATA. The "main parser"'s +-BISREADERDATA is allocated in Parser_Create and +-initialized in Parser_Parse */ +-typedef struct tagBISREADERDATA +-{ +- LPXMLPARSER parser; +- LPXMLENTITY curEnt; /* current entity (NULL for doc entity and internal entities) */ +- int line; +- int col; +- int noPos; +- int ubufsize; /* buffersize for encoding buffer (contains size of reader->ubuf) */ +- int stackLevel; +-} BISREADERDATA, *LPBISREADERDATA; +- +-/* STACK macro wrapper around Vector; can be used as tag stack in our +-case, even though Vector is optimized for sequential index access. +-Tag stack isn't likely to grow/shrink that much in xml parsing when +-using CapacityIncrement 16 x RUNTIMETAG (tag nesting level). +-STACK_POP always removes last item from Vector and that is efficient +-too. Note: Vector handles bounds checking in _Get and in _Remove */ +-#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) +- +-#endif /* XMLDEF__H */ +- ++/*=========================================================================== ++ xmldef.h ++ common definitions and macros for parsifal.c and encoding.c ++ see parsifal.h for copyright info ++===========================================================================*/ ++ ++#ifndef XMLDEF__H ++#define XMLDEF__H ++ ++#define TOK_LT "<" ++#define TOK_GT ">" ++#define TOK_END_PI "?>" ++#define TOK_END_COMMENT "--" ++#define TOK_END_CDATA "]]>" ++#define TOK_DOCTYPE "!DOCTYPE" ++#define TOK_XMLNS "xmlns" ++#define TOK_XML "xml" ++ ++#define UTF8_2BYTES 0xc0 ++#define UTF8_3BYTES 0xe0 ++#define UTF8_4BYTES 0xf0 ++ ++#define UTF8LEN(c,o) \ ++if (!(*c & 0x80)) o = 1; \ ++else if ((unsigned int)*c <= 0xdf) o = 2; \ ++else if ((unsigned int)*c <= 0xef) o = 3; \ ++else if ((unsigned int)*c <= 0xf7) o = 4; \ ++else if ((unsigned int)*c <= 0xfb) o = 5; \ ++else o = 6; ++ ++typedef struct tagSTDENTITIES ++{ ++ const XMLCH *szEntity; ++ const XMLCH chExpanded; ++ int len; ++} STDENTITIES; ++ ++enum tagXMLATTRIBUTETYPE { ++ XMLATT_NORMAL, ++ XMLATT_WITHNS, ++ XMLATT_PREFIXDECL, ++ XMLATT_DEFAULTDECL, ++ XMLATT_XMLPREFIXDECL ++}; ++typedef enum tagXMLATTRIBUTETYPE XMLATTRIBUTETYPE; ++ ++/* isspace gives us trouble trimming some utf-8 trailbytes... */ ++#ifdef isspace ++#undef isspace ++#endif ++#define isspace(c) (ISMAPCH(whitespace, (c))) ++ ++#define ISNULLSTR(str) ((str)==(XMLCH*)NULL) ++#define SAFE_FREESTR(s) \ ++ if (!ISNULLSTR(s)) { free(s); s = (XMLCH*)NULL; } ++ ++/* BUFTOSTR. similar to BufferedIStream_ToString, but modifies ++(nul terminates) actual buffer. There's no bounds checking like in _ToString, ++also must be sure that returned string stays valid (no _Read operations) ++Note that like in _ToString, last param is endPos, not length. ++macro can be used when BufferedIStream is in pos ?> for example ++and we can replace ? with \0 and use buffer as a string and ++avoid memory/time consuming _ToString call. */ ++#define BUFTOSTR(buf,startPos,endPos) \ ++ ((!(startPos)) ? (*((buf)+(endPos))='\0', (buf)) : \ ++ (*((buf)+(endPos))='\0', ((buf)+(startPos))) ) ++ ++#define RESIZEBUFPOS(buf,size,p,pos) \ ++ (buf = (void*)realloc(buf, (size)), p = buf+(pos), buf) ++ ++/* ISMAPCH macro for comparing ascii map char */ ++#define ISMAPCH(map, byte) ((map)[(byte) >> 3] & (1 << ((byte) & 7))) ++#define ISILLBYTE(c) (ISMAPCH(illByte, (c))) ++#define ISILL2BYTE(c) ((c > 0xD7FF && c < 0xE000) || c == 0xFFFE || c == 0xFFFF) ++ ++/* BISREADERDATA is put into parser->reader->userdata. ++Each parsed entity has its own reader and its own ++BISREADERDATA. The "main parser"'s ++BISREADERDATA is allocated in Parser_Create and ++initialized in Parser_Parse */ ++typedef struct tagBISREADERDATA ++{ ++ LPXMLPARSER parser; ++ LPXMLENTITY curEnt; /* current entity (NULL for doc entity and internal entities) */ ++ int line; ++ int col; ++ int noPos; ++ int ubufsize; /* buffersize for encoding buffer (contains size of reader->ubuf) */ ++ int stackLevel; ++} BISREADERDATA, *LPBISREADERDATA; ++ ++/* STACK macro wrapper around Vector; can be used as tag stack in our ++case, even though Vector is optimized for sequential index access. ++Tag stack isn't likely to grow/shrink that much in xml parsing when ++using CapacityIncrement 16 x RUNTIMETAG (tag nesting level). ++STACK_POP always removes last item from Vector and that is efficient ++too. Note: Vector handles bounds checking in _Get and in _Remove */ ++#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) ++ ++#endif /* XMLDEF__H */ ++ +diff -r ../src.orig/include/libparsifal/xmlhash.h ./include/libparsifal/xmlhash.h +--- ../src.orig/include/libparsifal/xmlhash.h Thu Oct 2 20:04:25 2003 ++++ ./include/libparsifal/xmlhash.h Wed Jan 7 23:43:23 2004 +@@ -1,90 +1,90 @@ +-/* See xmlhash.c for copyright info */ +- +-#ifndef XMLHASH__H +-#define XMLHASH__H +- +-#include /* For size_t */ +- +-/* +-** A hash table consists of an array of these buckets. Each bucket +-** holds a copy of the key, a pointer to the data associated with the +-** key, and a pointer to the next bucket that collided with this one, +-** if there was one. +-*/ +- +-typedef struct tagXMLHTABLEBUCKET { +- char *key; +- void *data; +- struct tagXMLHTABLEBUCKET *next; +-} XMLHTABLEBUCKET; +- +-/* +-** This is what you actually declare an instance of to create a table. +-** You then call 'construct_table' with the address of this structure, +-** and a guess at the size of the table. Note that more nodes than this +-** can be inserted in the table, but performance degrades as this +-** happens. Performance should still be quite adequate until 2 or 3 +-** times as many nodes have been inserted as the table was created with. +-*/ +- +-typedef struct tagXMLHTABLE { +- size_t size; +- XMLHTABLEBUCKET **table; +- void *userdata; +-} XMLHTABLE, *LPXMLHTABLE; +- +-/* +-** This is used to construct the table. If it doesn't succeed, it sets +-** the table's size to 0, and the pointer to the table to NULL. +-*/ +- +-LPXMLHTABLE XMLHTable_Create(LPXMLHTABLE table,size_t size); +- +-/* +-** Inserts a pointer to 'data' in the table, with a copy of 'key' as its +-** key. Note that this makes a copy of the key, but NOT of the +-** associated data. +-*/ +- +-void *XMLHTable_Insert(LPXMLHTABLE table, char *key, void *data); +- +-/* +-** Returns a pointer to the data associated with a key. If the key has +-** not been inserted in the table, returns NULL. +-*/ +- +-void *XMLHTable_Lookup(LPXMLHTABLE table, char *key); +- +-/* +-** Deletes an entry from the table. Returns a pointer to the data that +-** was associated with the key so the calling code can dispose of it +-** properly. +-*/ +- +-void *XMLHTable_Remove(LPXMLHTABLE table, char *key); +- +-/* +-** Goes through a hash table and calls the function passed to it +-** for each node that has been inserted. The function is passed +-** a pointer to the key, and a pointer to the data associated +-** with it. +-*/ +- +-int XMLHTable_Enumerate(LPXMLHTABLE table, int (*func)(char *,void *,void *)); +- +-/* +-** Frees a hash table. For each node that was inserted in the table, +-** it calls the function whose address it was passed, with a pointer +-** to the data that was in the table. The function is expected to +-** free the data. Typical usage would be: +-** free_table(&table, free); +-** if the data placed in the table was dynamically allocated, or: +-** free_table(&table, NULL); +-** if not. ( If the parameter passed is NULL, it knows not to call +-** any function with the data. ) +-*/ +- +-int XMLHTable_Destroy(LPXMLHTABLE table, int (*func)(char *, void *, void *), int FreeTable); +- +-#endif /* XMLHASH__H */ +- ++/* See xmlhash.c for copyright info */ ++ ++#ifndef XMLHASH__H ++#define XMLHASH__H ++ ++#include /* For size_t */ ++ ++/* ++** A hash table consists of an array of these buckets. Each bucket ++** holds a copy of the key, a pointer to the data associated with the ++** key, and a pointer to the next bucket that collided with this one, ++** if there was one. ++*/ ++ ++typedef struct tagXMLHTABLEBUCKET { ++ char *key; ++ void *data; ++ struct tagXMLHTABLEBUCKET *next; ++} XMLHTABLEBUCKET; ++ ++/* ++** This is what you actually declare an instance of to create a table. ++** You then call 'construct_table' with the address of this structure, ++** and a guess at the size of the table. Note that more nodes than this ++** can be inserted in the table, but performance degrades as this ++** happens. Performance should still be quite adequate until 2 or 3 ++** times as many nodes have been inserted as the table was created with. ++*/ ++ ++typedef struct tagXMLHTABLE { ++ size_t size; ++ XMLHTABLEBUCKET **table; ++ void *userdata; ++} XMLHTABLE, *LPXMLHTABLE; ++ ++/* ++** This is used to construct the table. If it doesn't succeed, it sets ++** the table's size to 0, and the pointer to the table to NULL. ++*/ ++ ++LPXMLHTABLE XMLHTable_Create(LPXMLHTABLE table,size_t size); ++ ++/* ++** Inserts a pointer to 'data' in the table, with a copy of 'key' as its ++** key. Note that this makes a copy of the key, but NOT of the ++** associated data. ++*/ ++ ++void *XMLHTable_Insert(LPXMLHTABLE table, char *key, void *data); ++ ++/* ++** Returns a pointer to the data associated with a key. If the key has ++** not been inserted in the table, returns NULL. ++*/ ++ ++void *XMLHTable_Lookup(LPXMLHTABLE table, char *key); ++ ++/* ++** Deletes an entry from the table. Returns a pointer to the data that ++** was associated with the key so the calling code can dispose of it ++** properly. ++*/ ++ ++void *XMLHTable_Remove(LPXMLHTABLE table, char *key); ++ ++/* ++** Goes through a hash table and calls the function passed to it ++** for each node that has been inserted. The function is passed ++** a pointer to the key, and a pointer to the data associated ++** with it. ++*/ ++ ++int XMLHTable_Enumerate(LPXMLHTABLE table, int (*func)(char *,void *,void *)); ++ ++/* ++** Frees a hash table. For each node that was inserted in the table, ++** it calls the function whose address it was passed, with a pointer ++** to the data that was in the table. The function is expected to ++** free the data. Typical usage would be: ++** free_table(&table, free); ++** if the data placed in the table was dynamically allocated, or: ++** free_table(&table, NULL); ++** if not. ( If the parameter passed is NULL, it knows not to call ++** any function with the data. ) ++*/ ++ ++int XMLHTable_Destroy(LPXMLHTABLE table, int (*func)(char *, void *, void *), int FreeTable); ++ ++#endif /* XMLHASH__H */ ++ +diff -r ../src.orig/include/libparsifal/xmlsbuf.h ./include/libparsifal/xmlsbuf.h +--- ../src.orig/include/libparsifal/xmlsbuf.h Thu Oct 2 20:04:15 2003 ++++ ./include/libparsifal/xmlsbuf.h Wed Jan 7 23:43:23 2004 +@@ -1,53 +1,53 @@ +-/*=========================================================================== +- vector.h +- see parsifal.h for copyright info +-===========================================================================*/ +- +-#ifndef XMLSBUF__H +-#define XMLSBUF__H +- +-#ifndef XMLAPI +-#define XMLAPI +-#endif +- +-#ifndef NULL +- #define NULL ((void *) 0) +-#endif +- +-#ifndef BYTE +- #define BYTE unsigned char +-#endif +- +-#ifndef XMLCH_DEFINED +- #define XMLCH_DEFINED +- typedef unsigned char XMLCH; +-#endif +- +-#ifndef COUNTBUFSIZE +-#define COUNTBUFSIZE(cBytes, blocksize) \ +-((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) +-#endif +- +-#ifndef XMLSTRINGBUF_STATICSIZE +- #define XMLSTRINGBUF_STATICSIZE 128 +-#endif +- +-typedef struct tagXMLSTRINGBUF +-{ +- int capacity; +- int blocksize; +- int len; +- int useStatic; +- XMLCH *str; +- XMLCH storage[XMLSTRINGBUF_STATICSIZE]; +-} XMLSTRINGBUF, *LPXMLSTRINGBUF; +- +-XMLCH XMLAPI *XMLStringbuf_Append(LPXMLSTRINGBUF sbuf, XMLCH *str, int len); +-XMLCH XMLAPI *XMLStringbuf_AppendCh(LPXMLSTRINGBUF sbuf, XMLCH c); +-XMLCH XMLAPI *XMLStringbuf_Init(LPXMLSTRINGBUF sbuf, int blockSize, int initSize); +-XMLCH XMLAPI *XMLStringbuf_ToString(LPXMLSTRINGBUF sbuf); +-int XMLAPI XMLStringbuf_SetLength(LPXMLSTRINGBUF sbuf, int len); +-void XMLAPI XMLStringbuf_Free(LPXMLSTRINGBUF sbuf); +- +-#endif /* XMLSBUF__H */ +- ++/*=========================================================================== ++ vector.h ++ see parsifal.h for copyright info ++===========================================================================*/ ++ ++#ifndef XMLSBUF__H ++#define XMLSBUF__H ++ ++#ifndef XMLAPI ++#define XMLAPI ++#endif ++ ++#ifndef NULL ++ #define NULL ((void *) 0) ++#endif ++ ++#ifndef BYTE ++ #define BYTE unsigned char ++#endif ++ ++#ifndef XMLCH_DEFINED ++ #define XMLCH_DEFINED ++ typedef unsigned char XMLCH; ++#endif ++ ++#ifndef COUNTBUFSIZE ++#define COUNTBUFSIZE(cBytes, blocksize) \ ++((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) ++#endif ++ ++#ifndef XMLSTRINGBUF_STATICSIZE ++ #define XMLSTRINGBUF_STATICSIZE 128 ++#endif ++ ++typedef struct tagXMLSTRINGBUF ++{ ++ int capacity; ++ int blocksize; ++ int len; ++ int useStatic; ++ XMLCH *str; ++ XMLCH storage[XMLSTRINGBUF_STATICSIZE]; ++} XMLSTRINGBUF, *LPXMLSTRINGBUF; ++ ++XMLCH XMLAPI *XMLStringbuf_Append(LPXMLSTRINGBUF sbuf, XMLCH *str, int len); ++XMLCH XMLAPI *XMLStringbuf_AppendCh(LPXMLSTRINGBUF sbuf, XMLCH c); ++XMLCH XMLAPI *XMLStringbuf_Init(LPXMLSTRINGBUF sbuf, int blockSize, int initSize); ++XMLCH XMLAPI *XMLStringbuf_ToString(LPXMLSTRINGBUF sbuf); ++int XMLAPI XMLStringbuf_SetLength(LPXMLSTRINGBUF sbuf, int len); ++void XMLAPI XMLStringbuf_Free(LPXMLSTRINGBUF sbuf); ++ ++#endif /* XMLSBUF__H */ ++ +diff -r ../src.orig/include/libparsifal/xmlvect.h ./include/libparsifal/xmlvect.h +--- ../src.orig/include/libparsifal/xmlvect.h Thu Oct 2 20:04:07 2003 ++++ ./include/libparsifal/xmlvect.h Wed Jan 7 23:43:23 2004 +@@ -1,51 +1,51 @@ +-/*=========================================================================== +- vector.h +- see parsifal.h for copyright info +-===========================================================================*/ +- +-#ifndef XMLVECTOR__H +-#define XMLVECTOR__H +- +-#ifndef XMLAPI +-#define XMLAPI +-#endif +- +-#ifndef NULL +- #define NULL ((void *) 0) +-#endif +- +-#ifndef BYTE +- #define BYTE unsigned char +-#endif +- +-#ifndef COUNTBUFSIZE +-#define COUNTBUFSIZE(cBytes, blocksize) \ +-((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) +-#endif +- +-typedef struct tagXMLVECTOR +-{ +- int length; +- int capacity; +- int capacityIncrement; +- int itemSize; +- BYTE *array; +-} XMLVECTOR, *LPXMLVECTOR; +- +-LPXMLVECTOR XMLAPI XMLVector_Create(LPXMLVECTOR *vector, int initialCapacity, int itemSize); +-void XMLAPI *XMLVector_Replace(LPXMLVECTOR vector, int index, void *item); +-int XMLAPI XMLVector_Remove(LPXMLVECTOR vector, int index); +-void XMLAPI *XMLVector_Get(LPXMLVECTOR vector, int index); +-int XMLAPI XMLVector_Resize(LPXMLVECTOR vector, int newsize); +-void XMLAPI *XMLVector_Append(LPXMLVECTOR vector, void *item); +-void XMLAPI *XMLVector_InsertBefore(LPXMLVECTOR vector, int index, void *item); +-void XMLAPI XMLVector_Free(LPXMLVECTOR vector); +- +-#define _XMLVector_RemoveAll(v) (XMLVector_Resize((v), 0)) +-#define _XMLVector_Get(v,index) \ +- (((index) < 0 || (index) > ((v)->length - 1)) ? NULL : (((v)->array+((index)*(v)->itemSize)))) +-#define _XMLVector_GetP(vect,i,ptype) (*((ptype##**)XMLVector_Get(((LPXMLVECTOR)vect), ((int)i)))) +-/* e.g. _XMLVector_GetP(v, 0, FILE); expands to *((FILE**)XMLVector_Get(v, 0)) */ +- +-#endif /* XMLVECTOR__H */ +- ++/*=========================================================================== ++ vector.h ++ see parsifal.h for copyright info ++===========================================================================*/ ++ ++#ifndef XMLVECTOR__H ++#define XMLVECTOR__H ++ ++#ifndef XMLAPI ++#define XMLAPI ++#endif ++ ++#ifndef NULL ++ #define NULL ((void *) 0) ++#endif ++ ++#ifndef BYTE ++ #define BYTE unsigned char ++#endif ++ ++#ifndef COUNTBUFSIZE ++#define COUNTBUFSIZE(cBytes, blocksize) \ ++((!(cBytes)) ? (blocksize) : (!( (cBytes) % (blocksize) ) ? (int)(cBytes) : (int)( (((cBytes) / (blocksize)) + 1) * (blocksize) )) ) ++#endif ++ ++typedef struct tagXMLVECTOR ++{ ++ int length; ++ int capacity; ++ int capacityIncrement; ++ int itemSize; ++ BYTE *array; ++} XMLVECTOR, *LPXMLVECTOR; ++ ++LPXMLVECTOR XMLAPI XMLVector_Create(LPXMLVECTOR *vector, int initialCapacity, int itemSize); ++void XMLAPI *XMLVector_Replace(LPXMLVECTOR vector, int index, void *item); ++int XMLAPI XMLVector_Remove(LPXMLVECTOR vector, int index); ++void XMLAPI *XMLVector_Get(LPXMLVECTOR vector, int index); ++int XMLAPI XMLVector_Resize(LPXMLVECTOR vector, int newsize); ++void XMLAPI *XMLVector_Append(LPXMLVECTOR vector, void *item); ++void XMLAPI *XMLVector_InsertBefore(LPXMLVECTOR vector, int index, void *item); ++void XMLAPI XMLVector_Free(LPXMLVECTOR vector); ++ ++#define _XMLVector_RemoveAll(v) (XMLVector_Resize((v), 0)) ++#define _XMLVector_Get(v,index) \ ++ (((index) < 0 || (index) > ((v)->length - 1)) ? NULL : (((v)->array+((index)*(v)->itemSize)))) ++#define _XMLVector_GetP(vect,i,ptype) (*((ptype##**)XMLVector_Get(((LPXMLVECTOR)vect), ((int)i)))) ++/* e.g. _XMLVector_GetP(v, 0, FILE); expands to *((FILE**)XMLVector_Get(v, 0)) */ ++ ++#endif /* XMLVECTOR__H */ ++ +Only in .: libtool +diff -r ../src.orig/samples/canonxml/canonxml.c ./samples/canonxml/canonxml.c +--- ../src.orig/samples/canonxml/canonxml.c Sun Jul 27 23:33:33 2003 ++++ ./samples/canonxml/canonxml.c Wed Jan 7 23:43:23 2004 +@@ -1,276 +1,276 @@ +-#include +-#include "libparsifal/parsifal.h" +- +-#define PFOUT (((CANONXMLPARSER*)UserData)->pfout) +-#define XMLNSURI "http://www.w3.org/2000/xmlns/" +-#define XMLURI "http://www.w3.org/XML/1998/namespace" +-#ifndef MAX_PATH +-#define MAX_PATH 256 +-#endif +- +-typedef struct tagCANONXMLPARSER { +- LPXMLPARSER parser; +- FILE *pfout; +- int hasIntSubset; +- char xmlbase[MAX_PATH]; +-} CANONXMLPARSER; +- +-/* parser events: */ +-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 EscCharacters(void *UserData, const XMLCH *chars, int cbChars); +-int Characters(void *UserData, const XMLCH *chars, int cbChars); +-int Comment(void *UserData, const XMLCH *chars, int cbChars); +-int StartDTD(void *UserData, const XMLCH *Name, const XMLCH *publicId, const XMLCH *systemId, int hasInternalSubset); +-int EndDTD(void *UserData); +-int DummyEvent(void *UserData); +-int XmlDecl(void *UserData, const XMLCH *version, const XMLCH *encoding, const XMLCH *standalone); +-int Pi(void *UserData, const XMLCH *target, const XMLCH *data); +-int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); +-int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); +- +-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); +-LPXMLVECTOR CloneXMLVector(LPXMLVECTOR source); +-int attcmp(const void *att1, const void *att2); +-void PrintEsc(FILE *fp, const XMLCH *str, int len); +- +-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) +-{ +- *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData); +- return (*cBytesActual < cBytes); +-} +- +-int DummyEvent(void *UserData) +-{ +- return 0; +-} +- +-int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) +-{ +- fprintf(PFOUT, "<%s", qName); +- if (atts->length) { +- int i; +- LPXMLRUNTIMEATT att; +- LPXMLVECTOR satts; +- +- if (atts->length > 1) { +- if (!(satts = CloneXMLVector(atts))) return XML_ABORT; +- qsort((void*)satts->array, satts->length, sizeof(XMLRUNTIMEATT), attcmp); +- } +- else { +- satts = atts; +- } +- +- for (i=0; ilength; i++) +- { +- att = XMLVector_Get(satts, i); +- fprintf(PFOUT, " %s=\"", att->qname); +- PrintEsc(PFOUT, att->value, strlen(att->value)); +- putc('\"', PFOUT); +- } +- if (atts->length > 1) XMLVector_Free(satts); +- } +- putc('>', PFOUT); +- return 0; +-} +- +-int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) +-{ +- fprintf(PFOUT, "", qName); +- return 0; +-} +- +-int EscCharacters(void *UserData, const XMLCH *chars, int cbChars) +-{ +- PrintEsc(PFOUT, chars, cbChars); +- return 0; +-} +- +-int Characters(void *UserData, const XMLCH *chars, int cbChars) +-{ +- fwrite(chars, cbChars, 1, PFOUT); +- return 0; +-} +- +-int Comment(void *UserData, const XMLCH *chars, int cbChars) +-{ +- 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 '\x0A': fputs(" ", fp); break; +- case '\x0D': fputs(" ", fp); break; +- default: fputc(*str, fp); break; +- } +- } +-} +- +-int Pi(void *UserData, const XMLCH *target, const XMLCH *data) +-{ +- fprintf(PFOUT, "", target, data); +- return 0; +-} +- +-int StartDTD(void *UserData, const XMLCH *name, const XMLCH *publicId, const XMLCH *systemId, int hasInternalSubset) +-{ +- fprintf(PFOUT, "hasIntSubset = 1; +- fputs(" [", PFOUT); +- } +- return 0; +-} +- +-int EndDTD(void *UserData) +-{ +- if (((CANONXMLPARSER*)UserData)->hasIntSubset) fputs("]>\xA", PFOUT); +- else fputs(">\xA", PFOUT); +- return 0; +-} +- +-int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) +-{ +- FILE *f; +- char file[MAX_PATH]; +- +- strcpy(file, ((CANONXMLPARSER*)UserData)->xmlbase); +- strcat(file, entity->systemID); +- +- if (!(f = fopen(file, "rb"))) { +- printf("error opening file '%s'!\n", file); +- return XML_ABORT; +- } +- reader->inputData = f; +- return 0; +-} +- +-/* note: externalEntityParsedHandler is never called unless reader->inputData +- parameter is given in resolveEntityHandler, thus it's safe to free +- the data without any checks. +- note also: this is called when parsing Error occurred too, so +- only thing you must ensure is that you SET VALID reader->inputData +- or NULL (default) in resolveEntityHandler */ +-int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) +-{ +- fclose((FILE*)reader->inputData); +- return 0; +-} +- +-LPXMLVECTOR CloneXMLVector(LPXMLVECTOR source) +-{ +- LPXMLVECTOR dest; +- if (!XMLVector_Create(&dest, source->length, source->itemSize)) return NULL; +- dest->length = source->length; +- memcpy(dest->array, source->array, dest->length * dest->itemSize); +- return dest; +-} +- +-/* attcmp for qsort +- sorting attributes in canonical xml is quite tricky 'cos of namespace declarations. +- We handle some of it, not everything (like removing redundant xmlns="" attributes). +- here's what happens: +- - all xmlns/xmlns:xxx attributes are put before any other attribs +- - normal attributes e.g. att="val" are put before namespaced xxx:att attributes +- - if both attributes are in a namespace, they are sorted by uris, not qnames. +-*/ +-int attcmp(const void *att1, const void *att2) +-{ +- LPXMLRUNTIMEATT a1 = (LPXMLRUNTIMEATT)att1; +- LPXMLRUNTIMEATT a2 = (LPXMLRUNTIMEATT)att2; +- int n1 = (!(strcmp(a1->uri, XMLNSURI))); +- int n2 = (!(strcmp(a2->uri, XMLNSURI))); +- +- if (n1 != n2) /* other one has XMLNSURI, it will be first: */ +- return (n2 - n1); +- +- if (!n1) { /* no XMLNSURI at all: */ +- n1 = ((*a1->uri) != 0); +- n2 = ((*a2->uri) != 0); +- +- if (n1 != n2) /* other one has uri, it will be last: */ +- return (n1 - n2); +- else if (n1) /* both have uris, compare them: */ +- return strcmp((const XMLCH*)a1->uri, (const XMLCH*)a2->uri); +- } +- /* both have XMLNSURI or are normal attribs, compare qnames: */ +- return strcmp((const XMLCH*)a1->qname, (const XMLCH*)a2->qname); +-} +- +-int main(int argc, char* argv[]) +-{ +- CANONXMLPARSER cxmlparser; /* UserData struct */ +- LPXMLPARSER parser; +- FILE *f; +- int ret; +- +- if (argc < 3 || argc > 4) { +- printf("Usage: canonxml infile.xml outfile.xml optionalbasedir/\n"); +- return -1; +- } +- +- if (argc == 4) +- strcpy(cxmlparser.xmlbase, argv[3]); +- else +- *(cxmlparser.xmlbase) = '\0'; +- +- if (!XMLParser_Create(&parser)) { +- printf("Error creating parser in main()\n"); +- return -1; +- } +- +- parser->UserData = &cxmlparser; +- parser->startElementHandler = StartElement; +- parser->endElementHandler = EndElement; +- parser->charactersHandler = parser->ignorableWhitespaceHandler = EscCharacters; +- parser->startCDATAHandler = DummyEvent; +- parser->processingInstructionHandler = Pi; +- parser->resolveEntityHandler = ResolveEntity; +- parser->externalEntityParsedHandler = FreeInputData; +- /* +- parser->commentHandler = Comment; +- parser->errorHandler = ErrorHandler; +- parser->defaultHandler = Characters; +- parser->startDTDHandler = StartDTD; +- parser->endDTDHandler = EndDTD; +- */ +- cxmlparser.hasIntSubset = 0; +- +- if (!(f = fopen(argv[1], "rb"))) { +- printf("Error opening file %s\n", argv[1]); +- return -1; +- } +- +- if (!(cxmlparser.pfout = fopen(argv[2], "wb"))) { +- printf("Error opening file %s\n", argv[2]); +- return -1; +- } +- +- _XMLParser_SetFlag(parser, XMLFLAG_NAMESPACE_PREFIXES, 1); +- +- XMLParser_Parse(parser, cstream, f, NULL); +- +- ret = (parser->ErrorCode != ERR_XMLP_ABORT) ? parser->ErrorCode : -1; +- fclose(f); +- fclose(cxmlparser.pfout); +- XMLParser_Free(parser); +- return ret; +-} +- ++#include ++#include "libparsifal/parsifal.h" ++ ++#define PFOUT (((CANONXMLPARSER*)UserData)->pfout) ++#define XMLNSURI "http://www.w3.org/2000/xmlns/" ++#define XMLURI "http://www.w3.org/XML/1998/namespace" ++#ifndef MAX_PATH ++#define MAX_PATH 256 ++#endif ++ ++typedef struct tagCANONXMLPARSER { ++ LPXMLPARSER parser; ++ FILE *pfout; ++ int hasIntSubset; ++ char xmlbase[MAX_PATH]; ++} CANONXMLPARSER; ++ ++/* parser events: */ ++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 EscCharacters(void *UserData, const XMLCH *chars, int cbChars); ++int Characters(void *UserData, const XMLCH *chars, int cbChars); ++int Comment(void *UserData, const XMLCH *chars, int cbChars); ++int StartDTD(void *UserData, const XMLCH *Name, const XMLCH *publicId, const XMLCH *systemId, int hasInternalSubset); ++int EndDTD(void *UserData); ++int DummyEvent(void *UserData); ++int XmlDecl(void *UserData, const XMLCH *version, const XMLCH *encoding, const XMLCH *standalone); ++int Pi(void *UserData, const XMLCH *target, const XMLCH *data); ++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); ++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); ++ ++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); ++LPXMLVECTOR CloneXMLVector(LPXMLVECTOR source); ++int attcmp(const void *att1, const void *att2); ++void PrintEsc(FILE *fp, const XMLCH *str, int len); ++ ++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) ++{ ++ *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData); ++ return (*cBytesActual < cBytes); ++} ++ ++int DummyEvent(void *UserData) ++{ ++ return 0; ++} ++ ++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) ++{ ++ fprintf(PFOUT, "<%s", qName); ++ if (atts->length) { ++ int i; ++ LPXMLRUNTIMEATT att; ++ LPXMLVECTOR satts; ++ ++ if (atts->length > 1) { ++ if (!(satts = CloneXMLVector(atts))) return XML_ABORT; ++ qsort((void*)satts->array, satts->length, sizeof(XMLRUNTIMEATT), attcmp); ++ } ++ else { ++ satts = atts; ++ } ++ ++ for (i=0; ilength; i++) ++ { ++ att = XMLVector_Get(satts, i); ++ fprintf(PFOUT, " %s=\"", att->qname); ++ PrintEsc(PFOUT, att->value, strlen(att->value)); ++ putc('\"', PFOUT); ++ } ++ if (atts->length > 1) XMLVector_Free(satts); ++ } ++ putc('>', PFOUT); ++ return 0; ++} ++ ++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) ++{ ++ fprintf(PFOUT, "", qName); ++ return 0; ++} ++ ++int EscCharacters(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ PrintEsc(PFOUT, chars, cbChars); ++ return 0; ++} ++ ++int Characters(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ fwrite(chars, cbChars, 1, PFOUT); ++ return 0; ++} ++ ++int Comment(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ 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 '\x0A': fputs(" ", fp); break; ++ case '\x0D': fputs(" ", fp); break; ++ default: fputc(*str, fp); break; ++ } ++ } ++} ++ ++int Pi(void *UserData, const XMLCH *target, const XMLCH *data) ++{ ++ fprintf(PFOUT, "", target, data); ++ return 0; ++} ++ ++int StartDTD(void *UserData, const XMLCH *name, const XMLCH *publicId, const XMLCH *systemId, int hasInternalSubset) ++{ ++ fprintf(PFOUT, "hasIntSubset = 1; ++ fputs(" [", PFOUT); ++ } ++ return 0; ++} ++ ++int EndDTD(void *UserData) ++{ ++ if (((CANONXMLPARSER*)UserData)->hasIntSubset) fputs("]>\xA", PFOUT); ++ else fputs(">\xA", PFOUT); ++ return 0; ++} ++ ++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) ++{ ++ FILE *f; ++ char file[MAX_PATH]; ++ ++ strcpy(file, ((CANONXMLPARSER*)UserData)->xmlbase); ++ strcat(file, entity->systemID); ++ ++ if (!(f = fopen(file, "rb"))) { ++ printf("error opening file '%s'!\n", file); ++ return XML_ABORT; ++ } ++ reader->inputData = f; ++ return 0; ++} ++ ++/* note: externalEntityParsedHandler is never called unless reader->inputData ++ parameter is given in resolveEntityHandler, thus it's safe to free ++ the data without any checks. ++ note also: this is called when parsing Error occurred too, so ++ only thing you must ensure is that you SET VALID reader->inputData ++ or NULL (default) in resolveEntityHandler */ ++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) ++{ ++ fclose((FILE*)reader->inputData); ++ return 0; ++} ++ ++LPXMLVECTOR CloneXMLVector(LPXMLVECTOR source) ++{ ++ LPXMLVECTOR dest; ++ if (!XMLVector_Create(&dest, source->length, source->itemSize)) return NULL; ++ dest->length = source->length; ++ memcpy(dest->array, source->array, dest->length * dest->itemSize); ++ return dest; ++} ++ ++/* attcmp for qsort ++ sorting attributes in canonical xml is quite tricky 'cos of namespace declarations. ++ We handle some of it, not everything (like removing redundant xmlns="" attributes). ++ here's what happens: ++ - all xmlns/xmlns:xxx attributes are put before any other attribs ++ - normal attributes e.g. att="val" are put before namespaced xxx:att attributes ++ - if both attributes are in a namespace, they are sorted by uris, not qnames. ++*/ ++int attcmp(const void *att1, const void *att2) ++{ ++ LPXMLRUNTIMEATT a1 = (LPXMLRUNTIMEATT)att1; ++ LPXMLRUNTIMEATT a2 = (LPXMLRUNTIMEATT)att2; ++ int n1 = (!(strcmp(a1->uri, XMLNSURI))); ++ int n2 = (!(strcmp(a2->uri, XMLNSURI))); ++ ++ if (n1 != n2) /* other one has XMLNSURI, it will be first: */ ++ return (n2 - n1); ++ ++ if (!n1) { /* no XMLNSURI at all: */ ++ n1 = ((*a1->uri) != 0); ++ n2 = ((*a2->uri) != 0); ++ ++ if (n1 != n2) /* other one has uri, it will be last: */ ++ return (n1 - n2); ++ else if (n1) /* both have uris, compare them: */ ++ return strcmp((const XMLCH*)a1->uri, (const XMLCH*)a2->uri); ++ } ++ /* both have XMLNSURI or are normal attribs, compare qnames: */ ++ return strcmp((const XMLCH*)a1->qname, (const XMLCH*)a2->qname); ++} ++ ++int main(int argc, char* argv[]) ++{ ++ CANONXMLPARSER cxmlparser; /* UserData struct */ ++ LPXMLPARSER parser; ++ FILE *f; ++ int ret; ++ ++ if (argc < 3 || argc > 4) { ++ printf("Usage: canonxml infile.xml outfile.xml optionalbasedir/\n"); ++ return -1; ++ } ++ ++ if (argc == 4) ++ strcpy(cxmlparser.xmlbase, argv[3]); ++ else ++ *(cxmlparser.xmlbase) = '\0'; ++ ++ if (!XMLParser_Create(&parser)) { ++ printf("Error creating parser in main()\n"); ++ return -1; ++ } ++ ++ parser->UserData = &cxmlparser; ++ parser->startElementHandler = StartElement; ++ parser->endElementHandler = EndElement; ++ parser->charactersHandler = parser->ignorableWhitespaceHandler = EscCharacters; ++ parser->startCDATAHandler = DummyEvent; ++ parser->processingInstructionHandler = Pi; ++ parser->resolveEntityHandler = ResolveEntity; ++ parser->externalEntityParsedHandler = FreeInputData; ++ /* ++ parser->commentHandler = Comment; ++ parser->errorHandler = ErrorHandler; ++ parser->defaultHandler = Characters; ++ parser->startDTDHandler = StartDTD; ++ parser->endDTDHandler = EndDTD; ++ */ ++ cxmlparser.hasIntSubset = 0; ++ ++ if (!(f = fopen(argv[1], "rb"))) { ++ printf("Error opening file %s\n", argv[1]); ++ return -1; ++ } ++ ++ if (!(cxmlparser.pfout = fopen(argv[2], "wb"))) { ++ printf("Error opening file %s\n", argv[2]); ++ return -1; ++ } ++ ++ _XMLParser_SetFlag(parser, XMLFLAG_NAMESPACE_PREFIXES, 1); ++ ++ XMLParser_Parse(parser, cstream, f, NULL); ++ ++ ret = (parser->ErrorCode != ERR_XMLP_ABORT) ? parser->ErrorCode : -1; ++ fclose(f); ++ fclose(cxmlparser.pfout); ++ XMLParser_Free(parser); ++ return ret; ++} ++ +diff -r ../src.orig/samples/elements/elements.c ./samples/elements/elements.c +--- ../src.orig/samples/elements/elements.c Fri Jun 27 18:32:54 2003 ++++ ./samples/elements/elements.c Wed Jan 7 23:43:23 2004 +@@ -1,57 +1,57 @@ +-#include +-#include "libparsifal/parsifal.h" +- +-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); +-void ErrorHandler(LPXMLPARSER parser) {} /* dummy, only for switching ErrorString and ErrorLine on, +-ErrorLine doesn't work with stdin though... */ +- +-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); +- +-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) +-{ +- *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData); +- return (*cBytesActual < cBytes); +-} +- +-int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) +-{ +- int i; +- int *depthPtr = UserData; +- for (i = 0; i < *depthPtr; i++) +- putchar('\t'); +- puts(qName); +- *depthPtr += 1; +- return 0; +-} +- +-int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) +-{ +- int *depthPtr = UserData; +- *depthPtr -= 1; +- return 0; +-} +- +-int main(int argc, char* argv[]) +-{ +- LPXMLPARSER parser; +- int depth = 0; +- +- if (!XMLParser_Create(&parser)) { +- printf("Error creating parser!\n"); +- exit(1); +- } +- +- parser->errorHandler = ErrorHandler; +- parser->startElementHandler = StartElement; +- parser->endElementHandler = EndElement; +- parser->UserData = &depth; +- +- if (!XMLParser_Parse(parser, cstream, stdin, 0)) { +- printf("Error: %s\n", parser->ErrorString); +- } +- +- XMLParser_Free(parser); +- return 0; +-} +- ++#include ++#include "libparsifal/parsifal.h" ++ ++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); ++void ErrorHandler(LPXMLPARSER parser) {} /* dummy, only for switching ErrorString and ErrorLine on, ++ErrorLine doesn't work with stdin though... */ ++ ++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); ++ ++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) ++{ ++ *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData); ++ return (*cBytesActual < cBytes); ++} ++ ++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) ++{ ++ int i; ++ int *depthPtr = UserData; ++ for (i = 0; i < *depthPtr; i++) ++ putchar('\t'); ++ puts(qName); ++ *depthPtr += 1; ++ return 0; ++} ++ ++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) ++{ ++ int *depthPtr = UserData; ++ *depthPtr -= 1; ++ return 0; ++} ++ ++int main(int argc, char* argv[]) ++{ ++ LPXMLPARSER parser; ++ int depth = 0; ++ ++ if (!XMLParser_Create(&parser)) { ++ printf("Error creating parser!\n"); ++ exit(1); ++ } ++ ++ parser->errorHandler = ErrorHandler; ++ parser->startElementHandler = StartElement; ++ parser->endElementHandler = EndElement; ++ parser->UserData = &depth; ++ ++ if (!XMLParser_Parse(parser, cstream, stdin, 0)) { ++ printf("Error: %s\n", parser->ErrorString); ++ } ++ ++ XMLParser_Free(parser); ++ return 0; ++} ++ +diff -r ../src.orig/samples/winurl/winurl.c ./samples/winurl/winurl.c +--- ../src.orig/samples/winurl/winurl.c Tue Sep 30 21:30:46 2003 ++++ ./samples/winurl/winurl.c Wed Jan 7 23:43:23 2004 +@@ -1,257 +1,257 @@ +-#include +-#include "libparsifal/parsifal.h" +-#undef BYTE /* must be undef - windef.h redefines it */ +-#include "windows.h" +-#include "urlmon.h" +- +-#define MAX_URILEN 512 +- +-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 PI(void *UserData, const XMLCH *target, const XMLCH *data); +-int Characters(void *UserData, const XMLCH *chars, int cbChars); +-int DefaultHandler(void *UserData, const XMLCH *chars, int cbChars); +-int Comment(void *UserData, const XMLCH *chars, int cbChars); +-int CharactersWide(void *UserData, const XMLCH *chars, int cbChars); +-int StartCData(void *UserData); +-int EndCData(void *UserData); +-int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset); +-void ErrorHandler(LPXMLPARSER parser); +-int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); +-int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); +-int SkippedEntity(void *UserData, const XMLCH *name); +-int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); +- +-int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) +-{ +- if (*uri) +- printf("\nStart tag: %s uri: %s localName: %s", qName, uri, localName); +- else +- printf("\nStart tag: %s", qName); +- +- if (atts->length) { +- int i; +- LPXMLRUNTIMEATT att; +- +- printf("\nhas %d attributes:", atts->length); +- for (i=0; ilength; i++) { +- att = (LPXMLRUNTIMEATT)XMLVector_Get(atts, i); +- +- if (*att->uri) +- printf("\n Name: %s Value: %s Prefix: %s LocalName: %s Uri: %s", +- att->qname, att->value, +- att->prefix, att->localName, +- att->uri); +- else +- printf("\n Name: %s Value: %s", +- att->qname, att->value); +- } +- +- /* this demonstrates XMLParser_GetNamedItem and XML_ABORT, just +- change the name "findthis" here to abort parsing when +- this attribute is encountered: */ +- +- if (att = XMLParser_GetNamedItem(UserData, "findthis")) { +- printf("FOUND ATTRIBUTE %s value: %s\nAborting...\n", att->qname, att->value); +- return XML_ABORT; +- } +- } +- return 0; +-} +- +-int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) +-{ +- printf("\nEnd tag: %s", qName); +- return 0; +-} +- +-int Characters(void *UserData, const XMLCH *chars, int cbChars) +-{ +- printf("\nText (%d bytes): ", cbChars); +- for (; cbChars; cbChars--, chars++) putc(*chars, stdout); +- return 0; +-} +- +-int DefaultHandler(void *UserData, const XMLCH *chars, int cbChars) +-{ +- printf("\ninternal subset data (%d bytes): ", cbChars); +- for (; cbChars; cbChars--, chars++) putc(*chars, stdout); +- return 0; +-} +- +-int SkippedEntity(void *UserData, const XMLCH *name) +-{ +- printf("\nskipped entity: %s", name); +- return 0; +-} +- +-int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset) +-{ +- printf("\nDOCTYPE Name: %s", name); +- if (publicID) printf(" publicID: %s", publicID); +- if (systemID) printf(" systemID: %s", systemID); +- printf(" hasInternalSubset: %d", hasInternalSubset); +- return 0; +-} +- +-int StartCData(void *UserData) +-{ +- printf("\nStart CData tag\n"); +- /* will call Characters to report CDATA contents */ +- return 0; +-} +- +-int EndCData(void *UserData) +-{ +- printf("\nEnd CData tag"); +- return 0; +-} +- +-int Comment(void *UserData, const XMLCH *chars, int cbChars) +-{ +- printf("\nComment (%d bytes): ", cbChars); +- for (; cbChars; cbChars--, chars++) putc(*chars, stdout); +- return 0; +-} +- +-int PI(void *UserData, const XMLCH *target, const XMLCH *data) +-{ +- printf("\nPI tag - target: %s data: %s", target, ((*data) ? data : "no data")); +- return 0; +-} +- +-void ErrorHandler(LPXMLPARSER parser) +-{ +- /* you should treat ERR_XMLP_ABORT as "user error" and give somekind of +- description before returning from callbacks, otherwise we present parser error: */ +- if (parser->ErrorCode != ERR_XMLP_ABORT) { +- XMLCH *SystemID = XMLParser_GetSystemID(parser); +- printf("\nParsing Error: %s\nCode: %d", +- parser->ErrorString, parser->ErrorCode); +- if (SystemID) printf("\nSystemID: '%s'", SystemID); +- } +- printf("\nLine: %d\nColumn: %d", parser->ErrorLine, parser->ErrorColumn); +-} +- +-/* +- Converts UTF-8 string to wchar_t string +- and shows converted string in MessageBoxW +- +- Set charactersHandler = CharactersWide if +- you want to test UTF-8 to wchar_t conversion for +- text content, you shouldn't run large documents with +- CharactersWide because those MessageBoxes can get annoying... +-*/ +-int CharactersWide(void *UserData, const XMLCH *chars, int cbChars) +-{ +- wchar_t wstr[1024]; +- int size; +- +- if (cbChars > 1023) cbChars = 1024; +- +- if ((size = MultiByteToWideChar(CP_UTF8, 0, chars, cbChars, wstr, 1024))) { +- *(wstr+size) = L'\0'; +- MessageBoxW(NULL, wstr, L"WinUrl sample", MB_OK); +- } +- else { +- printf("Unicode conversion error!"); +- return XML_ABORT; +- } +- return 0; +-} +- +-int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) +-{ +- IStream *pStm = NULL; /* pointer to COM stream */ +- HRESULT hr; +- XMLCH uri[MAX_URILEN]; +- XMLCH *base = XMLParser_GetPrefixMapping((LPXMLPARSER)UserData, "xml:base"); +- +- if (base) { +- printf("\nxml:base set to %s", base); +- strcpy(uri, base); +- strcat(uri, entity->systemID); +- } +- else { +- strcpy(uri, entity->systemID); +- } +- +- hr = URLOpenBlockingStream(0, uri, &pStm, 0,0); +- if (!SUCCEEDED(hr)) { +- printf("\nError opening url '%s'", uri); +- if (pStm) pStm->lpVtbl->Release(pStm); +- return XML_ABORT; +- } +- +- reader->inputData = pStm; +- return 0; +-} +- +-int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) +-{ +- IStream *pStm = (IStream*)reader->inputData; +- if (pStm) pStm->lpVtbl->Release(pStm); +- return 0; +-} +- +-int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) +-{ +- /* calls IStream.Read in C COM way: */ +- HRESULT hr = ((IStream*)inputData)->lpVtbl->Read((IStream*)inputData, buf, cBytes, cBytesActual); +- return (*cBytesActual < cBytes || !SUCCEEDED(hr)); +-} +- +-int main(int argc, char* argv[]) +-{ +- LPXMLPARSER parser; +- IStream *pStm = NULL; /* pointer to COM stream */ +- HRESULT hr; +- char szUrl[MAX_URILEN]; +- +- printf("\nWINURL Parsifal sample\n\nUrl to parse: "); +- gets(szUrl); +- +- /* open the url stream: */ +- hr = URLOpenBlockingStream(0, szUrl, &pStm, 0,0); +- if (!SUCCEEDED(hr)) { +- puts("Error opening url!"); +- if (pStm) pStm->lpVtbl->Release(pStm); +- exit(1); +- } +- +- if (!XMLParser_Create(&parser)) { +- puts("Error creating parser!"); +- exit(1); +- } +- +- parser->startElementHandler = StartElement; +- parser->endElementHandler = EndElement; +- parser->charactersHandler = Characters; /* set to CharactersWide +- to convert UTF-8 -> wchar_t */ +- parser->processingInstructionHandler = PI; +- parser->commentHandler = Comment; +- parser->startCDATAHandler = StartCData; +- parser->endCDATAHandler = EndCData; +- parser->errorHandler = ErrorHandler; +- parser->startDTDHandler = DoctypeDecl; +- parser->defaultHandler = DefaultHandler; +- parser->skippedEntityHandler = SkippedEntity; +- parser->resolveEntityHandler = ResolveEntity; +- parser->UserData = parser; +- +- printf("XMLFlags:\n"); +- printf("XMLFLAG_NAMESPACES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACES)); +- printf("XMLFLAG_NAMESPACE_PREFIXES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACE_PREFIXES)); +- printf("XMLFLAG_EXTERNAL_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_EXTERNAL_GENERAL_ENTITIES)); +- printf("XMLFLAG_PRESERVE_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_GENERAL_ENTITIES)); +- printf("XMLFLAG_UNDEF_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_UNDEF_GENERAL_ENTITIES)); +- printf("XMLFLAG_PRESERVE_WS_ATTRIBUTES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_WS_ATTRIBUTES)); +- +- XMLParser_Parse(parser, urlstream, pStm, NULL); +- +- if (pStm) pStm->lpVtbl->Release(pStm); +- XMLParser_Free(parser); +- +- return 0; +-} +- ++#include ++#include "libparsifal/parsifal.h" ++#undef BYTE /* must be undef - windef.h redefines it */ ++#include "windows.h" ++#include "urlmon.h" ++ ++#define MAX_URILEN 512 ++ ++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 PI(void *UserData, const XMLCH *target, const XMLCH *data); ++int Characters(void *UserData, const XMLCH *chars, int cbChars); ++int DefaultHandler(void *UserData, const XMLCH *chars, int cbChars); ++int Comment(void *UserData, const XMLCH *chars, int cbChars); ++int CharactersWide(void *UserData, const XMLCH *chars, int cbChars); ++int StartCData(void *UserData); ++int EndCData(void *UserData); ++int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset); ++void ErrorHandler(LPXMLPARSER parser); ++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); ++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader); ++int SkippedEntity(void *UserData, const XMLCH *name); ++int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); ++ ++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) ++{ ++ if (*uri) ++ printf("\nStart tag: %s uri: %s localName: %s", qName, uri, localName); ++ else ++ printf("\nStart tag: %s", qName); ++ ++ if (atts->length) { ++ int i; ++ LPXMLRUNTIMEATT att; ++ ++ printf("\nhas %d attributes:", atts->length); ++ for (i=0; ilength; i++) { ++ att = (LPXMLRUNTIMEATT)XMLVector_Get(atts, i); ++ ++ if (*att->uri) ++ printf("\n Name: %s Value: %s Prefix: %s LocalName: %s Uri: %s", ++ att->qname, att->value, ++ att->prefix, att->localName, ++ att->uri); ++ else ++ printf("\n Name: %s Value: %s", ++ att->qname, att->value); ++ } ++ ++ /* this demonstrates XMLParser_GetNamedItem and XML_ABORT, just ++ change the name "findthis" here to abort parsing when ++ this attribute is encountered: */ ++ ++ if (att = XMLParser_GetNamedItem(UserData, "findthis")) { ++ printf("FOUND ATTRIBUTE %s value: %s\nAborting...\n", att->qname, att->value); ++ return XML_ABORT; ++ } ++ } ++ return 0; ++} ++ ++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) ++{ ++ printf("\nEnd tag: %s", qName); ++ return 0; ++} ++ ++int Characters(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ printf("\nText (%d bytes): ", cbChars); ++ for (; cbChars; cbChars--, chars++) putc(*chars, stdout); ++ return 0; ++} ++ ++int DefaultHandler(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ printf("\ninternal subset data (%d bytes): ", cbChars); ++ for (; cbChars; cbChars--, chars++) putc(*chars, stdout); ++ return 0; ++} ++ ++int SkippedEntity(void *UserData, const XMLCH *name) ++{ ++ printf("\nskipped entity: %s", name); ++ return 0; ++} ++ ++int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset) ++{ ++ printf("\nDOCTYPE Name: %s", name); ++ if (publicID) printf(" publicID: %s", publicID); ++ if (systemID) printf(" systemID: %s", systemID); ++ printf(" hasInternalSubset: %d", hasInternalSubset); ++ return 0; ++} ++ ++int StartCData(void *UserData) ++{ ++ printf("\nStart CData tag\n"); ++ /* will call Characters to report CDATA contents */ ++ return 0; ++} ++ ++int EndCData(void *UserData) ++{ ++ printf("\nEnd CData tag"); ++ return 0; ++} ++ ++int Comment(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ printf("\nComment (%d bytes): ", cbChars); ++ for (; cbChars; cbChars--, chars++) putc(*chars, stdout); ++ return 0; ++} ++ ++int PI(void *UserData, const XMLCH *target, const XMLCH *data) ++{ ++ printf("\nPI tag - target: %s data: %s", target, ((*data) ? data : "no data")); ++ return 0; ++} ++ ++void ErrorHandler(LPXMLPARSER parser) ++{ ++ /* you should treat ERR_XMLP_ABORT as "user error" and give somekind of ++ description before returning from callbacks, otherwise we present parser error: */ ++ if (parser->ErrorCode != ERR_XMLP_ABORT) { ++ XMLCH *SystemID = XMLParser_GetSystemID(parser); ++ printf("\nParsing Error: %s\nCode: %d", ++ parser->ErrorString, parser->ErrorCode); ++ if (SystemID) printf("\nSystemID: '%s'", SystemID); ++ } ++ printf("\nLine: %d\nColumn: %d", parser->ErrorLine, parser->ErrorColumn); ++} ++ ++/* ++ Converts UTF-8 string to wchar_t string ++ and shows converted string in MessageBoxW ++ ++ Set charactersHandler = CharactersWide if ++ you want to test UTF-8 to wchar_t conversion for ++ text content, you shouldn't run large documents with ++ CharactersWide because those MessageBoxes can get annoying... ++*/ ++int CharactersWide(void *UserData, const XMLCH *chars, int cbChars) ++{ ++ wchar_t wstr[1024]; ++ int size; ++ ++ if (cbChars > 1023) cbChars = 1024; ++ ++ if ((size = MultiByteToWideChar(CP_UTF8, 0, chars, cbChars, wstr, 1024))) { ++ *(wstr+size) = L'\0'; ++ MessageBoxW(NULL, wstr, L"WinUrl sample", MB_OK); ++ } ++ else { ++ printf("Unicode conversion error!"); ++ return XML_ABORT; ++ } ++ return 0; ++} ++ ++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) ++{ ++ IStream *pStm = NULL; /* pointer to COM stream */ ++ HRESULT hr; ++ XMLCH uri[MAX_URILEN]; ++ XMLCH *base = XMLParser_GetPrefixMapping((LPXMLPARSER)UserData, "xml:base"); ++ ++ if (base) { ++ printf("\nxml:base set to %s", base); ++ strcpy(uri, base); ++ strcat(uri, entity->systemID); ++ } ++ else { ++ strcpy(uri, entity->systemID); ++ } ++ ++ hr = URLOpenBlockingStream(0, uri, &pStm, 0,0); ++ if (!SUCCEEDED(hr)) { ++ printf("\nError opening url '%s'", uri); ++ if (pStm) pStm->lpVtbl->Release(pStm); ++ return XML_ABORT; ++ } ++ ++ reader->inputData = pStm; ++ return 0; ++} ++ ++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) ++{ ++ IStream *pStm = (IStream*)reader->inputData; ++ if (pStm) pStm->lpVtbl->Release(pStm); ++ return 0; ++} ++ ++int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) ++{ ++ /* calls IStream.Read in C COM way: */ ++ HRESULT hr = ((IStream*)inputData)->lpVtbl->Read((IStream*)inputData, buf, cBytes, cBytesActual); ++ return (*cBytesActual < cBytes || !SUCCEEDED(hr)); ++} ++ ++int main(int argc, char* argv[]) ++{ ++ LPXMLPARSER parser; ++ IStream *pStm = NULL; /* pointer to COM stream */ ++ HRESULT hr; ++ char szUrl[MAX_URILEN]; ++ ++ printf("\nWINURL Parsifal sample\n\nUrl to parse: "); ++ gets(szUrl); ++ ++ /* open the url stream: */ ++ hr = URLOpenBlockingStream(0, szUrl, &pStm, 0,0); ++ if (!SUCCEEDED(hr)) { ++ puts("Error opening url!"); ++ if (pStm) pStm->lpVtbl->Release(pStm); ++ exit(1); ++ } ++ ++ if (!XMLParser_Create(&parser)) { ++ puts("Error creating parser!"); ++ exit(1); ++ } ++ ++ parser->startElementHandler = StartElement; ++ parser->endElementHandler = EndElement; ++ parser->charactersHandler = Characters; /* set to CharactersWide ++ to convert UTF-8 -> wchar_t */ ++ parser->processingInstructionHandler = PI; ++ parser->commentHandler = Comment; ++ parser->startCDATAHandler = StartCData; ++ parser->endCDATAHandler = EndCData; ++ parser->errorHandler = ErrorHandler; ++ parser->startDTDHandler = DoctypeDecl; ++ parser->defaultHandler = DefaultHandler; ++ parser->skippedEntityHandler = SkippedEntity; ++ parser->resolveEntityHandler = ResolveEntity; ++ parser->UserData = parser; ++ ++ printf("XMLFlags:\n"); ++ printf("XMLFLAG_NAMESPACES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACES)); ++ printf("XMLFLAG_NAMESPACE_PREFIXES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACE_PREFIXES)); ++ printf("XMLFLAG_EXTERNAL_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_EXTERNAL_GENERAL_ENTITIES)); ++ printf("XMLFLAG_PRESERVE_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_GENERAL_ENTITIES)); ++ printf("XMLFLAG_UNDEF_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_UNDEF_GENERAL_ENTITIES)); ++ printf("XMLFLAG_PRESERVE_WS_ATTRIBUTES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_WS_ATTRIBUTES)); ++ ++ XMLParser_Parse(parser, urlstream, pStm, NULL); ++ ++ if (pStm) pStm->lpVtbl->Release(pStm); ++ XMLParser_Free(parser); ++ ++ return 0; ++} ++ +Only in ../src.orig/samples/xmltest: FCOMPARE.C +Only in ./samples/xmltest: FCOMPARE.o +Only in ./samples/xmltest: fcompare.c +Only in ./samples/xmltest: xmltest +diff -r ../src.orig/samples/xmltest/xmltest.c ./samples/xmltest/xmltest.c +--- ../src.orig/samples/xmltest/xmltest.c Tue Sep 30 21:33:53 2003 ++++ ./samples/xmltest/xmltest.c Wed Jan 7 23:43:23 2004 +@@ -1,481 +1,481 @@ +-#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, "", 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; +-} +- ++#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, "", 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; ++} ++