1 #include <stdio.h>
2 #include "windows.h"
3 #include "urlmon.h"
4 #include "libparsifal/parsifal.h"
5 
6 #define MAX_URILEN 512
7 XMLCH gbase[MAX_URILEN] = {'\0'}; /* base uri - global for clarity */
8 
9 int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
10 int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName);
11 int PI(void *UserData, const XMLCH *target, const XMLCH *data);
12 int Characters(void *UserData, const XMLCH *chars, int cbChars);
13 int Comment(void *UserData, const XMLCH *chars, int cbChars);
14 int CharactersWide(void *UserData, const XMLCH *chars, int cbChars);
15 int StartCData(void *UserData);
16 int EndCData(void *UserData);
17 int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset);
18 void ErrorHandler(LPXMLPARSER parser);
19 int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
20 int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
21 int SkippedEntity(void *UserData, const XMLCH *name);
22 int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
23 /* see samples/misc/helper.c for comments of the following routines: */
24 size_t GetBaseDir(XMLCH *dst, XMLCH *src);
25 XMLCH *ResolveBaseUri(LPXMLPARSER parser, XMLCH *systemID, XMLCH *base);
26 
StartElement(void * UserData,const XMLCH * uri,const XMLCH * localName,const XMLCH * qName,LPXMLVECTOR atts)27 int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
28 {
29 	if (*uri)
30 		printf("\nStart tag: %s uri: %s localName: %s", qName, uri, localName);
31 	else
32 		printf("\nStart tag: %s", qName);
33 
34 	if (atts->length) {
35 		int i;
36 		LPXMLRUNTIMEATT att;
37 
38 		printf("\nhas %d attributes:", atts->length);
39 		for (i=0; i<atts->length; i++) {
40 			att = (LPXMLRUNTIMEATT)XMLVector_Get(atts, i);
41 
42 			if (*att->uri)
43 				printf("\n  Name: %s Value: %s Prefix: %s LocalName: %s Uri: %s",
44 					att->qname, att->value,
45 							att->prefix, att->localName,
46 								att->uri);
47 			else
48 				printf("\n  Name: %s Value: {%s}",
49 					att->qname, att->value);
50 		}
51 
52 		/* this demonstrates XMLParser_GetNamedItem and XML_ABORT, just
53 			change the name "findthis" here to abort parsing when
54 			this attribute is encountered: */
55 
56 		if (att = XMLParser_GetNamedItem(UserData, "findthis")) {
57 			printf("FOUND ATTRIBUTE %s value: %s\nAborting...\n", att->qname, att->value);
58 			return XML_ABORT;
59 		}
60 	}
61 	return 0;
62 }
63 
EndElement(void * UserData,const XMLCH * uri,const XMLCH * localName,const XMLCH * qName)64 int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName)
65 {
66 	printf("\nEnd tag: %s", qName);
67 	return 0;
68 }
69 
Characters(void * UserData,const XMLCH * chars,int cbChars)70 int Characters(void *UserData, const XMLCH *chars, int cbChars)
71 {
72 	printf("\nText (%d bytes): {", cbChars);
73 	for (; cbChars; cbChars--, chars++) putc(*chars, stdout);
74 	putc('}', stdout);
75 	return 0;
76 }
77 
SkippedEntity(void * UserData,const XMLCH * name)78 int SkippedEntity(void *UserData, const XMLCH *name)
79 {
80 	printf("\nskipped entity: %s", name);
81 	return 0;
82 }
83 
DoctypeDecl(void * UserData,const XMLCH * name,const XMLCH * publicID,const XMLCH * systemID,int hasInternalSubset)84 int DoctypeDecl(void *UserData, const XMLCH *name, const XMLCH *publicID, const XMLCH *systemID, int hasInternalSubset)
85 {
86 	printf("\nDOCTYPE Name: %s", name);
87 	if (publicID) printf(" publicID: %s", publicID);
88 	if (systemID) printf(" systemID: %s", systemID);
89 	printf(" hasInternalSubset: %d", hasInternalSubset);
90 	return 0;
91 }
92 
StartCData(void * UserData)93 int StartCData(void *UserData)
94 {
95 	printf("\nStart CData tag\n");
96 	/* will call Characters to report CDATA contents */
97 	return 0;
98 }
99 
EndCData(void * UserData)100 int EndCData(void *UserData)
101 {
102 	printf("\nEnd CData tag");
103 	return 0;
104 }
105 
Comment(void * UserData,const XMLCH * chars,int cbChars)106 int Comment(void *UserData, const XMLCH *chars, int cbChars)
107 {
108 	printf("\nComment (%d bytes): {", cbChars);
109 	for (; cbChars; cbChars--, chars++) putc(*chars, stdout);
110 	putc('}', stdout);
111 	return 0;
112 }
113 
PI(void * UserData,const XMLCH * target,const XMLCH * data)114 int PI(void *UserData, const XMLCH *target, const XMLCH *data)
115 {
116 	printf("\nPI tag - target: %s data: %s", target, ((*data) ? data : "no data"));
117 	return 0;
118 }
119 
ErrorHandler(LPXMLPARSER parser)120 void ErrorHandler(LPXMLPARSER parser)
121 {
122 	/* you should treat ERR_XMLP_ABORT as "user error" and give somekind of
123 	  description before returning from callbacks, otherwise we present parser error: */
124 	if (parser->ErrorCode != ERR_XMLP_ABORT) {
125 		XMLCH *SystemID = XMLParser_GetSystemID(parser);
126 		LPXMLENTITY curEnt = XMLParser_GetCurrentEntity(parser);
127 		printf("\nParsing Error: %s\nCode: %d",
128 			parser->ErrorString, parser->ErrorCode);
129 		if (curEnt && !curEnt->systemID) printf("\nin entity: '%s'", curEnt->name);
130 		if (SystemID) printf("\nSystemID: '%s'", SystemID);
131 	}
132 	printf("\nLine: %d\nColumn: %d", parser->ErrorLine, parser->ErrorColumn);
133 }
134 
135 /*
136 	Converts UTF-8 string to wchar_t string
137 	and shows converted string in MessageBoxW
138 
139 	Set charactersHandler = CharactersWide if
140 	you want to test UTF-8 to wchar_t conversion for
141 	text content, you shouldn't run large documents with
142 	CharactersWide because those MessageBoxes can get annoying...
143 */
CharactersWide(void * UserData,const XMLCH * chars,int cbChars)144 int CharactersWide(void *UserData, const XMLCH *chars, int cbChars)
145 {
146 	wchar_t wstr[1024];
147 	int size;
148 
149 	if (cbChars > 1023) cbChars = 1024;
150 
151 	if ((size = MultiByteToWideChar(CP_UTF8, 0, chars, cbChars, wstr, 1024))) {
152 		*(wstr+size) = L'\0';
153 		MessageBoxW(NULL, wstr, L"WinUrl sample", MB_OK);
154 	}
155 	else {
156 		printf("Unicode conversion error!");
157 		return XML_ABORT;
158 	}
159 	return 0;
160 }
161 
GetBaseDir(XMLCH * dst,XMLCH * src)162 size_t GetBaseDir(XMLCH *dst, XMLCH *src)
163 {
164 	XMLCH *s = strrchr(src, '/');
165 #ifdef _WIN32
166 	if (!s) s = strrchr(src, '\\');
167 #endif
168 	if (s) {
169 		size_t i = (s-src)+1;
170 		memcpy(dst, src, i);
171 		dst[i] = '\0';
172 		return i;
173 	}
174 	dst[0] = '\0';
175 	return 0;
176 }
177 
ResolveBaseUri(LPXMLPARSER parser,XMLCH * systemID,XMLCH * base)178 XMLCH *ResolveBaseUri(LPXMLPARSER parser, XMLCH *systemID, XMLCH *base)
179 {
180 	XMLCH *s=systemID;
181 	for (; *s; s++) {
182 		if (*s == ':') return systemID; /* probably absolute */
183 		if (*s == '/' || *s == '\\') break;
184 	}
185 	s = XMLParser_GetPrefixMapping(parser, "xml:base");
186 	return (s) ? s : base;
187 }
188 
ResolveEntity(void * UserData,LPXMLENTITY entity,LPBUFFEREDISTREAM reader)189 int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
190 {
191 	IStream *pStm = NULL; /* pointer to COM stream */
192 	HRESULT hr;
193 	XMLCH r[MAX_URILEN];
194 	XMLCH *uri = ResolveBaseUri((LPXMLPARSER)UserData, entity->systemID, gbase);
195 	if (uri != entity->systemID) {
196 		strcpy(r, uri);
197 		uri = strcat(r, entity->systemID);
198 	}
199 	printf("\nLoading external entity: %s uri: %s", entity->name, uri);
200 	hr = URLOpenBlockingStream(0, uri, &pStm, 0,0);
201 	if (!SUCCEEDED(hr)) {
202 		printf("\nError opening url '%s'", uri);
203 		if (pStm) pStm->lpVtbl->Release(pStm);
204 		return XML_ABORT;
205 	}
206 
207 	reader->inputData = pStm;
208 	return 0;
209 }
210 
FreeInputData(void * UserData,LPXMLENTITY entity,LPBUFFEREDISTREAM reader)211 int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
212 {
213 	IStream *pStm = (IStream*)reader->inputData;
214 	if (pStm) pStm->lpVtbl->Release(pStm);
215 	return 0;
216 }
217 
urlstream(BYTE * buf,int cBytes,int * cBytesActual,void * inputData)218 int urlstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
219 {
220 	/* calls IStream.Read in C COM way: */
221 	HRESULT hr = ((IStream*)inputData)->lpVtbl->Read((IStream*)inputData, buf, cBytes, cBytesActual);
222 	return (*cBytesActual < cBytes || !SUCCEEDED(hr));
223 }
224 
main(int argc,char * argv[])225 int main(int argc, char* argv[])
226 {
227 	LPXMLPARSER parser;
228 	IStream *pStm = NULL; /* pointer to COM stream */
229 	HRESULT hr;
230 	char szUrl[MAX_URILEN];
231 
232 	printf("\nWINURL Parsifal sample\n\nUrl to parse: ");
233 	gets(szUrl);
234 
235 	/* open the url stream: */
236 	hr = URLOpenBlockingStream(0, szUrl, &pStm, 0,0);
237 	if (!SUCCEEDED(hr)) {
238 		puts("Error opening url!");
239 		if (pStm) pStm->lpVtbl->Release(pStm);
240 		exit(1);
241 	}
242 
243 	GetBaseDir(gbase, szUrl);
244 
245 	if (!XMLParser_Create(&parser)) {
246 		puts("Error creating parser!");
247 		exit(1);
248 	}
249 
250 	parser->startElementHandler = StartElement;
251 	parser->endElementHandler = EndElement;
252 	parser->charactersHandler = Characters; /* set to CharactersWide
253 		to convert UTF-8 -> wchar_t */
254 	parser->processingInstructionHandler = PI;
255 	parser->commentHandler = Comment;
256 	parser->startCDATAHandler = StartCData;
257 	parser->endCDATAHandler = EndCData;
258 	parser->errorHandler = ErrorHandler;
259 	parser->startDTDHandler = DoctypeDecl;
260 	parser->skippedEntityHandler = SkippedEntity;
261 	parser->resolveEntityHandler = ResolveEntity;
262 	parser->externalEntityParsedHandler = FreeInputData;
263 	parser->UserData = parser;
264 
265 	printf("XMLFlags:\n");
266 	printf("XMLFLAG_NAMESPACES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACES));
267 	printf("XMLFLAG_NAMESPACE_PREFIXES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_NAMESPACE_PREFIXES));
268 	printf("XMLFLAG_EXTERNAL_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_EXTERNAL_GENERAL_ENTITIES));
269 	printf("XMLFLAG_PRESERVE_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_GENERAL_ENTITIES));
270 	printf("XMLFLAG_UNDEF_GENERAL_ENTITIES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_UNDEF_GENERAL_ENTITIES));
271 	printf("XMLFLAG_PRESERVE_WS_ATTRIBUTES: %d\n", _XMLParser_GetFlag(parser,XMLFLAG_PRESERVE_WS_ATTRIBUTES));
272 
273 	XMLParser_Parse(parser, urlstream, pStm, NULL);
274 
275 	if (pStm) pStm->lpVtbl->Release(pStm);
276 	XMLParser_Free(parser);
277 
278 	return 0;
279 }
280 
281 
282