ntdll/tests: Wait for async I/O to complete when the result is STATUS_PENDING.
[wine.git] / dlls / msxml3 / schema.c
blob8f2acb441bc0b3db614f9095dacffd450fdf089d
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 #endif
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winuser.h"
43 #include "ole2.h"
44 #include "msxml6.h"
46 #include "wine/debug.h"
48 #include "msxml_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
52 /* We use a chained hashtable, which can hold any number of schemas
53 * TODO: grow/shrink hashtable depending on load factor
54 * TODO: implement read-only where appropriate
57 /* This is just the number of buckets, should be prime */
58 #define DEFAULT_HASHTABLE_SIZE 17
60 #ifdef HAVE_LIBXML2
62 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI);
64 static const xmlChar XSD_schema[] = "schema";
65 static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
66 static const xmlChar XDR_schema[] = "Schema";
67 static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
68 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
70 static xmlChar const* datatypes_src;
71 static int datatypes_len;
72 static HGLOBAL datatypes_handle;
73 static HRSRC datatypes_rsrc;
74 static xmlSchemaPtr datatypes_schema;
76 static const WCHAR emptyW[] = {0};
78 /* Supported Types:
79 * msxml3 - XDR only
80 * msxml4 - XDR & XSD
81 * msxml5 - XDR & XSD
82 * mxsml6 - XSD only
84 typedef enum _SCHEMA_TYPE {
85 SCHEMA_TYPE_INVALID,
86 SCHEMA_TYPE_XDR,
87 SCHEMA_TYPE_XSD
88 } SCHEMA_TYPE;
90 typedef struct _schema_cache
92 const struct IXMLDOMSchemaCollection2Vtbl* lpVtbl;
93 MSXML_VERSION version;
94 xmlHashTablePtr cache;
95 LONG ref;
96 } schema_cache;
98 typedef struct _cache_entry
100 SCHEMA_TYPE type;
101 xmlSchemaPtr schema;
102 xmlDocPtr doc;
103 LONG ref;
104 } cache_entry;
106 typedef struct _cache_index_data
108 LONG index;
109 BSTR* out;
110 } cache_index_data;
112 /* datatypes lookup stuff
113 * generated with help from gperf */
114 #define DT_MIN_STR_LEN 2
115 #define DT_MAX_STR_LEN 11
116 #define DT_MIN_HASH_VALUE 2
117 #define DT_MAX_HASH_VALUE 115
119 static const xmlChar DT_bin_base64[] = "bin.base64";
120 static const xmlChar DT_bin_hex[] = "bin.hex";
121 static const xmlChar DT_boolean[] = "boolean";
122 static const xmlChar DT_char[] = "char";
123 static const xmlChar DT_date[] = "date";
124 static const xmlChar DT_date_tz[] = "date.tz";
125 static const xmlChar DT_dateTime[] = "dateTime";
126 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
127 static const xmlChar DT_entity[] = "entity";
128 static const xmlChar DT_entities[] = "entities";
129 static const xmlChar DT_enumeration[] = "enumeration";
130 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
131 static const xmlChar DT_float[] = "float";
132 static const xmlChar DT_i1[] = "i1";
133 static const xmlChar DT_i2[] = "i2";
134 static const xmlChar DT_i4[] = "i4";
135 static const xmlChar DT_i8[] = "i8";
136 static const xmlChar DT_id[] = "id";
137 static const xmlChar DT_idref[] = "idref";
138 static const xmlChar DT_idrefs[] = "idrefs";
139 static const xmlChar DT_int[] = "int";
140 static const xmlChar DT_nmtoken[] = "nmtoken";
141 static const xmlChar DT_nmtokens[] = "nmtokens";
142 static const xmlChar DT_notation[] = "notation";
143 static const xmlChar DT_number[] = "number";
144 static const xmlChar DT_r4[] = "r4";
145 static const xmlChar DT_r8[] = "r8";
146 static const xmlChar DT_string[] = "string";
147 static const xmlChar DT_time[] = "time";
148 static const xmlChar DT_time_tz[] = "time.tz";
149 static const xmlChar DT_ui1[] = "ui1";
150 static const xmlChar DT_ui2[] = "ui2";
151 static const xmlChar DT_ui4[] = "ui4";
152 static const xmlChar DT_ui8[] = "ui8";
153 static const xmlChar DT_uri[] = "uri";
154 static const xmlChar DT_uuid[] = "uuid";
156 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
157 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
158 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
159 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
160 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
161 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
162 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
163 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
164 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
165 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
166 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
167 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
168 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
169 static const OLECHAR wDT_i1[] = {'i','1',0};
170 static const OLECHAR wDT_i2[] = {'i','2',0};
171 static const OLECHAR wDT_i4[] = {'i','4',0};
172 static const OLECHAR wDT_i8[] = {'i','8',0};
173 static const OLECHAR wDT_id[] = {'i','d',0};
174 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
175 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
176 static const OLECHAR wDT_int[] = {'i','n','t',0};
177 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
178 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
179 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
180 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
181 static const OLECHAR wDT_r4[] = {'r','4',0};
182 static const OLECHAR wDT_r8[] = {'r','8',0};
183 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
184 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
185 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
186 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
187 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
188 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
189 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
190 static const OLECHAR wDT_uri[] = {'u','r','i',0};
191 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
193 static const BYTE hash_assoc_values[] =
195 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
196 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
197 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
198 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
199 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
200 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
201 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
202 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
203 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
204 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
205 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
206 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
207 0, 0, 10, 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, 116, 116, 116, 116,
210 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
211 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
212 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
213 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
214 116, 116, 116, 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
223 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
225 va_list ap;
226 va_start(ap, msg);
227 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
228 va_end(ap);
231 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
233 va_list ap;
234 va_start(ap, msg);
235 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
236 va_end(ap);
239 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
240 static void parser_serror(void* ctx, xmlErrorPtr err)
242 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
244 #endif
246 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
248 TRACE("(%p)\n", spctx);
250 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
251 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
252 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
253 #endif
255 return xmlSchemaParse(spctx);
258 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
260 va_list ap;
261 va_start(ap, msg);
262 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
263 va_end(ap);
266 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
268 va_list ap;
269 va_start(ap, msg);
270 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
271 va_end(ap);
274 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
275 static void validate_serror(void* ctx, xmlErrorPtr err)
277 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
279 #endif
281 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
283 xmlSchemaValidCtxtPtr svctx;
284 int err;
286 TRACE("(%p, %p)\n", schema, tree);
287 /* TODO: if validateOnLoad property is false,
288 * we probably need to validate the schema here. */
289 svctx = xmlSchemaNewValidCtxt(schema);
290 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
291 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
292 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
293 #endif
295 if (tree->type == XML_DOCUMENT_NODE)
296 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
297 else
298 err = xmlSchemaValidateOneElement(svctx, tree);
300 xmlSchemaFreeValidCtxt(svctx);
301 return err? S_FALSE : S_OK;
304 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
306 DWORD hval = (len == -1)? xmlStrlen(str) : len;
308 switch (hval)
310 default:
311 hval += hash_assoc_values[str[10]];
312 /*FALLTHROUGH*/
313 case 10:
314 hval += hash_assoc_values[str[9]];
315 /*FALLTHROUGH*/
316 case 9:
317 hval += hash_assoc_values[str[8]];
318 /*FALLTHROUGH*/
319 case 8:
320 hval += hash_assoc_values[str[7]];
321 /*FALLTHROUGH*/
322 case 7:
323 hval += hash_assoc_values[str[6]];
324 /*FALLTHROUGH*/
325 case 6:
326 hval += hash_assoc_values[str[5]];
327 /*FALLTHROUGH*/
328 case 5:
329 hval += hash_assoc_values[str[4]];
330 /*FALLTHROUGH*/
331 case 4:
332 hval += hash_assoc_values[str[3]];
333 /*FALLTHROUGH*/
334 case 3:
335 hval += hash_assoc_values[str[2]];
336 /*FALLTHROUGH*/
337 case 2:
338 hval += hash_assoc_values[str[1]];
339 /*FALLTHROUGH*/
340 case 1:
341 hval += hash_assoc_values[str[0]];
342 break;
344 return hval;
347 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
349 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
351 switch (hval)
353 default:
354 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
355 /*FALLTHROUGH*/
356 case 10:
357 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
358 /*FALLTHROUGH*/
359 case 9:
360 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
361 /*FALLTHROUGH*/
362 case 8:
363 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
364 /*FALLTHROUGH*/
365 case 7:
366 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
367 /*FALLTHROUGH*/
368 case 6:
369 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
370 /*FALLTHROUGH*/
371 case 5:
372 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
373 /*FALLTHROUGH*/
374 case 4:
375 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
376 /*FALLTHROUGH*/
377 case 3:
378 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
379 /*FALLTHROUGH*/
380 case 2:
381 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
382 /*FALLTHROUGH*/
383 case 1:
384 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
385 break;
387 return hval;
390 static const xmlChar *const DT_string_table[DT__N_TYPES] =
392 DT_bin_base64,
393 DT_bin_hex,
394 DT_boolean,
395 DT_char,
396 DT_date,
397 DT_date_tz,
398 DT_dateTime,
399 DT_dateTime_tz,
400 DT_entity,
401 DT_entities,
402 DT_enumeration,
403 DT_fixed_14_4,
404 DT_float,
405 DT_i1,
406 DT_i2,
407 DT_i4,
408 DT_i8,
409 DT_id,
410 DT_idref,
411 DT_idrefs,
412 DT_int,
413 DT_nmtoken,
414 DT_nmtokens,
415 DT_notation,
416 DT_number,
417 DT_r4,
418 DT_r8,
419 DT_string,
420 DT_time,
421 DT_time_tz,
422 DT_ui1,
423 DT_ui2,
424 DT_ui4,
425 DT_ui8,
426 DT_uri,
427 DT_uuid
430 static const WCHAR *const DT_wstring_table[DT__N_TYPES] =
432 wDT_bin_base64,
433 wDT_bin_hex,
434 wDT_boolean,
435 wDT_char,
436 wDT_date,
437 wDT_date_tz,
438 wDT_dateTime,
439 wDT_dateTime_tz,
440 wDT_entity,
441 wDT_entities,
442 wDT_enumeration,
443 wDT_fixed_14_4,
444 wDT_float,
445 wDT_i1,
446 wDT_i2,
447 wDT_i4,
448 wDT_i8,
449 wDT_id,
450 wDT_idref,
451 wDT_idrefs,
452 wDT_int,
453 wDT_nmtoken,
454 wDT_nmtokens,
455 wDT_notation,
456 wDT_number,
457 wDT_r4,
458 wDT_r8,
459 wDT_string,
460 wDT_time,
461 wDT_time_tz,
462 wDT_ui1,
463 wDT_ui2,
464 wDT_ui4,
465 wDT_ui8,
466 wDT_uri,
467 wDT_uuid
470 static const XDR_DT DT_lookup_table[] =
472 -1, -1,
473 DT_I8,
474 DT_UI8,
475 DT_TIME,
476 -1, -1,
477 DT_I4,
478 DT_UI4,
479 -1, -1, -1,
480 DT_R8,
481 DT_URI,
483 DT_FLOAT,
485 DT_R4,
486 DT_INT,
487 DT_CHAR,
489 DT_ENTITY,
490 DT_ID,
491 DT_ENTITIES,
492 DT_UUID,
493 -1, -1,
494 DT_TIME_TZ,
496 DT_DATE,
498 DT_NUMBER,
499 DT_BIN_HEX,
500 DT_DATETIME,
502 DT_IDREF,
503 DT_IDREFS,
504 DT_BOOLEAN,
505 -1, -1, -1,
506 DT_STRING,
507 DT_NMTOKEN,
508 DT_NMTOKENS,
510 DT_BIN_BASE64,
512 DT_I2,
513 DT_UI2,
514 -1, -1, -1,
515 DT_DATE_TZ,
516 DT_NOTATION,
517 -1, -1,
518 DT_DATETIME_TZ,
519 DT_I1,
520 DT_UI1,
521 -1, -1,
522 DT_ENUMERATION,
523 -1, -1, -1, -1, -1, -1, -1, -1, -1,
524 -1, -1, -1, -1, -1, -1, -1, -1, -1,
525 -1, -1, -1, -1, -1, -1, -1, -1, -1,
526 -1, -1, -1, -1, -1, -1, -1, -1, -1,
527 -1, -1, -1, -1, -1, -1, -1, -1, -1,
528 -1, -1, -1, -1, -1, -1, -1, -1,
529 DT_FIXED_14_4
532 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
534 DWORD hash = dt_hash(str, len);
535 XDR_DT dt = DT_INVALID;
537 if (hash <= DT_MAX_HASH_VALUE)
538 dt = DT_lookup_table[hash];
540 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
541 return dt;
543 return DT_INVALID;
546 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
548 DWORD hash = dt_hash_bstr(bstr, len);
549 XDR_DT dt = DT_INVALID;
551 if (hash <= DT_MAX_HASH_VALUE)
552 dt = DT_lookup_table[hash];
554 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
555 return dt;
557 return DT_INVALID;
560 xmlChar const* dt_to_str(XDR_DT dt)
562 if (dt == DT_INVALID)
563 return NULL;
565 return DT_string_table[dt];
568 OLECHAR const* dt_to_bstr(XDR_DT dt)
570 if (dt == DT_INVALID)
571 return NULL;
573 return DT_wstring_table[dt];
576 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
578 xmlDocPtr tmp_doc;
579 xmlNodePtr node;
580 xmlNsPtr ns;
581 HRESULT hr;
583 TRACE("(dt:%s, %s)\n", dt_to_str(dt), wine_dbgstr_a((char const*)content));
585 if (!datatypes_schema)
587 xmlSchemaParserCtxtPtr spctx;
588 assert(datatypes_src != NULL);
589 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
590 datatypes_schema = Schema_parse(spctx);
591 xmlSchemaFreeParserCtxt(spctx);
594 switch (dt)
596 case DT_INVALID:
597 return E_FAIL;
598 case DT_BIN_BASE64:
599 case DT_BIN_HEX:
600 case DT_BOOLEAN:
601 case DT_CHAR:
602 case DT_DATE:
603 case DT_DATE_TZ:
604 case DT_DATETIME:
605 case DT_DATETIME_TZ:
606 case DT_FIXED_14_4:
607 case DT_FLOAT:
608 case DT_I1:
609 case DT_I2:
610 case DT_I4:
611 case DT_I8:
612 case DT_INT:
613 case DT_NMTOKEN:
614 case DT_NMTOKENS:
615 case DT_NUMBER:
616 case DT_R4:
617 case DT_R8:
618 case DT_STRING:
619 case DT_TIME:
620 case DT_TIME_TZ:
621 case DT_UI1:
622 case DT_UI2:
623 case DT_UI4:
624 case DT_UI8:
625 case DT_URI:
626 case DT_UUID:
627 if (!datatypes_schema)
629 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
630 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
632 /* Hopefully they don't need much in the way of XDR datatypes support... */
633 return S_OK;
636 if (content && xmlStrlen(content))
638 tmp_doc = xmlNewDoc(NULL);
639 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
640 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
641 xmlSetNs(node, ns);
642 xmlDocSetRootElement(tmp_doc, node);
644 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
645 xmlFreeDoc(tmp_doc);
647 else
648 { /* probably the node is being created manually and has no content yet */
649 hr = S_OK;
651 return hr;
652 default:
653 FIXME("need to handle dt:%s\n", dt_to_str(dt));
654 return S_OK;
658 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
660 return (node->ns != NULL)? node->ns->href : NULL;
663 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
665 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
666 xmlHashLookup(This->cache, nsURI);
669 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
671 cache_entry* entry = get_entry(This, get_node_nsURI(node));
672 return (!entry)? NULL : entry->schema;
675 static xmlExternalEntityLoader _external_entity_loader;
677 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
678 xmlParserCtxtPtr ctxt)
680 xmlParserInputPtr input;
682 TRACE("(%s, %s, %p)\n", wine_dbgstr_a(URL), wine_dbgstr_a(ID), ctxt);
684 assert(MSXML_hInstance != NULL);
685 assert(datatypes_rsrc != NULL);
686 assert(datatypes_handle != NULL);
687 assert(datatypes_src != NULL);
689 /* TODO: if the desired schema is in the cache, load it from there */
690 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
692 TRACE("loading built-in schema for %s\n", URL);
693 input = xmlNewStringInputStream(ctxt, datatypes_src);
695 else
697 input = _external_entity_loader(URL, ID, ctxt);
700 return input;
703 void schemasInit(void)
705 int len;
706 char* buf;
707 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
709 FIXME("failed to find resource for %s\n", DT_nsURI);
710 return;
713 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
715 FIXME("failed to load resource for %s\n", DT_nsURI);
716 return;
718 buf = LockResource(datatypes_handle);
719 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
721 /* Resource is loaded as raw data,
722 * need a null-terminated string */
723 while (buf[len] != '>')
724 buf[len--] = 0;
725 datatypes_src = BAD_CAST buf;
726 datatypes_len = len + 1;
728 if (xmlGetExternalEntityLoader() != external_entity_loader)
730 _external_entity_loader = xmlGetExternalEntityLoader();
731 xmlSetExternalEntityLoader(external_entity_loader);
735 void schemasCleanup(void)
737 xmlSchemaFree(datatypes_schema);
738 xmlSetExternalEntityLoader(_external_entity_loader);
741 static LONG cache_entry_add_ref(cache_entry* entry)
743 LONG ref = InterlockedIncrement(&entry->ref);
744 TRACE("%p new ref %d\n", entry, ref);
745 return ref;
748 static LONG cache_entry_release(cache_entry* entry)
750 LONG ref = InterlockedDecrement(&entry->ref);
751 TRACE("%p new ref %d\n", entry, ref);
753 if (ref == 0)
755 if (entry->type == SCHEMA_TYPE_XSD)
757 xmldoc_release(entry->doc);
758 entry->schema->doc = NULL;
759 xmlSchemaFree(entry->schema);
760 heap_free(entry);
762 else /* SCHEMA_TYPE_XDR */
764 xmldoc_release(entry->doc);
765 xmldoc_release(entry->schema->doc);
766 entry->schema->doc = NULL;
767 xmlSchemaFree(entry->schema);
768 heap_free(entry);
771 return ref;
774 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
776 return (schema_cache*)((char*)iface - FIELD_OFFSET(schema_cache, lpVtbl));
779 static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
781 xmlNodePtr root = NULL;
782 if (schema)
783 root = xmlDocGetRootElement(schema);
784 if (root && root->ns)
787 if (xmlStrEqual(root->name, XDR_schema) &&
788 xmlStrEqual(root->ns->href, XDR_nsURI))
790 return SCHEMA_TYPE_XDR;
792 else if (xmlStrEqual(root->name, XSD_schema) &&
793 xmlStrEqual(root->ns->href, XSD_nsURI))
795 return SCHEMA_TYPE_XSD;
798 return SCHEMA_TYPE_INVALID;
801 static BOOL link_datatypes(xmlDocPtr schema)
803 xmlNodePtr root, next, child;
804 xmlNsPtr ns;
806 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
807 root = xmlDocGetRootElement(schema);
808 if (!root)
809 return FALSE;
811 for (ns = root->nsDef; ns != NULL; ns = ns->next)
813 if (xmlStrEqual(ns->href, DT_nsURI))
814 break;
817 if (!ns)
818 return FALSE;
820 next = xmlFirstElementChild(root);
821 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
822 if (next) child = xmlAddPrevSibling(next, child);
823 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
824 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
826 return TRUE;
829 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
831 cache_entry* entry = heap_alloc(sizeof(cache_entry));
832 xmlSchemaParserCtxtPtr spctx;
833 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
835 link_datatypes(new_doc);
837 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
838 * do we need to do something special here? */
839 entry->type = SCHEMA_TYPE_XSD;
840 entry->ref = 0;
841 spctx = xmlSchemaNewDocParserCtxt(new_doc);
843 if ((entry->schema = Schema_parse(spctx)))
845 xmldoc_init(entry->schema->doc, v);
846 entry->doc = entry->schema->doc;
847 xmldoc_add_ref(entry->doc);
849 else
851 FIXME("failed to parse doc\n");
852 xmlFreeDoc(new_doc);
853 heap_free(entry);
854 entry = NULL;
856 xmlSchemaFreeParserCtxt(spctx);
857 return entry;
860 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
862 cache_entry* entry = heap_alloc(sizeof(cache_entry));
863 xmlSchemaParserCtxtPtr spctx;
864 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
866 link_datatypes(xsd_doc);
868 entry->type = SCHEMA_TYPE_XDR;
869 entry->ref = 0;
870 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
872 if ((entry->schema = Schema_parse(spctx)))
874 entry->doc = new_doc;
875 xmldoc_init(entry->schema->doc, version);
876 xmldoc_init(entry->doc, version);
877 xmldoc_add_ref(entry->doc);
878 xmldoc_add_ref(entry->schema->doc);
880 else
882 FIXME("failed to parse doc\n");
883 xmlFreeDoc(new_doc);
884 xmlFreeDoc(xsd_doc);
885 heap_free(entry);
886 entry = NULL;
888 xmlSchemaFreeParserCtxt(spctx);
890 return entry;
893 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
895 cache_entry* entry;
896 IXMLDOMDocument3* domdoc = NULL;
897 xmlDocPtr doc = NULL;
898 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
899 VARIANT_BOOL b = VARIANT_FALSE;
900 SCHEMA_TYPE type = SCHEMA_TYPE_INVALID;
902 if (hr != S_OK)
904 FIXME("failed to create domdoc\n");
905 return NULL;
907 assert(domdoc != NULL);
908 assert(V_VT(&url) == VT_BSTR);
910 hr = IXMLDOMDocument3_load(domdoc, url, &b);
911 if (hr != S_OK)
913 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
914 if (b != VARIANT_TRUE)
916 FIXME("Failed to load doc at %s\n", wine_dbgstr_w(V_BSTR(&url)));
917 IXMLDOMDocument3_Release(domdoc);
918 return NULL;
921 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
922 type = schema_type_from_xmlDocPtr(doc);
924 switch (type)
926 case SCHEMA_TYPE_XSD:
927 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
928 break;
929 case SCHEMA_TYPE_XDR:
930 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
931 break;
932 case SCHEMA_TYPE_INVALID:
933 entry = NULL;
934 FIXME("invalid schema\n");
935 break;
937 IXMLDOMDocument3_Release(domdoc);
939 return entry;
942 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
943 REFIID riid, void** ppvObject)
945 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
947 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
949 if ( IsEqualIID(riid, &IID_IUnknown) ||
950 IsEqualIID(riid, &IID_IDispatch) ||
951 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
952 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
954 *ppvObject = iface;
956 else
958 FIXME("interface %s not implemented\n", debugstr_guid(riid));
959 *ppvObject = NULL;
960 return E_NOINTERFACE;
963 IXMLDOMSchemaCollection2_AddRef(iface);
965 return S_OK;
968 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
970 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
971 LONG ref = InterlockedIncrement(&This->ref);
972 TRACE("%p new ref %d\n", This, ref);
973 return ref;
976 static void cache_free(void* data, xmlChar* name /* ignored */)
978 cache_entry_release((cache_entry*)data);
981 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
983 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
984 LONG ref = InterlockedDecrement(&This->ref);
985 TRACE("%p new ref %d\n", This, ref);
987 if (ref == 0)
989 xmlHashFree(This->cache, cache_free);
990 heap_free(This);
993 return ref;
996 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
997 UINT* pctinfo)
999 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1001 TRACE("(%p)->(%p)\n", This, pctinfo);
1003 *pctinfo = 1;
1005 return S_OK;
1008 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1009 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1011 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1012 HRESULT hr;
1014 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1016 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, ppTInfo);
1018 return hr;
1021 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1022 REFIID riid, LPOLESTR* rgszNames,
1023 UINT cNames, LCID lcid, DISPID* rgDispId)
1025 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1026 ITypeInfo* typeinfo;
1027 HRESULT hr;
1029 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1030 lcid, rgDispId);
1032 if(!rgszNames || cNames == 0 || !rgDispId)
1033 return E_INVALIDARG;
1035 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1036 if(SUCCEEDED(hr))
1038 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1039 ITypeInfo_Release(typeinfo);
1042 return hr;
1045 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1046 DISPID dispIdMember, REFIID riid, LCID lcid,
1047 WORD wFlags, DISPPARAMS* pDispParams,
1048 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1049 UINT* puArgErr)
1051 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1052 ITypeInfo* typeinfo;
1053 HRESULT hr;
1055 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1056 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1058 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1059 if(SUCCEEDED(hr))
1061 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1062 pVarResult, pExcepInfo, puArgErr);
1063 ITypeInfo_Release(typeinfo);
1066 return hr;
1069 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1071 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1072 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1073 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1075 switch (V_VT(&var))
1077 case VT_NULL:
1079 xmlHashRemoveEntry(This->cache, name, cache_free);
1081 break;
1083 case VT_BSTR:
1085 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1087 if (entry)
1089 cache_entry_add_ref(entry);
1091 else
1093 heap_free(name);
1094 return E_FAIL;
1097 xmlHashRemoveEntry(This->cache, name, cache_free);
1098 xmlHashAddEntry(This->cache, name, entry);
1100 break;
1102 case VT_DISPATCH:
1104 xmlDocPtr doc = NULL;
1105 cache_entry* entry;
1106 SCHEMA_TYPE type;
1107 IXMLDOMNode* domnode = NULL;
1108 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1110 if (domnode)
1111 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1113 if (!doc)
1115 IXMLDOMNode_Release(domnode);
1116 heap_free(name);
1117 return E_INVALIDARG;
1119 type = schema_type_from_xmlDocPtr(doc);
1121 if (type == SCHEMA_TYPE_XSD)
1123 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1125 else if (type == SCHEMA_TYPE_XDR)
1127 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1129 else
1131 WARN("invalid schema!\n");
1132 entry = NULL;
1135 IXMLDOMNode_Release(domnode);
1137 if (entry)
1139 cache_entry_add_ref(entry);
1141 else
1143 heap_free(name);
1144 return E_FAIL;
1147 xmlHashRemoveEntry(This->cache, name, cache_free);
1148 xmlHashAddEntry(This->cache, name, entry);
1150 break;
1152 default:
1154 heap_free(name);
1155 return E_INVALIDARG;
1158 heap_free(name);
1159 return S_OK;
1162 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1163 IXMLDOMNode** node)
1165 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1166 xmlChar* name;
1167 cache_entry* entry;
1168 TRACE("(%p)->(%s, %p)\n", This, wine_dbgstr_w(uri), node);
1170 if (!node)
1171 return E_POINTER;
1173 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1174 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1175 heap_free(name);
1177 /* TODO: this should be read-only */
1178 if (entry)
1179 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1181 *node = NULL;
1182 return S_OK;
1185 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1187 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1188 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1189 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(uri));
1191 xmlHashRemoveEntry(This->cache, name, cache_free);
1192 heap_free(name);
1193 return S_OK;
1196 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1198 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1199 TRACE("(%p)->(%p)\n", This, length);
1201 if (!length)
1202 return E_POINTER;
1203 *length = xmlHashSize(This->cache);
1204 return S_OK;
1207 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1209 cache_index_data* index_data = (cache_index_data*)index;
1211 if (index_data->index-- == 0)
1212 *index_data->out = bstr_from_xmlChar(name);
1215 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1216 LONG index, BSTR* len)
1218 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1219 cache_index_data data = {index,len};
1220 TRACE("(%p)->(%i, %p)\n", This, index, len);
1222 if (!len)
1223 return E_POINTER;
1224 *len = NULL;
1226 if (index >= xmlHashSize(This->cache))
1227 return E_FAIL;
1229 xmlHashScan(This->cache, cache_index, &data);
1230 return S_OK;
1233 static void cache_copy(void* data, void* dest, xmlChar* name)
1235 schema_cache* This = (schema_cache*) dest;
1236 cache_entry* entry = (cache_entry*) data;
1238 if (xmlHashLookup(This->cache, name) == NULL)
1240 cache_entry_add_ref(entry);
1241 xmlHashAddEntry(This->cache, name, entry);
1245 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1246 IXMLDOMSchemaCollection* otherCollection)
1248 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1249 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1250 TRACE("(%p)->(%p)\n", This, That);
1252 if (!otherCollection)
1253 return E_POINTER;
1255 /* TODO: detect errors while copying & return E_FAIL */
1256 xmlHashScan(That->cache, cache_copy, This);
1258 return S_OK;
1261 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1262 IUnknown** ppUnk)
1264 FIXME("stub\n");
1265 if (ppUnk)
1266 *ppUnk = NULL;
1267 return E_NOTIMPL;
1270 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1272 FIXME("stub\n");
1273 return E_NOTIMPL;
1276 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1277 VARIANT_BOOL validateOnLoad)
1279 FIXME("stub\n");
1280 return E_NOTIMPL;
1283 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1284 VARIANT_BOOL* validateOnLoad)
1286 FIXME("stub\n");
1287 return E_NOTIMPL;
1290 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1291 BSTR namespaceURI, ISchema** schema)
1293 FIXME("stub\n");
1294 if (schema)
1295 *schema = NULL;
1296 return E_NOTIMPL;
1299 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1300 IXMLDOMNode* node, ISchemaItem** item)
1302 FIXME("stub\n");
1303 if (item)
1304 *item = NULL;
1305 return E_NOTIMPL;
1308 static const struct IXMLDOMSchemaCollection2Vtbl schema_cache_vtbl =
1310 schema_cache_QueryInterface,
1311 schema_cache_AddRef,
1312 schema_cache_Release,
1313 schema_cache_GetTypeInfoCount,
1314 schema_cache_GetTypeInfo,
1315 schema_cache_GetIDsOfNames,
1316 schema_cache_Invoke,
1317 schema_cache_add,
1318 schema_cache_get,
1319 schema_cache_remove,
1320 schema_cache_get_length,
1321 schema_cache_get_namespaceURI,
1322 schema_cache_addCollection,
1323 schema_cache_get__newEnum,
1324 schema_cache_validate,
1325 schema_cache_put_validateOnLoad,
1326 schema_cache_get_validateOnLoad,
1327 schema_cache_getSchema,
1328 schema_cache_getDeclaration
1331 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1333 xmlSchemaElementPtr decl = NULL;
1334 xmlChar const* nsURI = get_node_nsURI(node);
1336 TRACE("(%p, %p)\n", schema, node);
1338 if (xmlStrEqual(nsURI, schema->targetNamespace))
1339 decl = xmlHashLookup(schema->elemDecl, node->name);
1341 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1343 FIXME("declaration not found in main schema - need to check schema imports!\n");
1344 /*xmlSchemaImportPtr import;
1345 if (nsURI == NULL)
1346 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1347 else
1348 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1350 if (import != NULL)
1351 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1354 return decl;
1357 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1359 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1360 while (decl != NULL && decl->refDecl != NULL)
1361 decl = decl->refDecl;
1362 return (decl != NULL)? decl->node : NULL;
1365 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1367 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1368 xmlSchemaPtr schema;
1370 TRACE("(%p, %p)\n", This, tree);
1372 if (!tree)
1373 return E_POINTER;
1375 if (tree->type == XML_DOCUMENT_NODE)
1376 tree = xmlDocGetRootElement(tree->doc);
1378 schema = get_node_schema(This, tree);
1379 /* TODO: if the ns is not in the cache, and it's a URL,
1380 * do we try to load from that? */
1381 if (schema)
1382 return Schema_validate_tree(schema, tree);
1383 else
1384 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1386 return E_FAIL;
1389 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1391 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1392 xmlSchemaPtr schema = get_node_schema(This, node);
1393 XDR_DT dt = DT_INVALID;
1395 TRACE("(%p, %p)\n", This, node);
1397 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1399 dt = str_to_dt(node->name, -1);
1401 else if (schema)
1403 xmlChar* str;
1404 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1406 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1407 if (str)
1409 dt = str_to_dt(str, -1);
1410 xmlFree(str);
1414 return dt;
1417 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* pUnkOuter, void** ppObj)
1419 schema_cache* This = heap_alloc(sizeof(schema_cache));
1420 if (!This)
1421 return E_OUTOFMEMORY;
1423 This->lpVtbl = &schema_cache_vtbl;
1424 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1425 This->ref = 1;
1426 This->version = version;
1428 *ppObj = &This->lpVtbl;
1429 return S_OK;
1432 #else
1434 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* pUnkOuter, void** ppObj)
1436 MESSAGE("This program tried to use a SchemaCache object, but\n"
1437 "libxml2 support was not present at compile time.\n");
1438 return E_NOTIMPL;
1441 #endif