#include <stdio.h> #include <string.h> #include <stdlib.h> #include "libparsifal/parsifal.h" #include "libparsifal/dtdvalid.h" int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts); int StartElementSimple(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); int IgnorableWS(void *UserData, const XMLCH *Chars, int cbChars); int StartDocument(void *UserData); void ErrorHandler(LPXMLPARSER parser); int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData); /* see samples/misc/helper.c for comments of the following routines: */ size_t GetBaseDir(XMLCH *dst, XMLCH *src); XMLCH *ResolveBaseUri(LPXMLPARSER parser, XMLCH *systemID, XMLCH *base); #define NSVALIDP ((NSVALIDPARSER*)v->UserData) #define ASSERT_MEM_ABORT(p) \ if (!(p)) { printf("Out of memory! Line: %d\n", __LINE__); return XML_ABORT; } typedef struct tagNSVALIDPARSER { int elemCount; LPXMLVECTOR filteredAtts; char *wantedUri; char base[FILENAME_MAX]; char userDTD[FILENAME_MAX]; } NSVALIDPARSER; int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; if (!strcmp(uri, NSVALIDP->wantedUri)) { LPXMLVECTOR attsF; if (v->UserFlag) v->UserFlag = 0; NSVALIDP->elemCount++; if (!atts->length) attsF = atts; else { int i; LPXMLRUNTIMEATT a; if (NSVALIDP->filteredAtts->length) _XMLVector_RemoveAll(NSVALIDP->filteredAtts); for (i=0; i<atts->length; i++) { a = XMLVector_Get(atts, i); if (!*a->uri || !strcmp(a->uri, NSVALIDP->wantedUri)) a = XMLVector_Append(NSVALIDP->filteredAtts, a); ASSERT_MEM_ABORT(a); } attsF = NSVALIDP->filteredAtts; } return DTDValidate_StartElement(v, uri, localName, localName, attsF); } v->UserFlag++; return XML_OK; } int StartElementSimple(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; NSVALIDP->elemCount++; return XML_OK; } int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; if (!strcmp(uri, NSVALIDP->wantedUri)) { if (v->UserFlag) v->UserFlag = 0; return DTDValidate_EndElement(v, uri, localName, localName); } v->UserFlag--; return XML_OK; } int Characters(void *UserData, const XMLCH *Chars, int cbChars) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; return (v->UserFlag) ? XML_OK : DTDValidate_Characters(v, Chars, cbChars); } int IgnorableWS(void *UserData, const XMLCH *Chars, int cbChars) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; return (v->UserFlag) ? XML_OK : DTDValidate_IgnorableWhitespace(v, Chars, cbChars); } void ErrorHandler(LPXMLPARSER parser) { XMLCH *SystemID = XMLParser_GetSystemID(parser); LPXMLENTITY curEnt = XMLParser_GetCurrentEntity(parser); if (parser->ErrorCode == ERR_XMLP_VALIDATION) { LPXMLDTDVALIDATOR vp = (LPXMLDTDVALIDATOR)parser->UserData; printf("Validation Error: %s\nErrorLine: %d ErrorColumn: %d\n", vp->ErrorString, vp->ErrorLine, vp->ErrorColumn); } else { printf("Parsing Error: %s\nErrorLine: %d ErrorColumn: %d\n", parser->ErrorString, parser->ErrorLine, parser->ErrorColumn); } if (curEnt && !curEnt->systemID) printf("In entity: '%s'\n", curEnt->name); if (SystemID) printf("SystemID: '%s'\n", SystemID); } int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData) { *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData); return (*cBytesActual < cBytes); } XMLCH *ResolveBaseUri(LPXMLPARSER parser, XMLCH *systemID, XMLCH *base) { XMLCH *s=systemID; for (; *s; s++) { if (*s == ':') return systemID; /* probably absolute */ if (*s == '/' || *s == '\\') break; } s = XMLParser_GetPrefixMapping(parser, "xml:base"); return (s) ? s : base; } int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) { LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData; FILE *f; XMLCH r[FILENAME_MAX]; XMLCH *filename = ResolveBaseUri(v->parser, entity->systemID, NSVALIDP->base); if (filename != entity->systemID) { strcpy(r, filename); filename = strcat(r, entity->systemID); } if (!(f = fopen(filename, "rb"))) { printf("error opening file '%s'!\n", filename); return XML_ABORT; } reader->inputData = f; return XML_OK; } int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader) { fclose((FILE*)reader->inputData); return XML_OK; } size_t GetBaseDir(XMLCH *dst, XMLCH *src) { XMLCH *s = strrchr(src, '/'); #ifdef _WIN32 if (!s) s = strrchr(src, '\\'); #endif if (s) { size_t i = (s-src)+1; memcpy(dst, src, i); dst[i] = '\0'; return i; } dst[0] = '\0'; return 0; } int main(int argc, char* argv[]) { NSVALIDPARSER nsparser; LPXMLPARSER parser; LPXMLDTDVALIDATOR vp; FILE *f; int i; XMLCH *filename = NULL; if (argc < 2 || argc > 4) goto USAGE; nsparser.elemCount = 0; nsparser.wantedUri = ""; *nsparser.userDTD = '\0'; *nsparser.base = '\0'; for (i=1; i<argc; i++) { if (!strncmp(argv[i], "/DTD:", 5)) strcpy(nsparser.userDTD, argv[i]+5); else if (!strncmp(argv[i], "/URI:", 5)) nsparser.wantedUri = argv[i]+5; else { if (filename) goto USAGE; filename = argv[i]; } } if (!filename) goto USAGE; if (!XMLParser_Create(&parser)) { puts("Out of memory!"); return 1; } vp = XMLParser_CreateDTDValidator(); if (!vp) { puts("Out of memory!"); return 1; } if (!XMLVector_Create(&nsparser.filteredAtts, 0, sizeof(XMLRUNTIMEATT))) { puts("Out of memory!"); return 1; } vp->UserData = &nsparser; parser->errorHandler = ErrorHandler; parser->resolveEntityHandler = ResolveEntity; parser->externalEntityParsedHandler = FreeInputData; if (*nsparser.userDTD) { int filepos = GetBaseDir(nsparser.base, nsparser.userDTD); if (filepos) strcpy(nsparser.userDTD, nsparser.userDTD+filepos); XMLParser_SetExternalSubset(parser, NULL, nsparser.userDTD); } if (!*nsparser.base) GetBaseDir(nsparser.base, filename); if (*nsparser.wantedUri) { vp->startElementHandlerFilter = StartElement; vp->endElementHandlerFilter = EndElement; vp->charactersHandlerFilter = Characters; vp->ignorableWhitespaceHandlerFilter = IgnorableWS; } else /* simple validator w/o namespace filter: */ parser->startElementHandler = StartElementSimple; if (!(f = fopen(filename, "rb"))) { printf("Error opening file %s\n", filename); return 1; } if (XMLParser_ParseValidateDTD(vp, parser, cstream, f, 0)) { printf("Elements (total: %d) in namespace \"%s\" were valid\nin the" " document %s\n", nsparser.elemCount, ((*nsparser.wantedUri) ? nsparser.wantedUri : "not specified"), filename); } fclose(f); XMLVector_Free(nsparser.filteredAtts); XMLParser_FreeDTDValidator(vp); XMLParser_Free(parser); return 0; USAGE: puts("Usage: nsvalid document.xml /DTD:<optional> /URI:<optional>\n" "Example: nsvalid my.xml /DTD:/home/my.dtd /URI:http://my.org"); return 1; }