msxml3: Enable inline wrappers and fix warnings.
[wine/multimedia.git] / dlls / msxml3 / schema.c
blob2f31016a196d493bef55cbe3f323216309390247
1 /*
2 * Schema cache implementation
4 * Copyright 2007 Huw Davies
5 * Copyright 2010 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include "config.h"
26 #include <assert.h>
27 #include <stdarg.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/xmlerror.h>
30 # include <libxml/tree.h>
31 # include <libxml/xmlschemas.h>
32 # include <libxml/schemasInternals.h>
33 # include <libxml/hash.h>
34 # include <libxml/parser.h>
35 # include <libxml/parserInternals.h>
36 # include <libxml/xmlIO.h>
37 # include <libxml/xmlversion.h>
38 # include <libxml/xpath.h>
39 #endif
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winuser.h"
44 #include "ole2.h"
45 #include "msxml6.h"
47 #include "wine/debug.h"
49 #include "msxml_private.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
53 /* We use a chained hashtable, which can hold any number of schemas
54 * TODO: grow/shrink hashtable depending on load factor
55 * TODO: implement read-only where appropriate
58 /* This is just the number of buckets, should be prime */
59 #define DEFAULT_HASHTABLE_SIZE 17
61 #ifdef HAVE_LIBXML2
63 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI);
65 static const xmlChar XSD_schema[] = "schema";
66 static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
67 static const xmlChar XDR_schema[] = "Schema";
68 static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
69 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
71 static xmlChar const* datatypes_src;
72 static int datatypes_len;
73 static HGLOBAL datatypes_handle;
74 static HRSRC datatypes_rsrc;
75 static xmlSchemaPtr datatypes_schema;
77 static const WCHAR emptyW[] = {0};
79 /* Supported types:
80 * msxml3 - XDR only
81 * msxml4 - XDR & XSD
82 * msxml5 - XDR & XSD
83 * mxsml6 - XSD only
85 * CacheType_NS is a special type used for read-only collection build with
86 * IXMLDOMDocument2::namespaces()
88 typedef enum {
89 CacheEntryType_Invalid,
90 CacheEntryType_XDR,
91 CacheEntryType_XSD,
92 CacheEntryType_NS
93 } CacheEntryType;
95 typedef struct
97 DispatchEx dispex;
98 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface;
99 LONG ref;
101 MSXML_VERSION version;
102 xmlHashTablePtr cache;
104 VARIANT_BOOL validateOnLoad;
105 int read_only;
106 } schema_cache;
108 typedef struct
110 CacheEntryType type;
111 xmlSchemaPtr schema;
112 xmlDocPtr doc;
113 LONG ref;
114 } cache_entry;
116 typedef struct
118 LONG index;
119 BSTR* out;
120 } cache_index_data;
122 /* datatypes lookup stuff
123 * generated with help from gperf */
124 #define DT_MIN_STR_LEN 2
125 #define DT_MAX_STR_LEN 11
126 #define DT_MIN_HASH_VALUE 2
127 #define DT_MAX_HASH_VALUE 115
129 static const xmlChar DT_bin_base64[] = "bin.base64";
130 static const xmlChar DT_bin_hex[] = "bin.hex";
131 static const xmlChar DT_boolean[] = "boolean";
132 static const xmlChar DT_char[] = "char";
133 static const xmlChar DT_date[] = "date";
134 static const xmlChar DT_date_tz[] = "date.tz";
135 static const xmlChar DT_dateTime[] = "dateTime";
136 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
137 static const xmlChar DT_entity[] = "entity";
138 static const xmlChar DT_entities[] = "entities";
139 static const xmlChar DT_enumeration[] = "enumeration";
140 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
141 static const xmlChar DT_float[] = "float";
142 static const xmlChar DT_i1[] = "i1";
143 static const xmlChar DT_i2[] = "i2";
144 static const xmlChar DT_i4[] = "i4";
145 static const xmlChar DT_i8[] = "i8";
146 static const xmlChar DT_id[] = "id";
147 static const xmlChar DT_idref[] = "idref";
148 static const xmlChar DT_idrefs[] = "idrefs";
149 static const xmlChar DT_int[] = "int";
150 static const xmlChar DT_nmtoken[] = "nmtoken";
151 static const xmlChar DT_nmtokens[] = "nmtokens";
152 static const xmlChar DT_notation[] = "notation";
153 static const xmlChar DT_number[] = "number";
154 static const xmlChar DT_r4[] = "r4";
155 static const xmlChar DT_r8[] = "r8";
156 static const xmlChar DT_string[] = "string";
157 static const xmlChar DT_time[] = "time";
158 static const xmlChar DT_time_tz[] = "time.tz";
159 static const xmlChar DT_ui1[] = "ui1";
160 static const xmlChar DT_ui2[] = "ui2";
161 static const xmlChar DT_ui4[] = "ui4";
162 static const xmlChar DT_ui8[] = "ui8";
163 static const xmlChar DT_uri[] = "uri";
164 static const xmlChar DT_uuid[] = "uuid";
166 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
167 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
168 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
169 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
170 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
171 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
172 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
173 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
174 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
175 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
176 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
177 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
178 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
179 static const OLECHAR wDT_i1[] = {'i','1',0};
180 static const OLECHAR wDT_i2[] = {'i','2',0};
181 static const OLECHAR wDT_i4[] = {'i','4',0};
182 static const OLECHAR wDT_i8[] = {'i','8',0};
183 static const OLECHAR wDT_id[] = {'i','d',0};
184 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
185 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
186 static const OLECHAR wDT_int[] = {'i','n','t',0};
187 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
188 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
189 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
190 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
191 static const OLECHAR wDT_r4[] = {'r','4',0};
192 static const OLECHAR wDT_r8[] = {'r','8',0};
193 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
194 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
195 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
196 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
197 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
198 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
199 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
200 static const OLECHAR wDT_uri[] = {'u','r','i',0};
201 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
203 static const BYTE hash_assoc_values[] =
205 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
206 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
207 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
208 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
209 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
210 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
211 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
212 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
213 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
214 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
215 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
216 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
217 0, 0, 10, 116, 116, 116, 116, 116, 116, 116,
218 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
219 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
220 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
221 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
222 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
223 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
224 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
225 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
226 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
227 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
228 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
229 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
230 116, 116, 116, 116, 116, 116
233 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
235 va_list ap;
236 va_start(ap, msg);
237 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
238 va_end(ap);
241 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
243 va_list ap;
244 va_start(ap, msg);
245 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
246 va_end(ap);
249 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
250 static void parser_serror(void* ctx, xmlErrorPtr err)
252 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
254 #endif
256 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
258 TRACE("(%p)\n", spctx);
260 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
261 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
262 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
263 #endif
265 return xmlSchemaParse(spctx);
268 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
270 va_list ap;
271 va_start(ap, msg);
272 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
273 va_end(ap);
276 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
278 va_list ap;
279 va_start(ap, msg);
280 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
281 va_end(ap);
284 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
285 static void validate_serror(void* ctx, xmlErrorPtr err)
287 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
289 #endif
291 static HRESULT schema_cache_get_item(IUnknown *iface, LONG index, VARIANT *item)
293 V_VT(item) = VT_BSTR;
294 return IXMLDOMSchemaCollection2_get_namespaceURI((IXMLDOMSchemaCollection2*)iface, index, &V_BSTR(item));
297 static const struct enumvariant_funcs schemacache_enumvariant = {
298 schema_cache_get_item,
299 NULL
302 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
304 xmlSchemaValidCtxtPtr svctx;
305 int err;
307 TRACE("(%p, %p)\n", schema, tree);
308 /* TODO: if validateOnLoad property is false,
309 * we probably need to validate the schema here. */
310 svctx = xmlSchemaNewValidCtxt(schema);
311 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
312 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
313 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
314 #endif
316 if (tree->type == XML_DOCUMENT_NODE)
317 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
318 else
319 err = xmlSchemaValidateOneElement(svctx, tree);
321 xmlSchemaFreeValidCtxt(svctx);
322 return err? S_FALSE : S_OK;
325 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
327 DWORD hval = (len == -1)? xmlStrlen(str) : len;
329 switch (hval)
331 default:
332 hval += hash_assoc_values[str[10]];
333 /*FALLTHROUGH*/
334 case 10:
335 hval += hash_assoc_values[str[9]];
336 /*FALLTHROUGH*/
337 case 9:
338 hval += hash_assoc_values[str[8]];
339 /*FALLTHROUGH*/
340 case 8:
341 hval += hash_assoc_values[str[7]];
342 /*FALLTHROUGH*/
343 case 7:
344 hval += hash_assoc_values[str[6]];
345 /*FALLTHROUGH*/
346 case 6:
347 hval += hash_assoc_values[str[5]];
348 /*FALLTHROUGH*/
349 case 5:
350 hval += hash_assoc_values[str[4]];
351 /*FALLTHROUGH*/
352 case 4:
353 hval += hash_assoc_values[str[3]];
354 /*FALLTHROUGH*/
355 case 3:
356 hval += hash_assoc_values[str[2]];
357 /*FALLTHROUGH*/
358 case 2:
359 hval += hash_assoc_values[str[1]];
360 /*FALLTHROUGH*/
361 case 1:
362 hval += hash_assoc_values[str[0]];
363 break;
365 return hval;
368 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
370 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
372 switch (hval)
374 default:
375 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
376 /*FALLTHROUGH*/
377 case 10:
378 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
379 /*FALLTHROUGH*/
380 case 9:
381 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
382 /*FALLTHROUGH*/
383 case 8:
384 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
385 /*FALLTHROUGH*/
386 case 7:
387 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
388 /*FALLTHROUGH*/
389 case 6:
390 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
391 /*FALLTHROUGH*/
392 case 5:
393 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
394 /*FALLTHROUGH*/
395 case 4:
396 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
397 /*FALLTHROUGH*/
398 case 3:
399 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
400 /*FALLTHROUGH*/
401 case 2:
402 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
403 /*FALLTHROUGH*/
404 case 1:
405 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
406 break;
408 return hval;
411 static const xmlChar *const DT_string_table[LAST_DT] =
413 DT_bin_base64,
414 DT_bin_hex,
415 DT_boolean,
416 DT_char,
417 DT_date,
418 DT_date_tz,
419 DT_dateTime,
420 DT_dateTime_tz,
421 DT_entity,
422 DT_entities,
423 DT_enumeration,
424 DT_fixed_14_4,
425 DT_float,
426 DT_i1,
427 DT_i2,
428 DT_i4,
429 DT_i8,
430 DT_id,
431 DT_idref,
432 DT_idrefs,
433 DT_int,
434 DT_nmtoken,
435 DT_nmtokens,
436 DT_notation,
437 DT_number,
438 DT_r4,
439 DT_r8,
440 DT_string,
441 DT_time,
442 DT_time_tz,
443 DT_ui1,
444 DT_ui2,
445 DT_ui4,
446 DT_ui8,
447 DT_uri,
448 DT_uuid
451 static const WCHAR *const DT_wstring_table[LAST_DT] =
453 wDT_bin_base64,
454 wDT_bin_hex,
455 wDT_boolean,
456 wDT_char,
457 wDT_date,
458 wDT_date_tz,
459 wDT_dateTime,
460 wDT_dateTime_tz,
461 wDT_entity,
462 wDT_entities,
463 wDT_enumeration,
464 wDT_fixed_14_4,
465 wDT_float,
466 wDT_i1,
467 wDT_i2,
468 wDT_i4,
469 wDT_i8,
470 wDT_id,
471 wDT_idref,
472 wDT_idrefs,
473 wDT_int,
474 wDT_nmtoken,
475 wDT_nmtokens,
476 wDT_notation,
477 wDT_number,
478 wDT_r4,
479 wDT_r8,
480 wDT_string,
481 wDT_time,
482 wDT_time_tz,
483 wDT_ui1,
484 wDT_ui2,
485 wDT_ui4,
486 wDT_ui8,
487 wDT_uri,
488 wDT_uuid
491 static const XDR_DT DT_lookup_table[] =
493 -1, -1,
494 DT_I8,
495 DT_UI8,
496 DT_TIME,
497 -1, -1,
498 DT_I4,
499 DT_UI4,
500 -1, -1, -1,
501 DT_R8,
502 DT_URI,
504 DT_FLOAT,
506 DT_R4,
507 DT_INT,
508 DT_CHAR,
510 DT_ENTITY,
511 DT_ID,
512 DT_ENTITIES,
513 DT_UUID,
514 -1, -1,
515 DT_TIME_TZ,
517 DT_DATE,
519 DT_NUMBER,
520 DT_BIN_HEX,
521 DT_DATETIME,
523 DT_IDREF,
524 DT_IDREFS,
525 DT_BOOLEAN,
526 -1, -1, -1,
527 DT_STRING,
528 DT_NMTOKEN,
529 DT_NMTOKENS,
531 DT_BIN_BASE64,
533 DT_I2,
534 DT_UI2,
535 -1, -1, -1,
536 DT_DATE_TZ,
537 DT_NOTATION,
538 -1, -1,
539 DT_DATETIME_TZ,
540 DT_I1,
541 DT_UI1,
542 -1, -1,
543 DT_ENUMERATION,
544 -1, -1, -1, -1, -1, -1, -1, -1, -1,
545 -1, -1, -1, -1, -1, -1, -1, -1, -1,
546 -1, -1, -1, -1, -1, -1, -1, -1, -1,
547 -1, -1, -1, -1, -1, -1, -1, -1, -1,
548 -1, -1, -1, -1, -1, -1, -1, -1, -1,
549 -1, -1, -1, -1, -1, -1, -1, -1,
550 DT_FIXED_14_4
553 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
555 DWORD hash = dt_hash(str, len);
556 XDR_DT dt = DT_INVALID;
558 if (hash <= DT_MAX_HASH_VALUE)
559 dt = DT_lookup_table[hash];
561 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
562 return dt;
564 return DT_INVALID;
567 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
569 DWORD hash = dt_hash_bstr(bstr, len);
570 XDR_DT dt = DT_INVALID;
572 if (hash <= DT_MAX_HASH_VALUE)
573 dt = DT_lookup_table[hash];
575 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
576 return dt;
578 return DT_INVALID;
581 xmlChar const* dt_to_str(XDR_DT dt)
583 if (dt == DT_INVALID)
584 return NULL;
586 return DT_string_table[dt];
589 OLECHAR const* dt_to_bstr(XDR_DT dt)
591 if (dt == DT_INVALID)
592 return NULL;
594 return DT_wstring_table[dt];
597 const char* debugstr_dt(XDR_DT dt)
599 return debugstr_a(dt != DT_INVALID ? (const char*)DT_string_table[dt] : NULL);
602 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
604 xmlDocPtr tmp_doc;
605 xmlNodePtr node;
606 xmlNsPtr ns;
607 HRESULT hr;
609 TRACE("(dt:%s, %s)\n", debugstr_dt(dt), debugstr_a((char const*)content));
611 if (!datatypes_schema)
613 xmlSchemaParserCtxtPtr spctx;
614 assert(datatypes_src != NULL);
615 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
616 datatypes_schema = Schema_parse(spctx);
617 xmlSchemaFreeParserCtxt(spctx);
620 switch (dt)
622 case DT_INVALID:
623 return E_FAIL;
624 case DT_BIN_BASE64:
625 case DT_BIN_HEX:
626 case DT_BOOLEAN:
627 case DT_CHAR:
628 case DT_DATE:
629 case DT_DATE_TZ:
630 case DT_DATETIME:
631 case DT_DATETIME_TZ:
632 case DT_FIXED_14_4:
633 case DT_FLOAT:
634 case DT_I1:
635 case DT_I2:
636 case DT_I4:
637 case DT_I8:
638 case DT_INT:
639 case DT_NMTOKEN:
640 case DT_NMTOKENS:
641 case DT_NUMBER:
642 case DT_R4:
643 case DT_R8:
644 case DT_STRING:
645 case DT_TIME:
646 case DT_TIME_TZ:
647 case DT_UI1:
648 case DT_UI2:
649 case DT_UI4:
650 case DT_UI8:
651 case DT_URI:
652 case DT_UUID:
653 if (!datatypes_schema)
655 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
656 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
658 /* Hopefully they don't need much in the way of XDR datatypes support... */
659 return S_OK;
662 if (content && xmlStrlen(content))
664 tmp_doc = xmlNewDoc(NULL);
665 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
666 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
667 xmlSetNs(node, ns);
668 xmlDocSetRootElement(tmp_doc, node);
670 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
671 xmlFreeDoc(tmp_doc);
673 else
674 { /* probably the node is being created manually and has no content yet */
675 hr = S_OK;
677 return hr;
678 default:
679 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
680 return S_OK;
684 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
686 return (node->ns != NULL)? node->ns->href : NULL;
689 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
691 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
692 xmlHashLookup(This->cache, nsURI);
695 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
697 cache_entry* entry = get_entry(This, get_node_nsURI(node));
698 return (!entry)? NULL : entry->schema;
701 static xmlExternalEntityLoader _external_entity_loader;
703 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
704 xmlParserCtxtPtr ctxt)
706 xmlParserInputPtr input;
708 TRACE("(%s %s %p)\n", debugstr_a(URL), debugstr_a(ID), ctxt);
710 assert(MSXML_hInstance != NULL);
711 assert(datatypes_rsrc != NULL);
712 assert(datatypes_handle != NULL);
713 assert(datatypes_src != NULL);
715 /* TODO: if the desired schema is in the cache, load it from there */
716 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
718 TRACE("loading built-in schema for %s\n", URL);
719 input = xmlNewStringInputStream(ctxt, datatypes_src);
721 else
723 input = _external_entity_loader(URL, ID, ctxt);
726 return input;
729 void schemasInit(void)
731 int len;
732 xmlChar* buf;
733 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
735 FIXME("failed to find resource for %s\n", DT_nsURI);
736 return;
739 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
741 FIXME("failed to load resource for %s\n", DT_nsURI);
742 return;
744 buf = LockResource(datatypes_handle);
745 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
747 /* Resource is loaded as raw data,
748 * need a null-terminated string */
749 while (buf[len] != '>')
750 buf[len--] = 0;
751 datatypes_src = buf;
752 datatypes_len = len + 1;
754 if (xmlGetExternalEntityLoader() != external_entity_loader)
756 _external_entity_loader = xmlGetExternalEntityLoader();
757 xmlSetExternalEntityLoader(external_entity_loader);
761 void schemasCleanup(void)
763 xmlSchemaFree(datatypes_schema);
764 xmlSetExternalEntityLoader(_external_entity_loader);
767 static LONG cache_entry_add_ref(cache_entry* entry)
769 LONG ref = InterlockedIncrement(&entry->ref);
770 TRACE("(%p)->(%d)\n", entry, ref);
771 return ref;
774 static LONG cache_entry_release(cache_entry* entry)
776 LONG ref = InterlockedDecrement(&entry->ref);
777 TRACE("(%p)->(%d)\n", entry, ref);
779 if (ref == 0)
781 if (entry->type == CacheEntryType_XSD)
783 xmldoc_release(entry->doc);
784 entry->schema->doc = NULL;
785 xmlSchemaFree(entry->schema);
787 else if (entry->type == CacheEntryType_XDR)
789 xmldoc_release(entry->doc);
790 xmldoc_release(entry->schema->doc);
791 entry->schema->doc = NULL;
792 xmlSchemaFree(entry->schema);
795 heap_free(entry);
797 return ref;
800 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl;
802 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
804 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
807 static inline schema_cache* impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection* iface)
809 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
812 static inline schema_cache* unsafe_impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection *iface)
814 return iface->lpVtbl == (void*)&XMLDOMSchemaCollection2Vtbl ? impl_from_IXMLDOMSchemaCollection(iface) : NULL;
817 static inline CacheEntryType cache_type_from_xmlDocPtr(xmlDocPtr schema)
819 xmlNodePtr root = NULL;
820 if (schema)
821 root = xmlDocGetRootElement(schema);
822 if (root && root->ns)
825 if (xmlStrEqual(root->name, XDR_schema) &&
826 xmlStrEqual(root->ns->href, XDR_nsURI))
828 return CacheEntryType_XDR;
830 else if (xmlStrEqual(root->name, XSD_schema) &&
831 xmlStrEqual(root->ns->href, XSD_nsURI))
833 return CacheEntryType_XSD;
836 return CacheEntryType_Invalid;
839 static BOOL link_datatypes(xmlDocPtr schema)
841 xmlNodePtr root, next, child;
842 xmlNsPtr ns;
844 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
845 root = xmlDocGetRootElement(schema);
846 if (!root)
847 return FALSE;
849 for (ns = root->nsDef; ns != NULL; ns = ns->next)
851 if (xmlStrEqual(ns->href, DT_nsURI))
852 break;
855 if (!ns)
856 return FALSE;
858 next = xmlFirstElementChild(root);
859 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
860 if (next) child = xmlAddPrevSibling(next, child);
861 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
862 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
864 return TRUE;
867 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
869 cache_entry* entry = heap_alloc(sizeof(cache_entry));
870 xmlSchemaParserCtxtPtr spctx;
871 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
873 link_datatypes(new_doc);
875 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
876 * do we need to do something special here? */
877 entry->type = CacheEntryType_XSD;
878 entry->ref = 0;
879 spctx = xmlSchemaNewDocParserCtxt(new_doc);
881 if ((entry->schema = Schema_parse(spctx)))
883 xmldoc_init(entry->schema->doc, v);
884 entry->doc = entry->schema->doc;
885 xmldoc_add_ref(entry->doc);
887 else
889 FIXME("failed to parse doc\n");
890 xmlFreeDoc(new_doc);
891 heap_free(entry);
892 entry = NULL;
894 xmlSchemaFreeParserCtxt(spctx);
895 return entry;
898 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
900 cache_entry* entry = heap_alloc(sizeof(cache_entry));
901 xmlSchemaParserCtxtPtr spctx;
902 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
904 link_datatypes(xsd_doc);
906 entry->type = CacheEntryType_XDR;
907 entry->ref = 0;
908 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
910 if ((entry->schema = Schema_parse(spctx)))
912 entry->doc = new_doc;
913 xmldoc_init(entry->schema->doc, version);
914 xmldoc_init(entry->doc, version);
915 xmldoc_add_ref(entry->doc);
916 xmldoc_add_ref(entry->schema->doc);
918 else
920 FIXME("failed to parse doc\n");
921 xmlFreeDoc(new_doc);
922 xmlFreeDoc(xsd_doc);
923 heap_free(entry);
924 entry = NULL;
926 xmlSchemaFreeParserCtxt(spctx);
928 return entry;
931 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
933 cache_entry* entry;
934 IXMLDOMDocument3* domdoc = NULL;
935 xmlDocPtr doc = NULL;
936 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
937 VARIANT_BOOL b = VARIANT_FALSE;
938 CacheEntryType type = CacheEntryType_Invalid;
940 if (hr != S_OK)
942 FIXME("failed to create domdoc\n");
943 return NULL;
945 assert(domdoc != NULL);
946 assert(V_VT(&url) == VT_BSTR);
948 hr = IXMLDOMDocument3_load(domdoc, url, &b);
949 if (hr != S_OK)
951 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
952 if (b != VARIANT_TRUE)
954 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url)));
955 IXMLDOMDocument3_Release(domdoc);
956 return NULL;
959 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
960 type = cache_type_from_xmlDocPtr(doc);
962 switch (type)
964 case CacheEntryType_XSD:
965 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
966 break;
967 case CacheEntryType_XDR:
968 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
969 break;
970 default:
971 entry = NULL;
972 FIXME("invalid schema\n");
973 break;
975 IXMLDOMDocument3_Release(domdoc);
977 return entry;
980 static void cache_free(void* data, xmlChar* name /* ignored */)
982 cache_entry_release((cache_entry*)data);
985 /* This one adds all namespaces defined in document to a cache, without anything
986 associated with uri obviously.
987 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
988 it uses additional node type to describe namespace definition attribute while
989 in msxml it's expected to be a normal attribute - as a workaround document is
990 queried at libxml2 level here. */
991 HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node)
993 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
994 static const xmlChar query[] = "//*/namespace::*";
995 xmlXPathObjectPtr nodeset;
996 xmlXPathContextPtr ctxt;
998 This->read_only = 1;
1000 ctxt = xmlXPathNewContext(node->node->doc);
1002 nodeset = xmlXPathEvalExpression(query, ctxt);
1003 xmlXPathFreeContext(ctxt);
1005 if (nodeset)
1007 int pos = 0, len = xmlXPathNodeSetGetLength(nodeset->nodesetval);
1009 if (len == 0) return S_OK;
1011 while (pos < len)
1013 xmlNodePtr node = xmlXPathNodeSetItem(nodeset->nodesetval, pos);
1014 if (node->type == XML_NAMESPACE_DECL)
1016 static const xmlChar defns[] = "http://www.w3.org/XML/1998/namespace";
1017 xmlNsPtr ns = (xmlNsPtr)node;
1018 cache_entry *entry;
1020 /* filter out default uri */
1021 if (xmlStrEqual(ns->href, defns))
1023 pos++;
1024 continue;
1027 entry = heap_alloc(sizeof(cache_entry));
1028 entry->type = CacheEntryType_NS;
1029 entry->ref = 1;
1030 entry->schema = NULL;
1031 entry->doc = NULL;
1033 xmlHashRemoveEntry(This->cache, ns->href, cache_free);
1034 xmlHashAddEntry(This->cache, ns->href, entry);
1036 pos++;
1039 xmlXPathFreeObject(nodeset);
1042 return S_OK;
1045 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
1046 REFIID riid, void** ppvObject)
1048 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1050 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1052 if ( IsEqualIID(riid, &IID_IUnknown) ||
1053 IsEqualIID(riid, &IID_IDispatch) ||
1054 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
1055 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
1057 *ppvObject = iface;
1059 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
1061 return *ppvObject ? S_OK : E_NOINTERFACE;
1063 else
1065 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1066 *ppvObject = NULL;
1067 return E_NOINTERFACE;
1070 IXMLDOMSchemaCollection2_AddRef(iface);
1072 return S_OK;
1075 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
1077 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1078 LONG ref = InterlockedIncrement(&This->ref);
1079 TRACE("(%p)->(%d)\n", This, ref);
1080 return ref;
1083 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
1085 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1086 LONG ref = InterlockedDecrement(&This->ref);
1087 TRACE("(%p)->(%d)\n", This, ref);
1089 if (ref == 0)
1091 xmlHashFree(This->cache, cache_free);
1092 release_dispex(&This->dispex);
1093 heap_free(This);
1096 return ref;
1099 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1100 UINT* pctinfo)
1102 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1103 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1106 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1107 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1109 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1110 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
1111 iTInfo, lcid, ppTInfo);
1114 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1115 REFIID riid, LPOLESTR* rgszNames,
1116 UINT cNames, LCID lcid, DISPID* rgDispId)
1118 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1119 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1120 riid, rgszNames, cNames, lcid, rgDispId);
1123 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1124 DISPID dispIdMember, REFIID riid, LCID lcid,
1125 WORD wFlags, DISPPARAMS* pDispParams,
1126 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1127 UINT* puArgErr)
1129 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1130 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1131 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1134 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1136 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1137 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1138 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1140 if (This->read_only) return E_FAIL;
1142 switch (V_VT(&var))
1144 case VT_NULL:
1146 xmlHashRemoveEntry(This->cache, name, cache_free);
1148 break;
1150 case VT_BSTR:
1152 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1154 if (entry)
1156 cache_entry_add_ref(entry);
1158 else
1160 heap_free(name);
1161 return E_FAIL;
1164 xmlHashRemoveEntry(This->cache, name, cache_free);
1165 xmlHashAddEntry(This->cache, name, entry);
1167 break;
1169 case VT_DISPATCH:
1171 xmlDocPtr doc = NULL;
1172 cache_entry* entry;
1173 CacheEntryType type;
1174 IXMLDOMNode* domnode = NULL;
1175 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1177 if (domnode)
1178 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1180 if (!doc)
1182 IXMLDOMNode_Release(domnode);
1183 heap_free(name);
1184 return E_INVALIDARG;
1186 type = cache_type_from_xmlDocPtr(doc);
1188 if (type == CacheEntryType_XSD)
1190 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1192 else if (type == CacheEntryType_XDR)
1194 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1196 else
1198 WARN("invalid schema!\n");
1199 entry = NULL;
1202 IXMLDOMNode_Release(domnode);
1204 if (entry)
1206 cache_entry_add_ref(entry);
1208 else
1210 heap_free(name);
1211 return E_FAIL;
1214 xmlHashRemoveEntry(This->cache, name, cache_free);
1215 xmlHashAddEntry(This->cache, name, entry);
1217 break;
1219 default:
1221 heap_free(name);
1222 return E_INVALIDARG;
1225 heap_free(name);
1226 return S_OK;
1229 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1230 IXMLDOMNode** node)
1232 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1233 cache_entry* entry;
1234 xmlChar* name;
1236 TRACE("(%p)->(%s %p)\n", This, debugstr_w(uri), node);
1238 if (This->version == MSXML6) return E_NOTIMPL;
1240 if (!node)
1241 return E_POINTER;
1243 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1244 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1245 heap_free(name);
1247 /* TODO: this should be read-only */
1248 if (entry && entry->doc)
1249 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1251 *node = NULL;
1252 return S_OK;
1255 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1257 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1258 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1259 TRACE("(%p)->(%s)\n", This, debugstr_w(uri));
1261 if (This->version == MSXML6) return E_NOTIMPL;
1263 xmlHashRemoveEntry(This->cache, name, cache_free);
1264 heap_free(name);
1265 return S_OK;
1268 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1270 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1271 TRACE("(%p)->(%p)\n", This, length);
1273 if (!length)
1274 return E_POINTER;
1275 *length = xmlHashSize(This->cache);
1276 return S_OK;
1279 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1281 cache_index_data* index_data = (cache_index_data*)index;
1283 if (index_data->index-- == 0)
1284 *index_data->out = bstr_from_xmlChar(name);
1287 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1288 LONG index, BSTR* len)
1290 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1291 cache_index_data data = {index, len};
1292 TRACE("(%p)->(%i %p)\n", This, index, len);
1294 if (!len)
1295 return E_POINTER;
1297 if (index >= xmlHashSize(This->cache))
1298 return E_FAIL;
1300 *len = NULL;
1301 xmlHashScan(This->cache, cache_index, &data);
1302 return S_OK;
1305 static void cache_copy(void* data, void* dest, xmlChar* name)
1307 schema_cache* This = (schema_cache*) dest;
1308 cache_entry* entry = (cache_entry*) data;
1310 if (xmlHashLookup(This->cache, name) == NULL)
1312 cache_entry_add_ref(entry);
1313 xmlHashAddEntry(This->cache, name, entry);
1317 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1318 IXMLDOMSchemaCollection* collection)
1320 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1321 schema_cache* That;
1323 TRACE("(%p)->(%p)\n", This, collection);
1325 if (!collection)
1326 return E_POINTER;
1328 That = unsafe_impl_from_IXMLDOMSchemaCollection(collection);
1329 if (!That)
1331 ERR("external collection implementation\n");
1332 return E_FAIL;
1335 /* TODO: detect errors while copying & return E_FAIL */
1336 xmlHashScan(That->cache, cache_copy, This);
1338 return S_OK;
1341 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface, IUnknown** enumv)
1343 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1344 TRACE("(%p)->(%p)\n", This, enumv);
1345 return create_enumvariant((IUnknown*)iface, TRUE, &schemacache_enumvariant, (IEnumVARIANT**)enumv);
1348 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1350 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1351 FIXME("(%p): stub\n", This);
1352 return E_NOTIMPL;
1355 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1356 VARIANT_BOOL value)
1358 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1359 FIXME("(%p)->(%d): stub\n", This, value);
1361 This->validateOnLoad = value;
1362 /* it's ok to disable it, cause we don't validate on load anyway */
1363 if (value == VARIANT_FALSE) return S_OK;
1365 return E_NOTIMPL;
1368 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1369 VARIANT_BOOL* value)
1371 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1372 TRACE("(%p)->(%p)\n", This, value);
1374 if (!value) return E_POINTER;
1375 *value = This->validateOnLoad;
1377 return S_OK;
1380 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1381 BSTR namespaceURI, ISchema** schema)
1383 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1384 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1385 if (schema)
1386 *schema = NULL;
1387 return E_NOTIMPL;
1390 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1391 IXMLDOMNode* node, ISchemaItem** item)
1393 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1394 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1395 if (item)
1396 *item = NULL;
1397 return E_NOTIMPL;
1400 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl =
1402 schema_cache_QueryInterface,
1403 schema_cache_AddRef,
1404 schema_cache_Release,
1405 schema_cache_GetTypeInfoCount,
1406 schema_cache_GetTypeInfo,
1407 schema_cache_GetIDsOfNames,
1408 schema_cache_Invoke,
1409 schema_cache_add,
1410 schema_cache_get,
1411 schema_cache_remove,
1412 schema_cache_get_length,
1413 schema_cache_get_namespaceURI,
1414 schema_cache_addCollection,
1415 schema_cache_get__newEnum,
1416 schema_cache_validate,
1417 schema_cache_put_validateOnLoad,
1418 schema_cache_get_validateOnLoad,
1419 schema_cache_getSchema,
1420 schema_cache_getDeclaration
1423 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1425 xmlSchemaElementPtr decl = NULL;
1426 xmlChar const* nsURI = get_node_nsURI(node);
1428 TRACE("(%p, %p)\n", schema, node);
1430 if (xmlStrEqual(nsURI, schema->targetNamespace))
1431 decl = xmlHashLookup(schema->elemDecl, node->name);
1433 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1435 FIXME("declaration not found in main schema - need to check schema imports!\n");
1436 /*xmlSchemaImportPtr import;
1437 if (nsURI == NULL)
1438 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1439 else
1440 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1442 if (import != NULL)
1443 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1446 return decl;
1449 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1451 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1452 while (decl != NULL && decl->refDecl != NULL)
1453 decl = decl->refDecl;
1454 return (decl != NULL)? decl->node : NULL;
1457 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1459 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1460 xmlSchemaPtr schema;
1462 TRACE("(%p, %p)\n", This, tree);
1464 if (!tree)
1465 return E_POINTER;
1467 if (tree->type == XML_DOCUMENT_NODE)
1468 tree = xmlDocGetRootElement(tree->doc);
1470 schema = get_node_schema(This, tree);
1471 /* TODO: if the ns is not in the cache, and it's a URL,
1472 * do we try to load from that? */
1473 if (schema)
1474 return Schema_validate_tree(schema, tree);
1475 else
1476 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1478 return E_FAIL;
1481 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1483 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1484 xmlSchemaPtr schema = get_node_schema(This, node);
1485 XDR_DT dt = DT_INVALID;
1487 TRACE("(%p, %p)\n", This, node);
1489 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1491 dt = str_to_dt(node->name, -1);
1493 else if (schema)
1495 xmlChar* str;
1496 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1498 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1499 if (str)
1501 dt = str_to_dt(str, -1);
1502 xmlFree(str);
1506 return dt;
1509 static const tid_t schemacache_iface_tids[] = {
1510 IXMLDOMSchemaCollection2_tid,
1514 static dispex_static_data_t schemacache_dispex = {
1515 NULL,
1516 IXMLDOMSchemaCollection2_tid,
1517 NULL,
1518 schemacache_iface_tids
1521 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1523 schema_cache* This = heap_alloc(sizeof(schema_cache));
1524 if (!This)
1525 return E_OUTOFMEMORY;
1527 TRACE("(%d %p %p)\n", version, outer, obj);
1529 This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl;
1530 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1531 This->ref = 1;
1532 This->version = version;
1533 This->validateOnLoad = VARIANT_TRUE;
1534 This->read_only = 0;
1535 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSchemaCollection2_iface, &schemacache_dispex);
1537 *obj = &This->IXMLDOMSchemaCollection2_iface;
1538 return S_OK;
1541 #else
1543 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1545 MESSAGE("This program tried to use a SchemaCache object, but\n"
1546 "libxml2 support was not present at compile time.\n");
1547 return E_NOTIMPL;
1550 #endif