msxml3: Trace parameters in stub methods.
[wine/multimedia.git] / dlls / msxml3 / schema.c
blob9cdccb087337462e79a9cf59efdf0a15d4f61878
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 const char* debugstr_dt(XDR_DT dt)
578 return debugstr_a(dt != DT_INVALID ? (const char*)DT_string_table[dt] : NULL);
581 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
583 xmlDocPtr tmp_doc;
584 xmlNodePtr node;
585 xmlNsPtr ns;
586 HRESULT hr;
588 TRACE("(dt:%s, %s)\n", debugstr_dt(dt), wine_dbgstr_a((char const*)content));
590 if (!datatypes_schema)
592 xmlSchemaParserCtxtPtr spctx;
593 assert(datatypes_src != NULL);
594 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
595 datatypes_schema = Schema_parse(spctx);
596 xmlSchemaFreeParserCtxt(spctx);
599 switch (dt)
601 case DT_INVALID:
602 return E_FAIL;
603 case DT_BIN_BASE64:
604 case DT_BIN_HEX:
605 case DT_BOOLEAN:
606 case DT_CHAR:
607 case DT_DATE:
608 case DT_DATE_TZ:
609 case DT_DATETIME:
610 case DT_DATETIME_TZ:
611 case DT_FIXED_14_4:
612 case DT_FLOAT:
613 case DT_I1:
614 case DT_I2:
615 case DT_I4:
616 case DT_I8:
617 case DT_INT:
618 case DT_NMTOKEN:
619 case DT_NMTOKENS:
620 case DT_NUMBER:
621 case DT_R4:
622 case DT_R8:
623 case DT_STRING:
624 case DT_TIME:
625 case DT_TIME_TZ:
626 case DT_UI1:
627 case DT_UI2:
628 case DT_UI4:
629 case DT_UI8:
630 case DT_URI:
631 case DT_UUID:
632 if (!datatypes_schema)
634 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
635 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
637 /* Hopefully they don't need much in the way of XDR datatypes support... */
638 return S_OK;
641 if (content && xmlStrlen(content))
643 tmp_doc = xmlNewDoc(NULL);
644 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
645 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
646 xmlSetNs(node, ns);
647 xmlDocSetRootElement(tmp_doc, node);
649 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
650 xmlFreeDoc(tmp_doc);
652 else
653 { /* probably the node is being created manually and has no content yet */
654 hr = S_OK;
656 return hr;
657 default:
658 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
659 return S_OK;
663 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
665 return (node->ns != NULL)? node->ns->href : NULL;
668 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
670 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
671 xmlHashLookup(This->cache, nsURI);
674 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
676 cache_entry* entry = get_entry(This, get_node_nsURI(node));
677 return (!entry)? NULL : entry->schema;
680 static xmlExternalEntityLoader _external_entity_loader;
682 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
683 xmlParserCtxtPtr ctxt)
685 xmlParserInputPtr input;
687 TRACE("(%s %s %p)\n", wine_dbgstr_a(URL), wine_dbgstr_a(ID), ctxt);
689 assert(MSXML_hInstance != NULL);
690 assert(datatypes_rsrc != NULL);
691 assert(datatypes_handle != NULL);
692 assert(datatypes_src != NULL);
694 /* TODO: if the desired schema is in the cache, load it from there */
695 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
697 TRACE("loading built-in schema for %s\n", URL);
698 input = xmlNewStringInputStream(ctxt, datatypes_src);
700 else
702 input = _external_entity_loader(URL, ID, ctxt);
705 return input;
708 void schemasInit(void)
710 int len;
711 char* buf;
712 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
714 FIXME("failed to find resource for %s\n", DT_nsURI);
715 return;
718 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
720 FIXME("failed to load resource for %s\n", DT_nsURI);
721 return;
723 buf = LockResource(datatypes_handle);
724 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
726 /* Resource is loaded as raw data,
727 * need a null-terminated string */
728 while (buf[len] != '>')
729 buf[len--] = 0;
730 datatypes_src = BAD_CAST buf;
731 datatypes_len = len + 1;
733 if (xmlGetExternalEntityLoader() != external_entity_loader)
735 _external_entity_loader = xmlGetExternalEntityLoader();
736 xmlSetExternalEntityLoader(external_entity_loader);
740 void schemasCleanup(void)
742 xmlSchemaFree(datatypes_schema);
743 xmlSetExternalEntityLoader(_external_entity_loader);
746 static LONG cache_entry_add_ref(cache_entry* entry)
748 LONG ref = InterlockedIncrement(&entry->ref);
749 TRACE("(%p)->(%d)\n", entry, ref);
750 return ref;
753 static LONG cache_entry_release(cache_entry* entry)
755 LONG ref = InterlockedDecrement(&entry->ref);
756 TRACE("(%p)->(%d)\n", entry, ref);
758 if (ref == 0)
760 if (entry->type == SCHEMA_TYPE_XSD)
762 xmldoc_release(entry->doc);
763 entry->schema->doc = NULL;
764 xmlSchemaFree(entry->schema);
765 heap_free(entry);
767 else /* SCHEMA_TYPE_XDR */
769 xmldoc_release(entry->doc);
770 xmldoc_release(entry->schema->doc);
771 entry->schema->doc = NULL;
772 xmlSchemaFree(entry->schema);
773 heap_free(entry);
776 return ref;
779 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
781 return (schema_cache*)((char*)iface - FIELD_OFFSET(schema_cache, lpVtbl));
784 static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
786 xmlNodePtr root = NULL;
787 if (schema)
788 root = xmlDocGetRootElement(schema);
789 if (root && root->ns)
792 if (xmlStrEqual(root->name, XDR_schema) &&
793 xmlStrEqual(root->ns->href, XDR_nsURI))
795 return SCHEMA_TYPE_XDR;
797 else if (xmlStrEqual(root->name, XSD_schema) &&
798 xmlStrEqual(root->ns->href, XSD_nsURI))
800 return SCHEMA_TYPE_XSD;
803 return SCHEMA_TYPE_INVALID;
806 static BOOL link_datatypes(xmlDocPtr schema)
808 xmlNodePtr root, next, child;
809 xmlNsPtr ns;
811 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
812 root = xmlDocGetRootElement(schema);
813 if (!root)
814 return FALSE;
816 for (ns = root->nsDef; ns != NULL; ns = ns->next)
818 if (xmlStrEqual(ns->href, DT_nsURI))
819 break;
822 if (!ns)
823 return FALSE;
825 next = xmlFirstElementChild(root);
826 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
827 if (next) child = xmlAddPrevSibling(next, child);
828 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
829 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
831 return TRUE;
834 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
836 cache_entry* entry = heap_alloc(sizeof(cache_entry));
837 xmlSchemaParserCtxtPtr spctx;
838 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
840 link_datatypes(new_doc);
842 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
843 * do we need to do something special here? */
844 entry->type = SCHEMA_TYPE_XSD;
845 entry->ref = 0;
846 spctx = xmlSchemaNewDocParserCtxt(new_doc);
848 if ((entry->schema = Schema_parse(spctx)))
850 xmldoc_init(entry->schema->doc, v);
851 entry->doc = entry->schema->doc;
852 xmldoc_add_ref(entry->doc);
854 else
856 FIXME("failed to parse doc\n");
857 xmlFreeDoc(new_doc);
858 heap_free(entry);
859 entry = NULL;
861 xmlSchemaFreeParserCtxt(spctx);
862 return entry;
865 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
867 cache_entry* entry = heap_alloc(sizeof(cache_entry));
868 xmlSchemaParserCtxtPtr spctx;
869 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
871 link_datatypes(xsd_doc);
873 entry->type = SCHEMA_TYPE_XDR;
874 entry->ref = 0;
875 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
877 if ((entry->schema = Schema_parse(spctx)))
879 entry->doc = new_doc;
880 xmldoc_init(entry->schema->doc, version);
881 xmldoc_init(entry->doc, version);
882 xmldoc_add_ref(entry->doc);
883 xmldoc_add_ref(entry->schema->doc);
885 else
887 FIXME("failed to parse doc\n");
888 xmlFreeDoc(new_doc);
889 xmlFreeDoc(xsd_doc);
890 heap_free(entry);
891 entry = NULL;
893 xmlSchemaFreeParserCtxt(spctx);
895 return entry;
898 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
900 cache_entry* entry;
901 IXMLDOMDocument3* domdoc = NULL;
902 xmlDocPtr doc = NULL;
903 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
904 VARIANT_BOOL b = VARIANT_FALSE;
905 SCHEMA_TYPE type = SCHEMA_TYPE_INVALID;
907 if (hr != S_OK)
909 FIXME("failed to create domdoc\n");
910 return NULL;
912 assert(domdoc != NULL);
913 assert(V_VT(&url) == VT_BSTR);
915 hr = IXMLDOMDocument3_load(domdoc, url, &b);
916 if (hr != S_OK)
918 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
919 if (b != VARIANT_TRUE)
921 FIXME("Failed to load doc at %s\n", wine_dbgstr_w(V_BSTR(&url)));
922 IXMLDOMDocument3_Release(domdoc);
923 return NULL;
926 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
927 type = schema_type_from_xmlDocPtr(doc);
929 switch (type)
931 case SCHEMA_TYPE_XSD:
932 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
933 break;
934 case SCHEMA_TYPE_XDR:
935 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
936 break;
937 case SCHEMA_TYPE_INVALID:
938 entry = NULL;
939 FIXME("invalid schema\n");
940 break;
942 IXMLDOMDocument3_Release(domdoc);
944 return entry;
947 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
948 REFIID riid, void** ppvObject)
950 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
952 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
954 if ( IsEqualIID(riid, &IID_IUnknown) ||
955 IsEqualIID(riid, &IID_IDispatch) ||
956 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
957 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
959 *ppvObject = iface;
961 else
963 FIXME("interface %s not implemented\n", debugstr_guid(riid));
964 *ppvObject = NULL;
965 return E_NOINTERFACE;
968 IXMLDOMSchemaCollection2_AddRef(iface);
970 return S_OK;
973 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
975 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
976 LONG ref = InterlockedIncrement(&This->ref);
977 TRACE("(%p)->(%d)\n", This, ref);
978 return ref;
981 static void cache_free(void* data, xmlChar* name /* ignored */)
983 cache_entry_release((cache_entry*)data);
986 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
988 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
989 LONG ref = InterlockedDecrement(&This->ref);
990 TRACE("(%p)->(%d)\n", This, ref);
992 if (ref == 0)
994 xmlHashFree(This->cache, cache_free);
995 heap_free(This);
998 return ref;
1001 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1002 UINT* pctinfo)
1004 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1006 TRACE("(%p)->(%p)\n", This, pctinfo);
1008 *pctinfo = 1;
1010 return S_OK;
1013 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1014 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1016 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1017 HRESULT hr;
1019 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1021 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, ppTInfo);
1023 return hr;
1026 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1027 REFIID riid, LPOLESTR* rgszNames,
1028 UINT cNames, LCID lcid, DISPID* rgDispId)
1030 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1031 ITypeInfo* typeinfo;
1032 HRESULT hr;
1034 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1035 lcid, rgDispId);
1037 if(!rgszNames || cNames == 0 || !rgDispId)
1038 return E_INVALIDARG;
1040 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1041 if(SUCCEEDED(hr))
1043 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1044 ITypeInfo_Release(typeinfo);
1047 return hr;
1050 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1051 DISPID dispIdMember, REFIID riid, LCID lcid,
1052 WORD wFlags, DISPPARAMS* pDispParams,
1053 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1054 UINT* puArgErr)
1056 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1057 ITypeInfo* typeinfo;
1058 HRESULT hr;
1060 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1061 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1063 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1064 if(SUCCEEDED(hr))
1066 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1067 pVarResult, pExcepInfo, puArgErr);
1068 ITypeInfo_Release(typeinfo);
1071 return hr;
1074 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1076 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1077 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1078 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1080 switch (V_VT(&var))
1082 case VT_NULL:
1084 xmlHashRemoveEntry(This->cache, name, cache_free);
1086 break;
1088 case VT_BSTR:
1090 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1092 if (entry)
1094 cache_entry_add_ref(entry);
1096 else
1098 heap_free(name);
1099 return E_FAIL;
1102 xmlHashRemoveEntry(This->cache, name, cache_free);
1103 xmlHashAddEntry(This->cache, name, entry);
1105 break;
1107 case VT_DISPATCH:
1109 xmlDocPtr doc = NULL;
1110 cache_entry* entry;
1111 SCHEMA_TYPE type;
1112 IXMLDOMNode* domnode = NULL;
1113 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1115 if (domnode)
1116 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1118 if (!doc)
1120 IXMLDOMNode_Release(domnode);
1121 heap_free(name);
1122 return E_INVALIDARG;
1124 type = schema_type_from_xmlDocPtr(doc);
1126 if (type == SCHEMA_TYPE_XSD)
1128 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1130 else if (type == SCHEMA_TYPE_XDR)
1132 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1134 else
1136 WARN("invalid schema!\n");
1137 entry = NULL;
1140 IXMLDOMNode_Release(domnode);
1142 if (entry)
1144 cache_entry_add_ref(entry);
1146 else
1148 heap_free(name);
1149 return E_FAIL;
1152 xmlHashRemoveEntry(This->cache, name, cache_free);
1153 xmlHashAddEntry(This->cache, name, entry);
1155 break;
1157 default:
1159 heap_free(name);
1160 return E_INVALIDARG;
1163 heap_free(name);
1164 return S_OK;
1167 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1168 IXMLDOMNode** node)
1170 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1171 xmlChar* name;
1172 cache_entry* entry;
1173 TRACE("(%p)->(%s %p)\n", This, wine_dbgstr_w(uri), node);
1175 if (!node)
1176 return E_POINTER;
1178 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1179 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1180 heap_free(name);
1182 /* TODO: this should be read-only */
1183 if (entry)
1184 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1186 *node = NULL;
1187 return S_OK;
1190 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1192 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1193 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1194 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(uri));
1196 xmlHashRemoveEntry(This->cache, name, cache_free);
1197 heap_free(name);
1198 return S_OK;
1201 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1203 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1204 TRACE("(%p)->(%p)\n", This, length);
1206 if (!length)
1207 return E_POINTER;
1208 *length = xmlHashSize(This->cache);
1209 return S_OK;
1212 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1214 cache_index_data* index_data = (cache_index_data*)index;
1216 if (index_data->index-- == 0)
1217 *index_data->out = bstr_from_xmlChar(name);
1220 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1221 LONG index, BSTR* len)
1223 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1224 cache_index_data data = {index,len};
1225 TRACE("(%p)->(%i %p)\n", This, index, len);
1227 if (!len)
1228 return E_POINTER;
1229 *len = NULL;
1231 if (index >= xmlHashSize(This->cache))
1232 return E_FAIL;
1234 xmlHashScan(This->cache, cache_index, &data);
1235 return S_OK;
1238 static void cache_copy(void* data, void* dest, xmlChar* name)
1240 schema_cache* This = (schema_cache*) dest;
1241 cache_entry* entry = (cache_entry*) data;
1243 if (xmlHashLookup(This->cache, name) == NULL)
1245 cache_entry_add_ref(entry);
1246 xmlHashAddEntry(This->cache, name, entry);
1250 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1251 IXMLDOMSchemaCollection* otherCollection)
1253 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1254 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1255 TRACE("(%p)->(%p)\n", This, That);
1257 if (!otherCollection)
1258 return E_POINTER;
1260 /* TODO: detect errors while copying & return E_FAIL */
1261 xmlHashScan(That->cache, cache_copy, This);
1263 return S_OK;
1266 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1267 IUnknown** ppUnk)
1269 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1270 FIXME("(%p)->(%p): stub\n", This, ppUnk);
1271 if (ppUnk)
1272 *ppUnk = NULL;
1273 return E_NOTIMPL;
1276 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1278 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1279 FIXME("(%p): stub\n", This);
1280 return E_NOTIMPL;
1283 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1284 VARIANT_BOOL value)
1286 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1287 FIXME("(%p)->(%d): stub\n", This, value);
1288 return E_NOTIMPL;
1291 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1292 VARIANT_BOOL* value)
1294 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1295 FIXME("(%p)->(%p): stub\n", This, value);
1296 return E_NOTIMPL;
1299 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1300 BSTR namespaceURI, ISchema** schema)
1302 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1303 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1304 if (schema)
1305 *schema = NULL;
1306 return E_NOTIMPL;
1309 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1310 IXMLDOMNode* node, ISchemaItem** item)
1312 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1313 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1314 if (item)
1315 *item = NULL;
1316 return E_NOTIMPL;
1319 static const struct IXMLDOMSchemaCollection2Vtbl schema_cache_vtbl =
1321 schema_cache_QueryInterface,
1322 schema_cache_AddRef,
1323 schema_cache_Release,
1324 schema_cache_GetTypeInfoCount,
1325 schema_cache_GetTypeInfo,
1326 schema_cache_GetIDsOfNames,
1327 schema_cache_Invoke,
1328 schema_cache_add,
1329 schema_cache_get,
1330 schema_cache_remove,
1331 schema_cache_get_length,
1332 schema_cache_get_namespaceURI,
1333 schema_cache_addCollection,
1334 schema_cache_get__newEnum,
1335 schema_cache_validate,
1336 schema_cache_put_validateOnLoad,
1337 schema_cache_get_validateOnLoad,
1338 schema_cache_getSchema,
1339 schema_cache_getDeclaration
1342 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1344 xmlSchemaElementPtr decl = NULL;
1345 xmlChar const* nsURI = get_node_nsURI(node);
1347 TRACE("(%p, %p)\n", schema, node);
1349 if (xmlStrEqual(nsURI, schema->targetNamespace))
1350 decl = xmlHashLookup(schema->elemDecl, node->name);
1352 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1354 FIXME("declaration not found in main schema - need to check schema imports!\n");
1355 /*xmlSchemaImportPtr import;
1356 if (nsURI == NULL)
1357 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1358 else
1359 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1361 if (import != NULL)
1362 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1365 return decl;
1368 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1370 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1371 while (decl != NULL && decl->refDecl != NULL)
1372 decl = decl->refDecl;
1373 return (decl != NULL)? decl->node : NULL;
1376 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1378 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1379 xmlSchemaPtr schema;
1381 TRACE("(%p, %p)\n", This, tree);
1383 if (!tree)
1384 return E_POINTER;
1386 if (tree->type == XML_DOCUMENT_NODE)
1387 tree = xmlDocGetRootElement(tree->doc);
1389 schema = get_node_schema(This, tree);
1390 /* TODO: if the ns is not in the cache, and it's a URL,
1391 * do we try to load from that? */
1392 if (schema)
1393 return Schema_validate_tree(schema, tree);
1394 else
1395 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1397 return E_FAIL;
1400 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1402 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1403 xmlSchemaPtr schema = get_node_schema(This, node);
1404 XDR_DT dt = DT_INVALID;
1406 TRACE("(%p, %p)\n", This, node);
1408 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1410 dt = str_to_dt(node->name, -1);
1412 else if (schema)
1414 xmlChar* str;
1415 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1417 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1418 if (str)
1420 dt = str_to_dt(str, -1);
1421 xmlFree(str);
1425 return dt;
1428 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* pUnkOuter, void** ppObj)
1430 schema_cache* This = heap_alloc(sizeof(schema_cache));
1431 if (!This)
1432 return E_OUTOFMEMORY;
1434 This->lpVtbl = &schema_cache_vtbl;
1435 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1436 This->ref = 1;
1437 This->version = version;
1439 *ppObj = &This->lpVtbl;
1440 return S_OK;
1443 #else
1445 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* pUnkOuter, void** ppObj)
1447 MESSAGE("This program tried to use a SchemaCache object, but\n"
1448 "libxml2 support was not present at compile time.\n");
1449 return E_NOTIMPL;
1452 #endif