wined3d: Check the wined3d resource type and usage instead of the GL target in textur...
[wine.git] / dlls / msxml3 / schema.c
blob3760019ce2e39d765bcbe6b64acd8e3797928a97
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 <assert.h>
25 #include <stdarg.h>
26 #include <libxml/xmlerror.h>
27 #include <libxml/tree.h>
28 #include <libxml/xmlschemas.h>
29 #include <libxml/schemasInternals.h>
30 #include <libxml/hash.h>
31 #include <libxml/parser.h>
32 #include <libxml/parserInternals.h>
33 #include <libxml/xmlIO.h>
34 #include <libxml/xmlversion.h>
35 #include <libxml/xpath.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "ole2.h"
41 #include "msxml6.h"
43 #include "wine/debug.h"
45 #include "msxml_private.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
49 /* We use a chained hashtable, which can hold any number of schemas
50 * TODO: grow/shrink hashtable depending on load factor
51 * TODO: implement read-only where appropriate
54 /* This is just the number of buckets, should be prime */
55 #define DEFAULT_HASHTABLE_SIZE 17
57 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI);
59 static const xmlChar XSD_schema[] = "schema";
60 static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
61 static const xmlChar XDR_schema[] = "Schema";
62 static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
63 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
65 static xmlChar * datatypes_src;
66 static int datatypes_len;
67 static HGLOBAL datatypes_handle;
68 static HRSRC datatypes_rsrc;
69 static xmlSchemaPtr datatypes_schema;
71 static const WCHAR emptyW[] = {0};
73 /* Supported types:
74 * msxml3 - XDR only
75 * msxml4 - XDR & XSD
76 * msxml5 - XDR & XSD
77 * mxsml6 - XSD only
79 * CacheType_NS is a special type used for read-only collection build with
80 * IXMLDOMDocument2::namespaces()
82 typedef enum {
83 CacheEntryType_Invalid,
84 CacheEntryType_XDR,
85 CacheEntryType_XSD,
86 CacheEntryType_NS
87 } CacheEntryType;
89 typedef struct
91 DispatchEx dispex;
92 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface;
93 LONG ref;
95 MSXML_VERSION version;
96 xmlHashTablePtr cache;
97 xmlChar **uris;
98 int allocated;
99 int count;
101 VARIANT_BOOL validateOnLoad;
102 int read_only;
103 } schema_cache;
105 typedef struct
107 CacheEntryType type;
108 xmlSchemaPtr schema;
109 xmlDocPtr doc;
110 LONG ref;
111 } cache_entry;
113 static const tid_t schema_cache_se_tids[] = {
114 IXMLDOMSchemaCollection_tid,
115 IXMLDOMSchemaCollection2_tid,
116 NULL_tid
119 /* datatypes lookup stuff
120 * generated with help from gperf */
121 #define DT_MIN_STR_LEN 2
122 #define DT_MAX_STR_LEN 11
123 #define DT_MIN_HASH_VALUE 2
124 #define DT_MAX_HASH_VALUE 115
126 static const xmlChar DT_bin_base64[] = "bin.base64";
127 static const xmlChar DT_bin_hex[] = "bin.hex";
128 static const xmlChar DT_boolean[] = "boolean";
129 static const xmlChar DT_char[] = "char";
130 static const xmlChar DT_date[] = "date";
131 static const xmlChar DT_date_tz[] = "date.tz";
132 static const xmlChar DT_dateTime[] = "dateTime";
133 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
134 static const xmlChar DT_entity[] = "entity";
135 static const xmlChar DT_entities[] = "entities";
136 static const xmlChar DT_enumeration[] = "enumeration";
137 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
138 static const xmlChar DT_float[] = "float";
139 static const xmlChar DT_i1[] = "i1";
140 static const xmlChar DT_i2[] = "i2";
141 static const xmlChar DT_i4[] = "i4";
142 static const xmlChar DT_i8[] = "i8";
143 static const xmlChar DT_id[] = "id";
144 static const xmlChar DT_idref[] = "idref";
145 static const xmlChar DT_idrefs[] = "idrefs";
146 static const xmlChar DT_int[] = "int";
147 static const xmlChar DT_nmtoken[] = "nmtoken";
148 static const xmlChar DT_nmtokens[] = "nmtokens";
149 static const xmlChar DT_notation[] = "notation";
150 static const xmlChar DT_number[] = "number";
151 static const xmlChar DT_r4[] = "r4";
152 static const xmlChar DT_r8[] = "r8";
153 static const xmlChar DT_string[] = "string";
154 static const xmlChar DT_time[] = "time";
155 static const xmlChar DT_time_tz[] = "time.tz";
156 static const xmlChar DT_ui1[] = "ui1";
157 static const xmlChar DT_ui2[] = "ui2";
158 static const xmlChar DT_ui4[] = "ui4";
159 static const xmlChar DT_ui8[] = "ui8";
160 static const xmlChar DT_uri[] = "uri";
161 static const xmlChar DT_uuid[] = "uuid";
163 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
164 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
165 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
166 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
167 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
168 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
169 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
170 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
171 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
172 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
173 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
174 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
175 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
176 static const OLECHAR wDT_i1[] = {'i','1',0};
177 static const OLECHAR wDT_i2[] = {'i','2',0};
178 static const OLECHAR wDT_i4[] = {'i','4',0};
179 static const OLECHAR wDT_i8[] = {'i','8',0};
180 static const OLECHAR wDT_id[] = {'i','d',0};
181 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
182 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
183 static const OLECHAR wDT_int[] = {'i','n','t',0};
184 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
185 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
186 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
187 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
188 static const OLECHAR wDT_r4[] = {'r','4',0};
189 static const OLECHAR wDT_r8[] = {'r','8',0};
190 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
191 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
192 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
193 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
194 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
195 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
196 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
197 static const OLECHAR wDT_uri[] = {'u','r','i',0};
198 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
200 static const BYTE hash_assoc_values[] =
202 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
203 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
204 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
205 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
206 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
207 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
208 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
209 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
210 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
211 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
212 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
213 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
214 0, 0, 10, 116, 116, 116, 116, 116, 116, 116,
215 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
216 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
217 116, 116, 116, 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
230 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
232 va_list ap;
233 va_start(ap, msg);
234 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
235 va_end(ap);
238 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
240 va_list ap;
241 va_start(ap, msg);
242 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
243 va_end(ap);
246 static void parser_serror(void* ctx, xmlErrorPtr err)
248 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
251 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
253 TRACE("(%p)\n", spctx);
255 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
256 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
257 return xmlSchemaParse(spctx);
260 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
262 va_list ap;
263 va_start(ap, msg);
264 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
265 va_end(ap);
268 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
270 va_list ap;
271 va_start(ap, msg);
272 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
273 va_end(ap);
276 static void validate_serror(void* ctx, xmlErrorPtr err)
278 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
281 static HRESULT schema_cache_get_item(IUnknown *iface, LONG index, VARIANT *item)
283 V_VT(item) = VT_BSTR;
284 return IXMLDOMSchemaCollection2_get_namespaceURI((IXMLDOMSchemaCollection2*)iface, index, &V_BSTR(item));
287 static const struct enumvariant_funcs schemacache_enumvariant = {
288 schema_cache_get_item,
289 NULL
292 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
294 xmlSchemaValidCtxtPtr svctx;
295 int err;
297 TRACE("(%p, %p)\n", schema, tree);
298 /* TODO: if validateOnLoad property is false,
299 * we probably need to validate the schema here. */
300 svctx = xmlSchemaNewValidCtxt(schema);
301 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
302 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
304 if (tree->type == XML_DOCUMENT_NODE)
305 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
306 else
307 err = xmlSchemaValidateOneElement(svctx, tree);
309 xmlSchemaFreeValidCtxt(svctx);
310 return err? S_FALSE : S_OK;
313 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
315 DWORD hval = (len == -1)? xmlStrlen(str) : len;
317 switch (hval)
319 default:
320 hval += hash_assoc_values[str[10]];
321 /*FALLTHROUGH*/
322 case 10:
323 hval += hash_assoc_values[str[9]];
324 /*FALLTHROUGH*/
325 case 9:
326 hval += hash_assoc_values[str[8]];
327 /*FALLTHROUGH*/
328 case 8:
329 hval += hash_assoc_values[str[7]];
330 /*FALLTHROUGH*/
331 case 7:
332 hval += hash_assoc_values[str[6]];
333 /*FALLTHROUGH*/
334 case 6:
335 hval += hash_assoc_values[str[5]];
336 /*FALLTHROUGH*/
337 case 5:
338 hval += hash_assoc_values[str[4]];
339 /*FALLTHROUGH*/
340 case 4:
341 hval += hash_assoc_values[str[3]];
342 /*FALLTHROUGH*/
343 case 3:
344 hval += hash_assoc_values[str[2]];
345 /*FALLTHROUGH*/
346 case 2:
347 hval += hash_assoc_values[str[1]];
348 /*FALLTHROUGH*/
349 case 1:
350 hval += hash_assoc_values[str[0]];
351 break;
353 return hval;
356 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
358 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
360 switch (hval)
362 default:
363 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
364 /*FALLTHROUGH*/
365 case 10:
366 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
367 /*FALLTHROUGH*/
368 case 9:
369 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
370 /*FALLTHROUGH*/
371 case 8:
372 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
373 /*FALLTHROUGH*/
374 case 7:
375 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
376 /*FALLTHROUGH*/
377 case 6:
378 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
379 /*FALLTHROUGH*/
380 case 5:
381 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
382 /*FALLTHROUGH*/
383 case 4:
384 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
385 /*FALLTHROUGH*/
386 case 3:
387 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
388 /*FALLTHROUGH*/
389 case 2:
390 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
391 /*FALLTHROUGH*/
392 case 1:
393 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
394 break;
396 return hval;
399 static const xmlChar *const DT_string_table[LAST_DT] =
401 DT_bin_base64,
402 DT_bin_hex,
403 DT_boolean,
404 DT_char,
405 DT_date,
406 DT_date_tz,
407 DT_dateTime,
408 DT_dateTime_tz,
409 DT_entity,
410 DT_entities,
411 DT_enumeration,
412 DT_fixed_14_4,
413 DT_float,
414 DT_i1,
415 DT_i2,
416 DT_i4,
417 DT_i8,
418 DT_id,
419 DT_idref,
420 DT_idrefs,
421 DT_int,
422 DT_nmtoken,
423 DT_nmtokens,
424 DT_notation,
425 DT_number,
426 DT_r4,
427 DT_r8,
428 DT_string,
429 DT_time,
430 DT_time_tz,
431 DT_ui1,
432 DT_ui2,
433 DT_ui4,
434 DT_ui8,
435 DT_uri,
436 DT_uuid
439 static const WCHAR *const DT_wstring_table[LAST_DT] =
441 wDT_bin_base64,
442 wDT_bin_hex,
443 wDT_boolean,
444 wDT_char,
445 wDT_date,
446 wDT_date_tz,
447 wDT_dateTime,
448 wDT_dateTime_tz,
449 wDT_entity,
450 wDT_entities,
451 wDT_enumeration,
452 wDT_fixed_14_4,
453 wDT_float,
454 wDT_i1,
455 wDT_i2,
456 wDT_i4,
457 wDT_i8,
458 wDT_id,
459 wDT_idref,
460 wDT_idrefs,
461 wDT_int,
462 wDT_nmtoken,
463 wDT_nmtokens,
464 wDT_notation,
465 wDT_number,
466 wDT_r4,
467 wDT_r8,
468 wDT_string,
469 wDT_time,
470 wDT_time_tz,
471 wDT_ui1,
472 wDT_ui2,
473 wDT_ui4,
474 wDT_ui8,
475 wDT_uri,
476 wDT_uuid
479 static const XDR_DT DT_lookup_table[] =
481 -1, -1,
482 DT_I8,
483 DT_UI8,
484 DT_TIME,
485 -1, -1,
486 DT_I4,
487 DT_UI4,
488 -1, -1, -1,
489 DT_R8,
490 DT_URI,
492 DT_FLOAT,
494 DT_R4,
495 DT_INT,
496 DT_CHAR,
498 DT_ENTITY,
499 DT_ID,
500 DT_ENTITIES,
501 DT_UUID,
502 -1, -1,
503 DT_TIME_TZ,
505 DT_DATE,
507 DT_NUMBER,
508 DT_BIN_HEX,
509 DT_DATETIME,
511 DT_IDREF,
512 DT_IDREFS,
513 DT_BOOLEAN,
514 -1, -1, -1,
515 DT_STRING,
516 DT_NMTOKEN,
517 DT_NMTOKENS,
519 DT_BIN_BASE64,
521 DT_I2,
522 DT_UI2,
523 -1, -1, -1,
524 DT_DATE_TZ,
525 DT_NOTATION,
526 -1, -1,
527 DT_DATETIME_TZ,
528 DT_I1,
529 DT_UI1,
530 -1, -1,
531 DT_ENUMERATION,
532 -1, -1, -1, -1, -1, -1, -1, -1, -1,
533 -1, -1, -1, -1, -1, -1, -1, -1, -1,
534 -1, -1, -1, -1, -1, -1, -1, -1, -1,
535 -1, -1, -1, -1, -1, -1, -1, -1, -1,
536 -1, -1, -1, -1, -1, -1, -1, -1, -1,
537 -1, -1, -1, -1, -1, -1, -1, -1,
538 DT_FIXED_14_4
541 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
543 DWORD hash = dt_hash(str, len);
544 XDR_DT dt = DT_INVALID;
546 if (hash <= DT_MAX_HASH_VALUE)
547 dt = DT_lookup_table[hash];
549 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
550 return dt;
552 return DT_INVALID;
555 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
557 DWORD hash = dt_hash_bstr(bstr, len);
558 XDR_DT dt = DT_INVALID;
560 if (hash <= DT_MAX_HASH_VALUE)
561 dt = DT_lookup_table[hash];
563 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
564 return dt;
566 return DT_INVALID;
569 xmlChar const* dt_to_str(XDR_DT dt)
571 if (dt == DT_INVALID)
572 return NULL;
574 return DT_string_table[dt];
577 OLECHAR const* dt_to_bstr(XDR_DT dt)
579 if (dt == DT_INVALID)
580 return NULL;
582 return DT_wstring_table[dt];
585 const char* debugstr_dt(XDR_DT dt)
587 return debugstr_a(dt != DT_INVALID ? (const char*)DT_string_table[dt] : NULL);
590 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
592 xmlDocPtr tmp_doc;
593 xmlNodePtr node;
594 xmlNsPtr ns;
595 HRESULT hr;
597 TRACE("(dt:%s, %s)\n", debugstr_dt(dt), debugstr_a((char const*)content));
599 if (!datatypes_schema)
601 xmlSchemaParserCtxtPtr spctx;
602 assert(datatypes_src != NULL);
603 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
604 datatypes_schema = Schema_parse(spctx);
605 xmlSchemaFreeParserCtxt(spctx);
608 switch (dt)
610 case DT_INVALID:
611 return E_FAIL;
612 case DT_BIN_BASE64:
613 case DT_BIN_HEX:
614 case DT_BOOLEAN:
615 case DT_CHAR:
616 case DT_DATE:
617 case DT_DATE_TZ:
618 case DT_DATETIME:
619 case DT_DATETIME_TZ:
620 case DT_FIXED_14_4:
621 case DT_FLOAT:
622 case DT_I1:
623 case DT_I2:
624 case DT_I4:
625 case DT_I8:
626 case DT_INT:
627 case DT_NMTOKEN:
628 case DT_NMTOKENS:
629 case DT_NUMBER:
630 case DT_R4:
631 case DT_R8:
632 case DT_STRING:
633 case DT_TIME:
634 case DT_TIME_TZ:
635 case DT_UI1:
636 case DT_UI2:
637 case DT_UI4:
638 case DT_UI8:
639 case DT_URI:
640 case DT_UUID:
641 if (!datatypes_schema)
643 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
644 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
646 /* Hopefully they don't need much in the way of XDR datatypes support... */
647 return S_OK;
650 if (content && xmlStrlen(content))
652 tmp_doc = xmlNewDoc(NULL);
653 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
654 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
655 xmlSetNs(node, ns);
656 xmlDocSetRootElement(tmp_doc, node);
658 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
659 xmlFreeDoc(tmp_doc);
661 else
662 { /* probably the node is being created manually and has no content yet */
663 hr = S_OK;
665 return hr;
666 default:
667 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
668 return S_OK;
672 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
674 return (node->ns != NULL)? node->ns->href : NULL;
677 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
679 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
680 xmlHashLookup(This->cache, nsURI);
683 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
685 cache_entry* entry = get_entry(This, get_node_nsURI(node));
686 return (!entry)? NULL : entry->schema;
689 static xmlExternalEntityLoader _external_entity_loader;
691 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
692 xmlParserCtxtPtr ctxt)
694 xmlParserInputPtr input;
696 TRACE("(%s %s %p)\n", debugstr_a(URL), debugstr_a(ID), ctxt);
698 assert(MSXML_hInstance != NULL);
699 assert(datatypes_rsrc != NULL);
700 assert(datatypes_handle != NULL);
701 assert(datatypes_src != NULL);
703 /* TODO: if the desired schema is in the cache, load it from there */
704 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
706 TRACE("loading built-in schema for %s\n", URL);
707 input = xmlNewStringInputStream(ctxt, datatypes_src);
709 else
711 input = _external_entity_loader(URL, ID, ctxt);
714 return input;
717 void schemasInit(void)
719 xmlChar* buf;
720 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
722 FIXME("failed to find resource for %s\n", DT_nsURI);
723 return;
726 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
728 FIXME("failed to load resource for %s\n", DT_nsURI);
729 return;
731 buf = LockResource(datatypes_handle);
732 datatypes_len = SizeofResource(MSXML_hInstance, datatypes_rsrc);
734 /* Resource is loaded as raw data,
735 * need a null-terminated string */
736 while (buf[datatypes_len - 1] != '>') datatypes_len--;
737 datatypes_src = heap_alloc(datatypes_len + 1);
738 memcpy(datatypes_src, buf, datatypes_len);
739 datatypes_src[datatypes_len] = 0;
741 if (xmlGetExternalEntityLoader() != external_entity_loader)
743 _external_entity_loader = xmlGetExternalEntityLoader();
744 xmlSetExternalEntityLoader(external_entity_loader);
748 void schemasCleanup(void)
750 xmlSchemaFree(datatypes_schema);
751 heap_free(datatypes_src);
752 xmlSetExternalEntityLoader(_external_entity_loader);
755 static LONG cache_entry_add_ref(cache_entry* entry)
757 LONG ref = InterlockedIncrement(&entry->ref);
758 TRACE("%p, refcount %ld.\n", entry, ref);
759 return ref;
762 static LONG cache_entry_release(cache_entry* entry)
764 LONG ref = InterlockedDecrement(&entry->ref);
765 TRACE("%p, refcount %ld.\n", entry, ref);
767 if (ref == 0)
769 if (entry->type == CacheEntryType_XSD)
771 xmldoc_release(entry->doc);
772 entry->schema->doc = NULL;
773 xmlSchemaFree(entry->schema);
775 else if (entry->type == CacheEntryType_XDR)
777 xmldoc_release(entry->doc);
778 xmldoc_release(entry->schema->doc);
779 entry->schema->doc = NULL;
780 xmlSchemaFree(entry->schema);
783 heap_free(entry);
785 return ref;
788 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl;
790 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
792 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
795 static inline schema_cache* impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection* iface)
797 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
800 static inline schema_cache* unsafe_impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection *iface)
802 return iface->lpVtbl == (void*)&XMLDOMSchemaCollection2Vtbl ? impl_from_IXMLDOMSchemaCollection(iface) : NULL;
805 static inline CacheEntryType cache_type_from_xmlDocPtr(xmlDocPtr schema)
807 xmlNodePtr root = NULL;
808 if (schema)
809 root = xmlDocGetRootElement(schema);
810 if (root && root->ns)
813 if (xmlStrEqual(root->name, XDR_schema) &&
814 xmlStrEqual(root->ns->href, XDR_nsURI))
816 return CacheEntryType_XDR;
818 else if (xmlStrEqual(root->name, XSD_schema) &&
819 xmlStrEqual(root->ns->href, XSD_nsURI))
821 return CacheEntryType_XSD;
824 return CacheEntryType_Invalid;
827 static BOOL link_datatypes(xmlDocPtr schema)
829 xmlNodePtr root, next, child;
830 xmlNsPtr ns;
832 assert(xmlGetExternalEntityLoader() == external_entity_loader);
833 root = xmlDocGetRootElement(schema);
834 if (!root)
835 return FALSE;
837 for (ns = root->nsDef; ns != NULL; ns = ns->next)
839 if (xmlStrEqual(ns->href, DT_nsURI))
840 break;
843 if (!ns)
844 return FALSE;
846 next = xmlFirstElementChild(root);
847 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
848 if (next) child = xmlAddPrevSibling(next, child);
849 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
850 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
852 return TRUE;
855 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
857 cache_entry* entry = heap_alloc(sizeof(cache_entry));
858 xmlSchemaParserCtxtPtr spctx;
859 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
861 link_datatypes(new_doc);
863 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
864 * do we need to do something special here? */
865 entry->type = CacheEntryType_XSD;
866 entry->ref = 0;
867 spctx = xmlSchemaNewDocParserCtxt(new_doc);
869 if ((entry->schema = Schema_parse(spctx)))
871 xmldoc_init(entry->schema->doc, v);
872 entry->doc = entry->schema->doc;
873 xmldoc_add_ref(entry->doc);
875 else
877 FIXME("failed to parse doc\n");
878 xmlFreeDoc(new_doc);
879 heap_free(entry);
880 entry = NULL;
882 xmlSchemaFreeParserCtxt(spctx);
883 return entry;
886 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
888 cache_entry* entry = heap_alloc(sizeof(cache_entry));
889 xmlSchemaParserCtxtPtr spctx;
890 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
892 link_datatypes(xsd_doc);
894 entry->type = CacheEntryType_XDR;
895 entry->ref = 0;
896 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
898 if ((entry->schema = Schema_parse(spctx)))
900 entry->doc = new_doc;
901 xmldoc_init(entry->schema->doc, version);
902 xmldoc_init(entry->doc, version);
903 xmldoc_add_ref(entry->doc);
904 xmldoc_add_ref(entry->schema->doc);
906 else
908 FIXME("failed to parse doc\n");
909 xmlFreeDoc(new_doc);
910 xmlFreeDoc(xsd_doc);
911 heap_free(entry);
912 entry = NULL;
914 xmlSchemaFreeParserCtxt(spctx);
916 return entry;
919 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
921 cache_entry* entry;
922 IXMLDOMDocument3* domdoc = NULL;
923 xmlDocPtr doc = NULL;
924 HRESULT hr = dom_document_create(version, (void **)&domdoc);
925 VARIANT_BOOL b = VARIANT_FALSE;
926 CacheEntryType type = CacheEntryType_Invalid;
928 if (hr != S_OK)
930 FIXME("failed to create domdoc\n");
931 return NULL;
933 assert(domdoc != NULL);
934 assert(V_VT(&url) == VT_BSTR);
936 hr = IXMLDOMDocument3_load(domdoc, url, &b);
937 if (hr != S_OK)
939 ERR("load() returned %#lx.\n", hr);
940 if (b != VARIANT_TRUE)
942 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url)));
943 IXMLDOMDocument3_Release(domdoc);
944 return NULL;
947 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
948 type = cache_type_from_xmlDocPtr(doc);
950 switch (type)
952 case CacheEntryType_XSD:
953 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
954 break;
955 case CacheEntryType_XDR:
956 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
957 break;
958 default:
959 entry = NULL;
960 FIXME("invalid schema\n");
961 break;
963 IXMLDOMDocument3_Release(domdoc);
965 return entry;
968 static void cache_free(void* data, const xmlChar* name /* ignored */)
970 cache_entry_release((cache_entry*)data);
973 /* returns index or -1 if not found */
974 static int cache_free_uri(schema_cache *cache, const xmlChar *uri)
976 int i;
978 for (i = 0; i < cache->count; i++)
979 if (xmlStrEqual(cache->uris[i], uri))
981 heap_free(cache->uris[i]);
982 return i;
985 return -1;
988 static void cache_add_entry(schema_cache *cache, const xmlChar *uri, cache_entry *entry)
990 int i;
992 /* meaning no entry found with this name */
993 if (xmlHashRemoveEntry(cache->cache, uri, cache_free))
995 if (cache->count == cache->allocated)
997 cache->allocated *= 2;
998 cache->uris = heap_realloc(cache->uris, cache->allocated*sizeof(xmlChar*));
1000 i = cache->count++;
1002 else
1003 i = cache_free_uri(cache, uri);
1005 cache->uris[i] = heap_strdupxmlChar(uri);
1006 xmlHashAddEntry(cache->cache, uri, entry);
1009 static void cache_remove_entry(schema_cache *cache, const xmlChar *uri)
1011 /* adjust index if entry was really removed */
1012 if (xmlHashRemoveEntry(cache->cache, uri, cache_free) == 0)
1014 int i = cache_free_uri(cache, uri);
1015 if (i == -1) return;
1016 /* shift array */
1017 if (i != --cache->count)
1018 memmove(&cache->uris[i], &cache->uris[i+1], (cache->count-i)*sizeof(xmlChar*));
1022 /* This one adds all namespaces defined in document to a cache, without anything
1023 associated with uri obviously.
1024 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
1025 it uses additional node type to describe namespace definition attribute while
1026 in msxml it's expected to be a normal attribute - as a workaround document is
1027 queried at libxml2 level here. */
1028 HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node)
1030 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1031 static const xmlChar query[] = "//*/namespace::*";
1032 xmlXPathObjectPtr nodeset;
1033 xmlXPathContextPtr ctxt;
1035 This->read_only = 1;
1037 ctxt = xmlXPathNewContext(node->node->doc);
1039 nodeset = xmlXPathEvalExpression(query, ctxt);
1040 xmlXPathFreeContext(ctxt);
1042 if (nodeset)
1044 int pos = 0, len = xmlXPathNodeSetGetLength(nodeset->nodesetval);
1046 while (pos < len)
1048 xmlNodePtr node = xmlXPathNodeSetItem(nodeset->nodesetval, pos);
1049 if (node->type == XML_NAMESPACE_DECL)
1051 static const xmlChar defns[] = "http://www.w3.org/XML/1998/namespace";
1052 xmlNsPtr ns = (xmlNsPtr)node;
1053 cache_entry *entry;
1055 /* filter out default uri */
1056 if (xmlStrEqual(ns->href, defns))
1058 pos++;
1059 continue;
1062 entry = heap_alloc(sizeof(cache_entry));
1063 entry->type = CacheEntryType_NS;
1064 entry->ref = 1;
1065 entry->schema = NULL;
1066 entry->doc = NULL;
1068 cache_add_entry(This, ns->href, entry);
1070 pos++;
1073 xmlXPathFreeObject(nodeset);
1076 return S_OK;
1079 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
1080 REFIID riid, void** ppvObject)
1082 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1084 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1086 if ( IsEqualIID(riid, &IID_IUnknown) ||
1087 IsEqualIID(riid, &IID_IDispatch) ||
1088 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
1089 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
1091 *ppvObject = iface;
1093 else if(This->version == MSXML6 && IsEqualIID(riid, &CLSID_XMLSchemaCache60))
1096 * Version 6 can be queried for an interface with IID equal to CLSID.
1097 * There is no public interface with that IID and returned pointer
1098 * is equal to returned IXMLDOMSchemaCollection2 iface. We assume
1099 * that it's just another way for querying IXMLDOMSchemaCollection2
1100 * interface. Office 2013 ClickToRun installer uses this.
1102 WARN("riid CLSID_XMLSchemaCache60, returning IXMLDOMSchemaCollection2 interface.\n");
1103 *ppvObject = iface;
1105 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
1107 return *ppvObject ? S_OK : E_NOINTERFACE;
1109 else if(IsEqualGUID( riid, &IID_ISupportErrorInfo ))
1111 return node_create_supporterrorinfo(schema_cache_se_tids, ppvObject);
1113 else
1115 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1116 *ppvObject = NULL;
1117 return E_NOINTERFACE;
1120 IXMLDOMSchemaCollection2_AddRef(iface);
1122 return S_OK;
1125 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
1127 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1128 LONG ref = InterlockedIncrement(&This->ref);
1129 TRACE("%p, refcount %ld.\n", iface, ref);
1130 return ref;
1133 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
1135 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1136 LONG ref = InterlockedDecrement(&This->ref);
1137 TRACE("%p, refcount %ld.\n", iface, ref);
1139 if (!ref)
1141 int i;
1143 for (i = 0; i < This->count; i++)
1144 heap_free(This->uris[i]);
1145 heap_free(This->uris);
1146 xmlHashFree(This->cache, cache_free);
1147 heap_free(This);
1150 return ref;
1153 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1154 UINT* pctinfo)
1156 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1157 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1160 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1161 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1163 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1164 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
1165 iTInfo, lcid, ppTInfo);
1168 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1169 REFIID riid, LPOLESTR* rgszNames,
1170 UINT cNames, LCID lcid, DISPID* rgDispId)
1172 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1173 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1174 riid, rgszNames, cNames, lcid, rgDispId);
1177 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1178 DISPID dispIdMember, REFIID riid, LCID lcid,
1179 WORD wFlags, DISPPARAMS* pDispParams,
1180 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1181 UINT* puArgErr)
1183 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1184 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1185 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1188 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1190 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1191 xmlChar* name;
1193 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1195 if (This->read_only) return E_FAIL;
1197 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1199 switch (V_VT(&var))
1201 case VT_NULL:
1203 cache_remove_entry(This, name);
1205 break;
1207 case VT_BSTR:
1209 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1211 if (entry)
1213 cache_entry_add_ref(entry);
1215 else
1217 heap_free(name);
1218 return E_FAIL;
1221 cache_add_entry(This, name, entry);
1223 break;
1225 case VT_DISPATCH:
1226 case VT_UNKNOWN:
1228 xmlDocPtr doc = NULL;
1229 cache_entry* entry;
1230 CacheEntryType type;
1231 IXMLDOMNode* domnode = NULL;
1232 IUnknown_QueryInterface(V_UNKNOWN(&var), &IID_IXMLDOMNode, (void**)&domnode);
1234 if (domnode)
1236 DOMNodeType type;
1238 IXMLDOMNode_get_nodeType(domnode, &type);
1239 switch (type)
1241 case NODE_ELEMENT:
1243 IXMLDOMDocument *domdoc;
1244 VARIANT_BOOL b;
1245 BSTR xml;
1247 IXMLDOMNode_get_xml(domnode, &xml);
1248 dom_document_create(This->version, (void **)&domdoc);
1249 IXMLDOMDocument_loadXML(domdoc, xml, &b);
1250 SysFreeString(xml);
1251 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
1252 break;
1254 default:
1255 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1256 break;
1260 if (!doc)
1262 IXMLDOMNode_Release(domnode);
1263 heap_free(name);
1264 return E_INVALIDARG;
1266 type = cache_type_from_xmlDocPtr(doc);
1268 if (type == CacheEntryType_XSD)
1270 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1272 else if (type == CacheEntryType_XDR)
1274 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1276 else
1278 WARN("invalid schema!\n");
1279 entry = NULL;
1282 IXMLDOMNode_Release(domnode);
1284 if (entry)
1286 cache_entry_add_ref(entry);
1288 else
1290 heap_free(name);
1291 return E_FAIL;
1294 cache_add_entry(This, name, entry);
1296 break;
1298 default:
1299 FIXME("arg type is not supported, %s\n", debugstr_variant(&var));
1300 heap_free(name);
1301 return E_INVALIDARG;
1303 heap_free(name);
1304 return S_OK;
1307 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1308 IXMLDOMNode** node)
1310 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1311 cache_entry* entry;
1312 xmlChar* name;
1314 TRACE("(%p)->(%s %p)\n", This, debugstr_w(uri), node);
1316 if (This->version == MSXML6)
1318 if (node) *node = NULL;
1319 return E_NOTIMPL;
1322 if (!node)
1323 return E_POINTER;
1325 *node = NULL;
1327 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1328 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1329 heap_free(name);
1331 /* TODO: this should be read-only */
1332 if (entry && entry->doc)
1333 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1335 return S_OK;
1338 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1340 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1341 xmlChar* name;
1343 TRACE("(%p)->(%s)\n", This, debugstr_w(uri));
1345 if (This->version == MSXML6) return E_NOTIMPL;
1347 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1348 cache_remove_entry(This, name);
1349 heap_free(name);
1350 return S_OK;
1353 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1355 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1356 TRACE("(%p)->(%p)\n", This, length);
1358 if (!length)
1359 return E_POINTER;
1361 *length = This->count;
1362 return S_OK;
1365 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1366 LONG index, BSTR* uri)
1368 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1370 TRACE("%p, %ld, %p.\n", iface, index, uri);
1372 if (!uri)
1373 return E_POINTER;
1375 if (This->version == MSXML6)
1376 *uri = NULL;
1378 if (index >= This->count)
1379 return E_FAIL;
1381 *uri = bstr_from_xmlChar(This->uris[index]);
1382 return S_OK;
1385 static void cache_copy(void* data, void* dest, const xmlChar* name)
1387 schema_cache* This = (schema_cache*) dest;
1388 cache_entry* entry = (cache_entry*) data;
1390 if (xmlHashLookup(This->cache, name) == NULL)
1392 cache_entry_add_ref(entry);
1393 cache_add_entry(This, name, entry);
1397 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1398 IXMLDOMSchemaCollection* collection)
1400 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1401 schema_cache* That;
1403 TRACE("(%p)->(%p)\n", This, collection);
1405 if (!collection)
1406 return E_POINTER;
1408 That = unsafe_impl_from_IXMLDOMSchemaCollection(collection);
1409 if (!That)
1411 ERR("external collection implementation\n");
1412 return E_FAIL;
1415 /* TODO: detect errors while copying & return E_FAIL */
1416 xmlHashScan(That->cache, cache_copy, This);
1418 return S_OK;
1421 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface, IUnknown** enumv)
1423 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1424 TRACE("(%p)->(%p)\n", This, enumv);
1425 return create_enumvariant((IUnknown*)iface, TRUE, &schemacache_enumvariant, (IEnumVARIANT**)enumv);
1428 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1430 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1431 FIXME("(%p): stub\n", This);
1432 return E_NOTIMPL;
1435 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1436 VARIANT_BOOL value)
1438 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1439 FIXME("(%p)->(%d): stub\n", This, value);
1441 This->validateOnLoad = value;
1442 /* it's ok to disable it, cause we don't validate on load anyway */
1443 if (value == VARIANT_FALSE) return S_OK;
1445 return E_NOTIMPL;
1448 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1449 VARIANT_BOOL* value)
1451 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1452 TRACE("(%p)->(%p)\n", This, value);
1454 if (!value) return E_POINTER;
1455 *value = This->validateOnLoad;
1457 return S_OK;
1460 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1461 BSTR namespaceURI, ISchema** schema)
1463 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1464 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1465 if (schema)
1466 *schema = NULL;
1467 return E_NOTIMPL;
1470 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1471 IXMLDOMNode* node, ISchemaItem** item)
1473 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1474 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1475 if (item)
1476 *item = NULL;
1477 return E_NOTIMPL;
1480 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl =
1482 schema_cache_QueryInterface,
1483 schema_cache_AddRef,
1484 schema_cache_Release,
1485 schema_cache_GetTypeInfoCount,
1486 schema_cache_GetTypeInfo,
1487 schema_cache_GetIDsOfNames,
1488 schema_cache_Invoke,
1489 schema_cache_add,
1490 schema_cache_get,
1491 schema_cache_remove,
1492 schema_cache_get_length,
1493 schema_cache_get_namespaceURI,
1494 schema_cache_addCollection,
1495 schema_cache_get__newEnum,
1496 schema_cache_validate,
1497 schema_cache_put_validateOnLoad,
1498 schema_cache_get_validateOnLoad,
1499 schema_cache_getSchema,
1500 schema_cache_getDeclaration
1503 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1505 xmlSchemaElementPtr decl = NULL;
1506 xmlChar const* nsURI = get_node_nsURI(node);
1508 TRACE("(%p, %p)\n", schema, node);
1510 if (xmlStrEqual(nsURI, schema->targetNamespace))
1511 decl = xmlHashLookup(schema->elemDecl, node->name);
1513 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1515 FIXME("declaration not found in main schema - need to check schema imports!\n");
1516 /*xmlSchemaImportPtr import;
1517 if (nsURI == NULL)
1518 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1519 else
1520 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1522 if (import != NULL)
1523 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1526 return decl;
1529 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1531 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1532 while (decl != NULL && decl->refDecl != NULL)
1533 decl = decl->refDecl;
1534 return (decl != NULL)? decl->node : NULL;
1537 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1539 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1540 xmlSchemaPtr schema;
1542 TRACE("(%p, %p)\n", This, tree);
1544 if (!tree)
1545 return E_POINTER;
1547 if (tree->type == XML_DOCUMENT_NODE)
1548 tree = xmlDocGetRootElement(tree->doc);
1550 schema = get_node_schema(This, tree);
1551 /* TODO: if the ns is not in the cache, and it's a URL,
1552 * do we try to load from that? */
1553 if (schema)
1554 return Schema_validate_tree(schema, tree);
1555 else
1556 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1558 return E_FAIL;
1561 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1563 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1564 xmlSchemaPtr schema = get_node_schema(This, node);
1565 XDR_DT dt = DT_INVALID;
1567 TRACE("(%p, %p)\n", This, node);
1569 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1571 dt = str_to_dt(node->name, -1);
1573 else if (schema)
1575 xmlChar* str;
1576 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1578 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1579 if (str)
1581 dt = str_to_dt(str, -1);
1582 xmlFree(str);
1586 return dt;
1589 static const tid_t schemacache_iface_tids[] = {
1590 IXMLDOMSchemaCollection2_tid,
1594 static dispex_static_data_t schemacache_dispex = {
1595 NULL,
1596 IXMLDOMSchemaCollection2_tid,
1597 NULL,
1598 schemacache_iface_tids
1601 HRESULT SchemaCache_create(MSXML_VERSION version, void** obj)
1603 schema_cache* This = heap_alloc(sizeof(schema_cache));
1604 if (!This)
1605 return E_OUTOFMEMORY;
1607 TRACE("(%d %p)\n", version, obj);
1609 This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl;
1610 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1611 This->allocated = 10;
1612 This->count = 0;
1613 This->uris = heap_alloc(This->allocated*sizeof(xmlChar*));
1614 This->ref = 1;
1615 This->version = version;
1616 This->validateOnLoad = VARIANT_TRUE;
1617 This->read_only = 0;
1618 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSchemaCollection2_iface, &schemacache_dispex);
1620 *obj = &This->IXMLDOMSchemaCollection2_iface;
1621 return S_OK;