po: Remove English strings from the Finnish translation.
[wine.git] / dlls / msxml3 / schema.c
blob7473dbbbdede540436b0374c0765ee92a551c11d
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
92 DispatchEx dispex;
93 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface;
94 LONG ref;
96 MSXML_VERSION version;
97 xmlHashTablePtr cache;
99 VARIANT_BOOL validateOnLoad;
100 } schema_cache;
102 typedef struct _cache_entry
104 SCHEMA_TYPE type;
105 xmlSchemaPtr schema;
106 xmlDocPtr doc;
107 LONG ref;
108 } cache_entry;
110 typedef struct _cache_index_data
112 LONG index;
113 BSTR* out;
114 } cache_index_data;
116 /* datatypes lookup stuff
117 * generated with help from gperf */
118 #define DT_MIN_STR_LEN 2
119 #define DT_MAX_STR_LEN 11
120 #define DT_MIN_HASH_VALUE 2
121 #define DT_MAX_HASH_VALUE 115
123 static const xmlChar DT_bin_base64[] = "bin.base64";
124 static const xmlChar DT_bin_hex[] = "bin.hex";
125 static const xmlChar DT_boolean[] = "boolean";
126 static const xmlChar DT_char[] = "char";
127 static const xmlChar DT_date[] = "date";
128 static const xmlChar DT_date_tz[] = "date.tz";
129 static const xmlChar DT_dateTime[] = "dateTime";
130 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
131 static const xmlChar DT_entity[] = "entity";
132 static const xmlChar DT_entities[] = "entities";
133 static const xmlChar DT_enumeration[] = "enumeration";
134 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
135 static const xmlChar DT_float[] = "float";
136 static const xmlChar DT_i1[] = "i1";
137 static const xmlChar DT_i2[] = "i2";
138 static const xmlChar DT_i4[] = "i4";
139 static const xmlChar DT_i8[] = "i8";
140 static const xmlChar DT_id[] = "id";
141 static const xmlChar DT_idref[] = "idref";
142 static const xmlChar DT_idrefs[] = "idrefs";
143 static const xmlChar DT_int[] = "int";
144 static const xmlChar DT_nmtoken[] = "nmtoken";
145 static const xmlChar DT_nmtokens[] = "nmtokens";
146 static const xmlChar DT_notation[] = "notation";
147 static const xmlChar DT_number[] = "number";
148 static const xmlChar DT_r4[] = "r4";
149 static const xmlChar DT_r8[] = "r8";
150 static const xmlChar DT_string[] = "string";
151 static const xmlChar DT_time[] = "time";
152 static const xmlChar DT_time_tz[] = "time.tz";
153 static const xmlChar DT_ui1[] = "ui1";
154 static const xmlChar DT_ui2[] = "ui2";
155 static const xmlChar DT_ui4[] = "ui4";
156 static const xmlChar DT_ui8[] = "ui8";
157 static const xmlChar DT_uri[] = "uri";
158 static const xmlChar DT_uuid[] = "uuid";
160 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
161 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
162 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
163 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
164 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
165 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
166 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
167 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
168 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
169 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
170 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
171 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
172 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
173 static const OLECHAR wDT_i1[] = {'i','1',0};
174 static const OLECHAR wDT_i2[] = {'i','2',0};
175 static const OLECHAR wDT_i4[] = {'i','4',0};
176 static const OLECHAR wDT_i8[] = {'i','8',0};
177 static const OLECHAR wDT_id[] = {'i','d',0};
178 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
179 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
180 static const OLECHAR wDT_int[] = {'i','n','t',0};
181 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
182 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
183 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
184 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
185 static const OLECHAR wDT_r4[] = {'r','4',0};
186 static const OLECHAR wDT_r8[] = {'r','8',0};
187 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
188 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
189 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
190 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
191 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
192 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
193 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
194 static const OLECHAR wDT_uri[] = {'u','r','i',0};
195 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
197 static const BYTE hash_assoc_values[] =
199 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
200 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
201 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
202 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
203 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
204 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
205 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
206 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
207 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
208 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
209 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
210 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
211 0, 0, 10, 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, 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
227 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
229 va_list ap;
230 va_start(ap, msg);
231 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
232 va_end(ap);
235 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
237 va_list ap;
238 va_start(ap, msg);
239 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
240 va_end(ap);
243 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
244 static void parser_serror(void* ctx, xmlErrorPtr err)
246 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
248 #endif
250 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
252 TRACE("(%p)\n", spctx);
254 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
255 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
256 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
257 #endif
259 return xmlSchemaParse(spctx);
262 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
264 va_list ap;
265 va_start(ap, msg);
266 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
267 va_end(ap);
270 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
272 va_list ap;
273 va_start(ap, msg);
274 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
275 va_end(ap);
278 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
279 static void validate_serror(void* ctx, xmlErrorPtr err)
281 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
283 #endif
285 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
287 xmlSchemaValidCtxtPtr svctx;
288 int err;
290 TRACE("(%p, %p)\n", schema, tree);
291 /* TODO: if validateOnLoad property is false,
292 * we probably need to validate the schema here. */
293 svctx = xmlSchemaNewValidCtxt(schema);
294 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
295 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
296 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
297 #endif
299 if (tree->type == XML_DOCUMENT_NODE)
300 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
301 else
302 err = xmlSchemaValidateOneElement(svctx, tree);
304 xmlSchemaFreeValidCtxt(svctx);
305 return err? S_FALSE : S_OK;
308 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
310 DWORD hval = (len == -1)? xmlStrlen(str) : len;
312 switch (hval)
314 default:
315 hval += hash_assoc_values[str[10]];
316 /*FALLTHROUGH*/
317 case 10:
318 hval += hash_assoc_values[str[9]];
319 /*FALLTHROUGH*/
320 case 9:
321 hval += hash_assoc_values[str[8]];
322 /*FALLTHROUGH*/
323 case 8:
324 hval += hash_assoc_values[str[7]];
325 /*FALLTHROUGH*/
326 case 7:
327 hval += hash_assoc_values[str[6]];
328 /*FALLTHROUGH*/
329 case 6:
330 hval += hash_assoc_values[str[5]];
331 /*FALLTHROUGH*/
332 case 5:
333 hval += hash_assoc_values[str[4]];
334 /*FALLTHROUGH*/
335 case 4:
336 hval += hash_assoc_values[str[3]];
337 /*FALLTHROUGH*/
338 case 3:
339 hval += hash_assoc_values[str[2]];
340 /*FALLTHROUGH*/
341 case 2:
342 hval += hash_assoc_values[str[1]];
343 /*FALLTHROUGH*/
344 case 1:
345 hval += hash_assoc_values[str[0]];
346 break;
348 return hval;
351 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
353 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
355 switch (hval)
357 default:
358 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
359 /*FALLTHROUGH*/
360 case 10:
361 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
362 /*FALLTHROUGH*/
363 case 9:
364 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
365 /*FALLTHROUGH*/
366 case 8:
367 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
368 /*FALLTHROUGH*/
369 case 7:
370 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
371 /*FALLTHROUGH*/
372 case 6:
373 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
374 /*FALLTHROUGH*/
375 case 5:
376 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
377 /*FALLTHROUGH*/
378 case 4:
379 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
380 /*FALLTHROUGH*/
381 case 3:
382 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
383 /*FALLTHROUGH*/
384 case 2:
385 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
386 /*FALLTHROUGH*/
387 case 1:
388 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
389 break;
391 return hval;
394 static const xmlChar *const DT_string_table[DT__N_TYPES] =
396 DT_bin_base64,
397 DT_bin_hex,
398 DT_boolean,
399 DT_char,
400 DT_date,
401 DT_date_tz,
402 DT_dateTime,
403 DT_dateTime_tz,
404 DT_entity,
405 DT_entities,
406 DT_enumeration,
407 DT_fixed_14_4,
408 DT_float,
409 DT_i1,
410 DT_i2,
411 DT_i4,
412 DT_i8,
413 DT_id,
414 DT_idref,
415 DT_idrefs,
416 DT_int,
417 DT_nmtoken,
418 DT_nmtokens,
419 DT_notation,
420 DT_number,
421 DT_r4,
422 DT_r8,
423 DT_string,
424 DT_time,
425 DT_time_tz,
426 DT_ui1,
427 DT_ui2,
428 DT_ui4,
429 DT_ui8,
430 DT_uri,
431 DT_uuid
434 static const WCHAR *const DT_wstring_table[DT__N_TYPES] =
436 wDT_bin_base64,
437 wDT_bin_hex,
438 wDT_boolean,
439 wDT_char,
440 wDT_date,
441 wDT_date_tz,
442 wDT_dateTime,
443 wDT_dateTime_tz,
444 wDT_entity,
445 wDT_entities,
446 wDT_enumeration,
447 wDT_fixed_14_4,
448 wDT_float,
449 wDT_i1,
450 wDT_i2,
451 wDT_i4,
452 wDT_i8,
453 wDT_id,
454 wDT_idref,
455 wDT_idrefs,
456 wDT_int,
457 wDT_nmtoken,
458 wDT_nmtokens,
459 wDT_notation,
460 wDT_number,
461 wDT_r4,
462 wDT_r8,
463 wDT_string,
464 wDT_time,
465 wDT_time_tz,
466 wDT_ui1,
467 wDT_ui2,
468 wDT_ui4,
469 wDT_ui8,
470 wDT_uri,
471 wDT_uuid
474 static const XDR_DT DT_lookup_table[] =
476 -1, -1,
477 DT_I8,
478 DT_UI8,
479 DT_TIME,
480 -1, -1,
481 DT_I4,
482 DT_UI4,
483 -1, -1, -1,
484 DT_R8,
485 DT_URI,
487 DT_FLOAT,
489 DT_R4,
490 DT_INT,
491 DT_CHAR,
493 DT_ENTITY,
494 DT_ID,
495 DT_ENTITIES,
496 DT_UUID,
497 -1, -1,
498 DT_TIME_TZ,
500 DT_DATE,
502 DT_NUMBER,
503 DT_BIN_HEX,
504 DT_DATETIME,
506 DT_IDREF,
507 DT_IDREFS,
508 DT_BOOLEAN,
509 -1, -1, -1,
510 DT_STRING,
511 DT_NMTOKEN,
512 DT_NMTOKENS,
514 DT_BIN_BASE64,
516 DT_I2,
517 DT_UI2,
518 -1, -1, -1,
519 DT_DATE_TZ,
520 DT_NOTATION,
521 -1, -1,
522 DT_DATETIME_TZ,
523 DT_I1,
524 DT_UI1,
525 -1, -1,
526 DT_ENUMERATION,
527 -1, -1, -1, -1, -1, -1, -1, -1, -1,
528 -1, -1, -1, -1, -1, -1, -1, -1, -1,
529 -1, -1, -1, -1, -1, -1, -1, -1, -1,
530 -1, -1, -1, -1, -1, -1, -1, -1, -1,
531 -1, -1, -1, -1, -1, -1, -1, -1, -1,
532 -1, -1, -1, -1, -1, -1, -1, -1,
533 DT_FIXED_14_4
536 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
538 DWORD hash = dt_hash(str, len);
539 XDR_DT dt = DT_INVALID;
541 if (hash <= DT_MAX_HASH_VALUE)
542 dt = DT_lookup_table[hash];
544 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
545 return dt;
547 return DT_INVALID;
550 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
552 DWORD hash = dt_hash_bstr(bstr, len);
553 XDR_DT dt = DT_INVALID;
555 if (hash <= DT_MAX_HASH_VALUE)
556 dt = DT_lookup_table[hash];
558 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
559 return dt;
561 return DT_INVALID;
564 xmlChar const* dt_to_str(XDR_DT dt)
566 if (dt == DT_INVALID)
567 return NULL;
569 return DT_string_table[dt];
572 OLECHAR const* dt_to_bstr(XDR_DT dt)
574 if (dt == DT_INVALID)
575 return NULL;
577 return DT_wstring_table[dt];
580 const char* debugstr_dt(XDR_DT dt)
582 return debugstr_a(dt != DT_INVALID ? (const char*)DT_string_table[dt] : NULL);
585 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
587 xmlDocPtr tmp_doc;
588 xmlNodePtr node;
589 xmlNsPtr ns;
590 HRESULT hr;
592 TRACE("(dt:%s, %s)\n", debugstr_dt(dt), wine_dbgstr_a((char const*)content));
594 if (!datatypes_schema)
596 xmlSchemaParserCtxtPtr spctx;
597 assert(datatypes_src != NULL);
598 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
599 datatypes_schema = Schema_parse(spctx);
600 xmlSchemaFreeParserCtxt(spctx);
603 switch (dt)
605 case DT_INVALID:
606 return E_FAIL;
607 case DT_BIN_BASE64:
608 case DT_BIN_HEX:
609 case DT_BOOLEAN:
610 case DT_CHAR:
611 case DT_DATE:
612 case DT_DATE_TZ:
613 case DT_DATETIME:
614 case DT_DATETIME_TZ:
615 case DT_FIXED_14_4:
616 case DT_FLOAT:
617 case DT_I1:
618 case DT_I2:
619 case DT_I4:
620 case DT_I8:
621 case DT_INT:
622 case DT_NMTOKEN:
623 case DT_NMTOKENS:
624 case DT_NUMBER:
625 case DT_R4:
626 case DT_R8:
627 case DT_STRING:
628 case DT_TIME:
629 case DT_TIME_TZ:
630 case DT_UI1:
631 case DT_UI2:
632 case DT_UI4:
633 case DT_UI8:
634 case DT_URI:
635 case DT_UUID:
636 if (!datatypes_schema)
638 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
639 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
641 /* Hopefully they don't need much in the way of XDR datatypes support... */
642 return S_OK;
645 if (content && xmlStrlen(content))
647 tmp_doc = xmlNewDoc(NULL);
648 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
649 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
650 xmlSetNs(node, ns);
651 xmlDocSetRootElement(tmp_doc, node);
653 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
654 xmlFreeDoc(tmp_doc);
656 else
657 { /* probably the node is being created manually and has no content yet */
658 hr = S_OK;
660 return hr;
661 default:
662 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
663 return S_OK;
667 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
669 return (node->ns != NULL)? node->ns->href : NULL;
672 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
674 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
675 xmlHashLookup(This->cache, nsURI);
678 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
680 cache_entry* entry = get_entry(This, get_node_nsURI(node));
681 return (!entry)? NULL : entry->schema;
684 static xmlExternalEntityLoader _external_entity_loader;
686 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
687 xmlParserCtxtPtr ctxt)
689 xmlParserInputPtr input;
691 TRACE("(%s %s %p)\n", wine_dbgstr_a(URL), wine_dbgstr_a(ID), ctxt);
693 assert(MSXML_hInstance != NULL);
694 assert(datatypes_rsrc != NULL);
695 assert(datatypes_handle != NULL);
696 assert(datatypes_src != NULL);
698 /* TODO: if the desired schema is in the cache, load it from there */
699 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
701 TRACE("loading built-in schema for %s\n", URL);
702 input = xmlNewStringInputStream(ctxt, datatypes_src);
704 else
706 input = _external_entity_loader(URL, ID, ctxt);
709 return input;
712 void schemasInit(void)
714 int len;
715 char* buf;
716 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
718 FIXME("failed to find resource for %s\n", DT_nsURI);
719 return;
722 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
724 FIXME("failed to load resource for %s\n", DT_nsURI);
725 return;
727 buf = LockResource(datatypes_handle);
728 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
730 /* Resource is loaded as raw data,
731 * need a null-terminated string */
732 while (buf[len] != '>')
733 buf[len--] = 0;
734 datatypes_src = BAD_CAST buf;
735 datatypes_len = len + 1;
737 if (xmlGetExternalEntityLoader() != external_entity_loader)
739 _external_entity_loader = xmlGetExternalEntityLoader();
740 xmlSetExternalEntityLoader(external_entity_loader);
744 void schemasCleanup(void)
746 xmlSchemaFree(datatypes_schema);
747 xmlSetExternalEntityLoader(_external_entity_loader);
750 static LONG cache_entry_add_ref(cache_entry* entry)
752 LONG ref = InterlockedIncrement(&entry->ref);
753 TRACE("(%p)->(%d)\n", entry, ref);
754 return ref;
757 static LONG cache_entry_release(cache_entry* entry)
759 LONG ref = InterlockedDecrement(&entry->ref);
760 TRACE("(%p)->(%d)\n", entry, ref);
762 if (ref == 0)
764 if (entry->type == SCHEMA_TYPE_XSD)
766 xmldoc_release(entry->doc);
767 entry->schema->doc = NULL;
768 xmlSchemaFree(entry->schema);
769 heap_free(entry);
771 else /* SCHEMA_TYPE_XDR */
773 xmldoc_release(entry->doc);
774 xmldoc_release(entry->schema->doc);
775 entry->schema->doc = NULL;
776 xmlSchemaFree(entry->schema);
777 heap_free(entry);
780 return ref;
783 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
785 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
788 static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
790 xmlNodePtr root = NULL;
791 if (schema)
792 root = xmlDocGetRootElement(schema);
793 if (root && root->ns)
796 if (xmlStrEqual(root->name, XDR_schema) &&
797 xmlStrEqual(root->ns->href, XDR_nsURI))
799 return SCHEMA_TYPE_XDR;
801 else if (xmlStrEqual(root->name, XSD_schema) &&
802 xmlStrEqual(root->ns->href, XSD_nsURI))
804 return SCHEMA_TYPE_XSD;
807 return SCHEMA_TYPE_INVALID;
810 static BOOL link_datatypes(xmlDocPtr schema)
812 xmlNodePtr root, next, child;
813 xmlNsPtr ns;
815 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
816 root = xmlDocGetRootElement(schema);
817 if (!root)
818 return FALSE;
820 for (ns = root->nsDef; ns != NULL; ns = ns->next)
822 if (xmlStrEqual(ns->href, DT_nsURI))
823 break;
826 if (!ns)
827 return FALSE;
829 next = xmlFirstElementChild(root);
830 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
831 if (next) child = xmlAddPrevSibling(next, child);
832 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
833 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
835 return TRUE;
838 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
840 cache_entry* entry = heap_alloc(sizeof(cache_entry));
841 xmlSchemaParserCtxtPtr spctx;
842 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
844 link_datatypes(new_doc);
846 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
847 * do we need to do something special here? */
848 entry->type = SCHEMA_TYPE_XSD;
849 entry->ref = 0;
850 spctx = xmlSchemaNewDocParserCtxt(new_doc);
852 if ((entry->schema = Schema_parse(spctx)))
854 xmldoc_init(entry->schema->doc, v);
855 entry->doc = entry->schema->doc;
856 xmldoc_add_ref(entry->doc);
858 else
860 FIXME("failed to parse doc\n");
861 xmlFreeDoc(new_doc);
862 heap_free(entry);
863 entry = NULL;
865 xmlSchemaFreeParserCtxt(spctx);
866 return entry;
869 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
871 cache_entry* entry = heap_alloc(sizeof(cache_entry));
872 xmlSchemaParserCtxtPtr spctx;
873 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
875 link_datatypes(xsd_doc);
877 entry->type = SCHEMA_TYPE_XDR;
878 entry->ref = 0;
879 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
881 if ((entry->schema = Schema_parse(spctx)))
883 entry->doc = new_doc;
884 xmldoc_init(entry->schema->doc, version);
885 xmldoc_init(entry->doc, version);
886 xmldoc_add_ref(entry->doc);
887 xmldoc_add_ref(entry->schema->doc);
889 else
891 FIXME("failed to parse doc\n");
892 xmlFreeDoc(new_doc);
893 xmlFreeDoc(xsd_doc);
894 heap_free(entry);
895 entry = NULL;
897 xmlSchemaFreeParserCtxt(spctx);
899 return entry;
902 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
904 cache_entry* entry;
905 IXMLDOMDocument3* domdoc = NULL;
906 xmlDocPtr doc = NULL;
907 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
908 VARIANT_BOOL b = VARIANT_FALSE;
909 SCHEMA_TYPE type = SCHEMA_TYPE_INVALID;
911 if (hr != S_OK)
913 FIXME("failed to create domdoc\n");
914 return NULL;
916 assert(domdoc != NULL);
917 assert(V_VT(&url) == VT_BSTR);
919 hr = IXMLDOMDocument3_load(domdoc, url, &b);
920 if (hr != S_OK)
922 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
923 if (b != VARIANT_TRUE)
925 FIXME("Failed to load doc at %s\n", wine_dbgstr_w(V_BSTR(&url)));
926 IXMLDOMDocument3_Release(domdoc);
927 return NULL;
930 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
931 type = schema_type_from_xmlDocPtr(doc);
933 switch (type)
935 case SCHEMA_TYPE_XSD:
936 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
937 break;
938 case SCHEMA_TYPE_XDR:
939 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
940 break;
941 case SCHEMA_TYPE_INVALID:
942 entry = NULL;
943 FIXME("invalid schema\n");
944 break;
946 IXMLDOMDocument3_Release(domdoc);
948 return entry;
951 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
952 REFIID riid, void** ppvObject)
954 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
956 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
958 if ( IsEqualIID(riid, &IID_IUnknown) ||
959 IsEqualIID(riid, &IID_IDispatch) ||
960 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
961 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
963 *ppvObject = iface;
965 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
967 return *ppvObject ? S_OK : E_NOINTERFACE;
969 else
971 FIXME("interface %s not implemented\n", debugstr_guid(riid));
972 *ppvObject = NULL;
973 return E_NOINTERFACE;
976 IXMLDOMSchemaCollection2_AddRef(iface);
978 return S_OK;
981 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
983 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
984 LONG ref = InterlockedIncrement(&This->ref);
985 TRACE("(%p)->(%d)\n", This, ref);
986 return ref;
989 static void cache_free(void* data, xmlChar* name /* ignored */)
991 cache_entry_release((cache_entry*)data);
994 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
996 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
997 LONG ref = InterlockedDecrement(&This->ref);
998 TRACE("(%p)->(%d)\n", This, ref);
1000 if (ref == 0)
1002 xmlHashFree(This->cache, cache_free);
1003 release_dispex(&This->dispex);
1004 heap_free(This);
1007 return ref;
1010 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1011 UINT* pctinfo)
1013 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1014 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1017 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1018 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1020 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1021 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
1022 iTInfo, lcid, ppTInfo);
1025 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1026 REFIID riid, LPOLESTR* rgszNames,
1027 UINT cNames, LCID lcid, DISPID* rgDispId)
1029 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1030 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1031 riid, rgszNames, cNames, lcid, rgDispId);
1034 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1035 DISPID dispIdMember, REFIID riid, LCID lcid,
1036 WORD wFlags, DISPPARAMS* pDispParams,
1037 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1038 UINT* puArgErr)
1040 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1041 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1042 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1045 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1047 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1048 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1049 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1051 switch (V_VT(&var))
1053 case VT_NULL:
1055 xmlHashRemoveEntry(This->cache, name, cache_free);
1057 break;
1059 case VT_BSTR:
1061 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1063 if (entry)
1065 cache_entry_add_ref(entry);
1067 else
1069 heap_free(name);
1070 return E_FAIL;
1073 xmlHashRemoveEntry(This->cache, name, cache_free);
1074 xmlHashAddEntry(This->cache, name, entry);
1076 break;
1078 case VT_DISPATCH:
1080 xmlDocPtr doc = NULL;
1081 cache_entry* entry;
1082 SCHEMA_TYPE type;
1083 IXMLDOMNode* domnode = NULL;
1084 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1086 if (domnode)
1087 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1089 if (!doc)
1091 IXMLDOMNode_Release(domnode);
1092 heap_free(name);
1093 return E_INVALIDARG;
1095 type = schema_type_from_xmlDocPtr(doc);
1097 if (type == SCHEMA_TYPE_XSD)
1099 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1101 else if (type == SCHEMA_TYPE_XDR)
1103 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1105 else
1107 WARN("invalid schema!\n");
1108 entry = NULL;
1111 IXMLDOMNode_Release(domnode);
1113 if (entry)
1115 cache_entry_add_ref(entry);
1117 else
1119 heap_free(name);
1120 return E_FAIL;
1123 xmlHashRemoveEntry(This->cache, name, cache_free);
1124 xmlHashAddEntry(This->cache, name, entry);
1126 break;
1128 default:
1130 heap_free(name);
1131 return E_INVALIDARG;
1134 heap_free(name);
1135 return S_OK;
1138 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1139 IXMLDOMNode** node)
1141 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1142 xmlChar* name;
1143 cache_entry* entry;
1144 TRACE("(%p)->(%s %p)\n", This, wine_dbgstr_w(uri), node);
1146 if (!node)
1147 return E_POINTER;
1149 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1150 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1151 heap_free(name);
1153 /* TODO: this should be read-only */
1154 if (entry)
1155 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1157 *node = NULL;
1158 return S_OK;
1161 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1163 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1164 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1165 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(uri));
1167 xmlHashRemoveEntry(This->cache, name, cache_free);
1168 heap_free(name);
1169 return S_OK;
1172 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1174 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1175 TRACE("(%p)->(%p)\n", This, length);
1177 if (!length)
1178 return E_POINTER;
1179 *length = xmlHashSize(This->cache);
1180 return S_OK;
1183 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1185 cache_index_data* index_data = (cache_index_data*)index;
1187 if (index_data->index-- == 0)
1188 *index_data->out = bstr_from_xmlChar(name);
1191 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1192 LONG index, BSTR* len)
1194 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1195 cache_index_data data = {index,len};
1196 TRACE("(%p)->(%i %p)\n", This, index, len);
1198 if (!len)
1199 return E_POINTER;
1200 *len = NULL;
1202 if (index >= xmlHashSize(This->cache))
1203 return E_FAIL;
1205 xmlHashScan(This->cache, cache_index, &data);
1206 return S_OK;
1209 static void cache_copy(void* data, void* dest, xmlChar* name)
1211 schema_cache* This = (schema_cache*) dest;
1212 cache_entry* entry = (cache_entry*) data;
1214 if (xmlHashLookup(This->cache, name) == NULL)
1216 cache_entry_add_ref(entry);
1217 xmlHashAddEntry(This->cache, name, entry);
1221 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1222 IXMLDOMSchemaCollection* otherCollection)
1224 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1225 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1226 TRACE("(%p)->(%p)\n", This, That);
1228 if (!otherCollection)
1229 return E_POINTER;
1231 /* TODO: detect errors while copying & return E_FAIL */
1232 xmlHashScan(That->cache, cache_copy, This);
1234 return S_OK;
1237 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1238 IUnknown** ppUnk)
1240 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1241 FIXME("(%p)->(%p): stub\n", This, ppUnk);
1242 if (ppUnk)
1243 *ppUnk = NULL;
1244 return E_NOTIMPL;
1247 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1249 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1250 FIXME("(%p): stub\n", This);
1251 return E_NOTIMPL;
1254 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1255 VARIANT_BOOL value)
1257 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1258 FIXME("(%p)->(%d): stub\n", This, value);
1260 This->validateOnLoad = value;
1261 /* it's ok to disable it, cause we don't validate on load anyway */
1262 if (value == VARIANT_FALSE) return S_OK;
1264 return E_NOTIMPL;
1267 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1268 VARIANT_BOOL* value)
1270 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1271 TRACE("(%p)->(%p)\n", This, value);
1273 if (!value) return E_POINTER;
1274 *value = This->validateOnLoad;
1276 return S_OK;
1279 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1280 BSTR namespaceURI, ISchema** schema)
1282 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1283 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1284 if (schema)
1285 *schema = NULL;
1286 return E_NOTIMPL;
1289 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1290 IXMLDOMNode* node, ISchemaItem** item)
1292 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1293 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1294 if (item)
1295 *item = NULL;
1296 return E_NOTIMPL;
1299 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl =
1301 schema_cache_QueryInterface,
1302 schema_cache_AddRef,
1303 schema_cache_Release,
1304 schema_cache_GetTypeInfoCount,
1305 schema_cache_GetTypeInfo,
1306 schema_cache_GetIDsOfNames,
1307 schema_cache_Invoke,
1308 schema_cache_add,
1309 schema_cache_get,
1310 schema_cache_remove,
1311 schema_cache_get_length,
1312 schema_cache_get_namespaceURI,
1313 schema_cache_addCollection,
1314 schema_cache_get__newEnum,
1315 schema_cache_validate,
1316 schema_cache_put_validateOnLoad,
1317 schema_cache_get_validateOnLoad,
1318 schema_cache_getSchema,
1319 schema_cache_getDeclaration
1322 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1324 xmlSchemaElementPtr decl = NULL;
1325 xmlChar const* nsURI = get_node_nsURI(node);
1327 TRACE("(%p, %p)\n", schema, node);
1329 if (xmlStrEqual(nsURI, schema->targetNamespace))
1330 decl = xmlHashLookup(schema->elemDecl, node->name);
1332 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1334 FIXME("declaration not found in main schema - need to check schema imports!\n");
1335 /*xmlSchemaImportPtr import;
1336 if (nsURI == NULL)
1337 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1338 else
1339 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1341 if (import != NULL)
1342 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1345 return decl;
1348 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1350 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1351 while (decl != NULL && decl->refDecl != NULL)
1352 decl = decl->refDecl;
1353 return (decl != NULL)? decl->node : NULL;
1356 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1358 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1359 xmlSchemaPtr schema;
1361 TRACE("(%p, %p)\n", This, tree);
1363 if (!tree)
1364 return E_POINTER;
1366 if (tree->type == XML_DOCUMENT_NODE)
1367 tree = xmlDocGetRootElement(tree->doc);
1369 schema = get_node_schema(This, tree);
1370 /* TODO: if the ns is not in the cache, and it's a URL,
1371 * do we try to load from that? */
1372 if (schema)
1373 return Schema_validate_tree(schema, tree);
1374 else
1375 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1377 return E_FAIL;
1380 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1382 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1383 xmlSchemaPtr schema = get_node_schema(This, node);
1384 XDR_DT dt = DT_INVALID;
1386 TRACE("(%p, %p)\n", This, node);
1388 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1390 dt = str_to_dt(node->name, -1);
1392 else if (schema)
1394 xmlChar* str;
1395 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1397 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1398 if (str)
1400 dt = str_to_dt(str, -1);
1401 xmlFree(str);
1405 return dt;
1408 static const tid_t schemacache_iface_tids[] = {
1409 IXMLDOMSchemaCollection2_tid,
1413 static dispex_static_data_t schemacache_dispex = {
1414 NULL,
1415 IXMLDOMSchemaCollection2_tid,
1416 NULL,
1417 schemacache_iface_tids
1420 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1422 schema_cache* This = heap_alloc(sizeof(schema_cache));
1423 if (!This)
1424 return E_OUTOFMEMORY;
1426 TRACE("(%d %p %p)\n", version, outer, obj);
1428 This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl;
1429 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1430 This->ref = 1;
1431 This->version = version;
1432 This->validateOnLoad = VARIANT_TRUE;
1433 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSchemaCollection2_iface, &schemacache_dispex);
1435 *obj = &This->IXMLDOMSchemaCollection2_iface;
1436 return S_OK;
1439 #else
1441 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* pUnkOuter, void** ppObj)
1443 MESSAGE("This program tried to use a SchemaCache object, but\n"
1444 "libxml2 support was not present at compile time.\n");
1445 return E_NOTIMPL;
1448 #endif