msxml3: Move string conversion helper to header.
[wine.git] / dlls / msxml3 / schema.c
blobc13bc27b3a016493d2a3228e6f2dcc7197c98e10
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/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/tree.h>
32 # include <libxml/xmlschemas.h>
33 # include <libxml/schemasInternals.h>
34 # include <libxml/hash.h>
35 # include <libxml/parser.h>
36 # include <libxml/parserInternals.h>
37 # include <libxml/xmlIO.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 assert(datatypes_schema != NULL);
628 if (content && xmlStrlen(content))
630 tmp_doc = xmlNewDoc(NULL);
631 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
632 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
633 xmlSetNs(node, ns);
634 xmlDocSetRootElement(tmp_doc, node);
636 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
637 xmlFreeDoc(tmp_doc);
639 else
640 { /* probably the node is being created manually and has no content yet */
641 hr = S_OK;
643 return hr;
644 default:
645 FIXME("need to handle dt:%s\n", dt_to_str(dt));
646 return S_OK;
650 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
652 return (node->ns != NULL)? node->ns->href : NULL;
655 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
657 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
658 xmlHashLookup(This->cache, nsURI);
661 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
663 cache_entry* entry = get_entry(This, get_node_nsURI(node));
664 return (!entry)? NULL : entry->schema;
667 static xmlExternalEntityLoader _external_entity_loader;
669 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
670 xmlParserCtxtPtr ctxt)
672 xmlParserInputPtr input;
674 TRACE("(%s, %s, %p)\n", wine_dbgstr_a(URL), wine_dbgstr_a(ID), ctxt);
676 assert(MSXML_hInstance != NULL);
677 assert(datatypes_rsrc != NULL);
678 assert(datatypes_handle != NULL);
679 assert(datatypes_src != NULL);
681 /* TODO: if the desired schema is in the cache, load it from there */
682 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
684 TRACE("loading built-in schema for %s\n", URL);
685 input = xmlNewStringInputStream(ctxt, datatypes_src);
687 else
689 input = _external_entity_loader(URL, ID, ctxt);
692 return input;
695 void schemasInit(void)
697 int len;
698 char* buf;
699 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
701 FIXME("failed to find resource for %s\n", DT_nsURI);
702 return;
705 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
707 FIXME("failed to load resource for %s\n", DT_nsURI);
708 return;
710 buf = LockResource(datatypes_handle);
711 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
713 /* Resource is loaded as raw data,
714 * need a null-terminated string */
715 while (buf[len] != '>')
716 buf[len--] = 0;
717 datatypes_src = BAD_CAST buf;
718 datatypes_len = len + 1;
720 if (xmlGetExternalEntityLoader() != external_entity_loader)
722 _external_entity_loader = xmlGetExternalEntityLoader();
723 xmlSetExternalEntityLoader(external_entity_loader);
727 void schemasCleanup(void)
729 xmlSchemaFree(datatypes_schema);
730 xmlSetExternalEntityLoader(_external_entity_loader);
733 static LONG cache_entry_add_ref(cache_entry* entry)
735 LONG ref = InterlockedIncrement(&entry->ref);
736 TRACE("%p new ref %d\n", entry, ref);
737 return ref;
740 static LONG cache_entry_release(cache_entry* entry)
742 LONG ref = InterlockedDecrement(&entry->ref);
743 TRACE("%p new ref %d\n", entry, ref);
745 if (ref == 0)
747 if (entry->type == SCHEMA_TYPE_XSD)
749 xmldoc_release(entry->doc);
750 entry->schema->doc = NULL;
751 xmlSchemaFree(entry->schema);
752 heap_free(entry);
754 else /* SCHEMA_TYPE_XDR */
756 xmldoc_release(entry->doc);
757 xmldoc_release(entry->schema->doc);
758 entry->schema->doc = NULL;
759 xmlSchemaFree(entry->schema);
760 heap_free(entry);
763 return ref;
766 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
768 return (schema_cache*)((char*)iface - FIELD_OFFSET(schema_cache, lpVtbl));
771 static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
773 xmlNodePtr root = NULL;
774 if (schema)
775 root = xmlDocGetRootElement(schema);
776 if (root && root->ns)
779 if (xmlStrEqual(root->name, XDR_schema) &&
780 xmlStrEqual(root->ns->href, XDR_nsURI))
782 return SCHEMA_TYPE_XDR;
784 else if (xmlStrEqual(root->name, XSD_schema) &&
785 xmlStrEqual(root->ns->href, XSD_nsURI))
787 return SCHEMA_TYPE_XSD;
790 return SCHEMA_TYPE_INVALID;
793 static BOOL link_datatypes(xmlDocPtr schema)
795 xmlNodePtr root, next, child;
796 xmlNsPtr ns;
798 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
799 root = xmlDocGetRootElement(schema);
800 if (!root)
801 return FALSE;
803 for (ns = root->nsDef; ns != NULL; ns = ns->next)
805 if (xmlStrEqual(ns->href, DT_nsURI))
806 break;
809 if (!ns)
810 return FALSE;
812 next = xmlFirstElementChild(root);
813 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
814 if (next) child = xmlAddPrevSibling(next, child);
815 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
816 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
818 return TRUE;
821 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
823 cache_entry* entry = heap_alloc(sizeof(cache_entry));
824 xmlSchemaParserCtxtPtr spctx;
825 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
827 link_datatypes(new_doc);
829 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
830 * do we need to do something special here? */
831 entry->type = SCHEMA_TYPE_XSD;
832 entry->ref = 0;
833 spctx = xmlSchemaNewDocParserCtxt(new_doc);
835 if ((entry->schema = Schema_parse(spctx)))
837 xmldoc_init(entry->schema->doc, DOMDocument_version(v));
838 entry->doc = entry->schema->doc;
839 xmldoc_add_ref(entry->doc);
841 else
843 FIXME("failed to parse doc\n");
844 xmlFreeDoc(new_doc);
845 heap_free(entry);
846 entry = NULL;
848 xmlSchemaFreeParserCtxt(spctx);
849 return entry;
852 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
854 cache_entry* entry = heap_alloc(sizeof(cache_entry));
855 xmlSchemaParserCtxtPtr spctx;
856 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
858 link_datatypes(xsd_doc);
860 entry->type = SCHEMA_TYPE_XDR;
861 entry->ref = 0;
862 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
864 if ((entry->schema = Schema_parse(spctx)))
866 entry->doc = new_doc;
867 xmldoc_init(entry->schema->doc, DOMDocument_version(v));
868 xmldoc_init(entry->doc, DOMDocument_version(v));
869 xmldoc_add_ref(entry->doc);
870 xmldoc_add_ref(entry->schema->doc);
872 else
874 FIXME("failed to parse doc\n");
875 xmlFreeDoc(new_doc);
876 xmlFreeDoc(xsd_doc);
877 heap_free(entry);
878 entry = NULL;
880 xmlSchemaFreeParserCtxt(spctx);
882 return entry;
885 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION v)
887 cache_entry* entry;
888 IXMLDOMDocument3* domdoc = NULL;
889 xmlDocPtr doc = NULL;
890 HRESULT hr = DOMDocument_create(DOMDocument_version(v), NULL, (void**)&domdoc);
891 VARIANT_BOOL b = VARIANT_FALSE;
892 SCHEMA_TYPE type = SCHEMA_TYPE_INVALID;
894 if (hr != S_OK)
896 FIXME("failed to create domdoc\n");
897 return NULL;
899 assert(domdoc != NULL);
900 assert(V_VT(&url) == VT_BSTR);
902 hr = IXMLDOMDocument3_load(domdoc, url, &b);
903 if (hr != S_OK)
905 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
906 if (b != VARIANT_TRUE)
908 FIXME("Failed to load doc at %s\n", wine_dbgstr_w(V_BSTR(&url)));
909 IXMLDOMDocument3_Release(domdoc);
910 return NULL;
913 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
914 type = schema_type_from_xmlDocPtr(doc);
916 switch (type)
918 case SCHEMA_TYPE_XSD:
919 entry = cache_entry_from_xsd_doc(doc, nsURI, v);
920 break;
921 case SCHEMA_TYPE_XDR:
922 entry = cache_entry_from_xdr_doc(doc, nsURI, v);
923 break;
924 case SCHEMA_TYPE_INVALID:
925 entry = NULL;
926 FIXME("invalid schema\n");
927 break;
929 IXMLDOMDocument3_Release(domdoc);
931 return entry;
934 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
935 REFIID riid, void** ppvObject)
937 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
939 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
941 if ( IsEqualIID(riid, &IID_IUnknown) ||
942 IsEqualIID(riid, &IID_IDispatch) ||
943 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
944 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
946 *ppvObject = iface;
948 else
950 FIXME("interface %s not implemented\n", debugstr_guid(riid));
951 *ppvObject = NULL;
952 return E_NOINTERFACE;
955 IXMLDOMSchemaCollection2_AddRef(iface);
957 return S_OK;
960 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
962 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
963 LONG ref = InterlockedIncrement(&This->ref);
964 TRACE("%p new ref %d\n", This, ref);
965 return ref;
968 static void cache_free(void* data, xmlChar* name /* ignored */)
970 cache_entry_release((cache_entry*)data);
973 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
975 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
976 LONG ref = InterlockedDecrement(&This->ref);
977 TRACE("%p new ref %d\n", This, ref);
979 if (ref == 0)
981 xmlHashFree(This->cache, cache_free);
982 heap_free(This);
985 return ref;
988 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
989 UINT* pctinfo)
991 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
993 TRACE("(%p)->(%p)\n", This, pctinfo);
995 *pctinfo = 1;
997 return S_OK;
1000 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1001 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1003 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1004 HRESULT hr;
1006 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1008 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, ppTInfo);
1010 return hr;
1013 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1014 REFIID riid, LPOLESTR* rgszNames,
1015 UINT cNames, LCID lcid, DISPID* rgDispId)
1017 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1018 ITypeInfo* typeinfo;
1019 HRESULT hr;
1021 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1022 lcid, rgDispId);
1024 if(!rgszNames || cNames == 0 || !rgDispId)
1025 return E_INVALIDARG;
1027 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1028 if(SUCCEEDED(hr))
1030 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1031 ITypeInfo_Release(typeinfo);
1034 return hr;
1037 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1038 DISPID dispIdMember, REFIID riid, LCID lcid,
1039 WORD wFlags, DISPPARAMS* pDispParams,
1040 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1041 UINT* puArgErr)
1043 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1044 ITypeInfo* typeinfo;
1045 HRESULT hr;
1047 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1048 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1050 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1051 if(SUCCEEDED(hr))
1053 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1054 pVarResult, pExcepInfo, puArgErr);
1055 ITypeInfo_Release(typeinfo);
1058 return hr;
1061 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1063 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1064 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1065 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1067 switch (V_VT(&var))
1069 case VT_NULL:
1071 xmlHashRemoveEntry(This->cache, name, cache_free);
1073 break;
1075 case VT_BSTR:
1077 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1079 if (entry)
1081 cache_entry_add_ref(entry);
1083 else
1085 heap_free(name);
1086 return E_FAIL;
1089 xmlHashRemoveEntry(This->cache, name, cache_free);
1090 xmlHashAddEntry(This->cache, name, entry);
1092 break;
1094 case VT_DISPATCH:
1096 xmlDocPtr doc = NULL;
1097 cache_entry* entry;
1098 SCHEMA_TYPE type;
1099 IXMLDOMNode* domnode = NULL;
1100 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1102 if (domnode)
1103 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1105 if (!doc)
1107 IXMLDOMNode_Release(domnode);
1108 heap_free(name);
1109 return E_INVALIDARG;
1111 type = schema_type_from_xmlDocPtr(doc);
1113 if (type == SCHEMA_TYPE_XSD)
1115 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1117 else if (type == SCHEMA_TYPE_XDR)
1119 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1121 else
1123 WARN("invalid schema!\n");
1124 entry = NULL;
1127 IXMLDOMNode_Release(domnode);
1129 if (entry)
1131 cache_entry_add_ref(entry);
1133 else
1135 heap_free(name);
1136 return E_FAIL;
1139 xmlHashRemoveEntry(This->cache, name, cache_free);
1140 xmlHashAddEntry(This->cache, name, entry);
1142 break;
1144 default:
1146 heap_free(name);
1147 return E_INVALIDARG;
1150 heap_free(name);
1151 return S_OK;
1154 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1155 IXMLDOMNode** node)
1157 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1158 xmlChar* name;
1159 cache_entry* entry;
1160 TRACE("(%p)->(%s, %p)\n", This, wine_dbgstr_w(uri), node);
1162 if (!node)
1163 return E_POINTER;
1165 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1166 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1167 heap_free(name);
1169 /* TODO: this should be read-only */
1170 if (entry)
1171 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1173 *node = NULL;
1174 return S_OK;
1177 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1179 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1180 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1181 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(uri));
1183 xmlHashRemoveEntry(This->cache, name, cache_free);
1184 heap_free(name);
1185 return S_OK;
1188 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1190 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1191 TRACE("(%p)->(%p)\n", This, length);
1193 if (!length)
1194 return E_POINTER;
1195 *length = xmlHashSize(This->cache);
1196 return S_OK;
1199 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1201 cache_index_data* index_data = (cache_index_data*)index;
1203 if (index_data->index-- == 0)
1204 *index_data->out = bstr_from_xmlChar(name);
1207 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1208 LONG index, BSTR* len)
1210 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1211 cache_index_data data = {index,len};
1212 TRACE("(%p)->(%i, %p)\n", This, index, len);
1214 if (!len)
1215 return E_POINTER;
1216 *len = NULL;
1218 if (index >= xmlHashSize(This->cache))
1219 return E_FAIL;
1221 xmlHashScan(This->cache, cache_index, &data);
1222 return S_OK;
1225 static void cache_copy(void* data, void* dest, xmlChar* name)
1227 schema_cache* This = (schema_cache*) dest;
1228 cache_entry* entry = (cache_entry*) data;
1230 if (xmlHashLookup(This->cache, name) == NULL)
1232 cache_entry_add_ref(entry);
1233 xmlHashAddEntry(This->cache, name, entry);
1237 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1238 IXMLDOMSchemaCollection* otherCollection)
1240 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1241 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1242 TRACE("(%p)->(%p)\n", This, That);
1244 if (!otherCollection)
1245 return E_POINTER;
1247 /* TODO: detect errors while copying & return E_FAIL */
1248 xmlHashScan(That->cache, cache_copy, This);
1250 return S_OK;
1253 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1254 IUnknown** ppUnk)
1256 FIXME("stub\n");
1257 if (ppUnk)
1258 *ppUnk = NULL;
1259 return E_NOTIMPL;
1262 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1264 FIXME("stub\n");
1265 return E_NOTIMPL;
1268 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1269 VARIANT_BOOL validateOnLoad)
1271 FIXME("stub\n");
1272 return E_NOTIMPL;
1275 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1276 VARIANT_BOOL* validateOnLoad)
1278 FIXME("stub\n");
1279 return E_NOTIMPL;
1282 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1283 BSTR namespaceURI, ISchema** schema)
1285 FIXME("stub\n");
1286 if (schema)
1287 *schema = NULL;
1288 return E_NOTIMPL;
1291 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1292 IXMLDOMNode* node, ISchemaItem** item)
1294 FIXME("stub\n");
1295 if (item)
1296 *item = NULL;
1297 return E_NOTIMPL;
1300 static const struct IXMLDOMSchemaCollection2Vtbl schema_cache_vtbl =
1302 schema_cache_QueryInterface,
1303 schema_cache_AddRef,
1304 schema_cache_Release,
1305 schema_cache_GetTypeInfoCount,
1306 schema_cache_GetTypeInfo,
1307 schema_cache_GetIDsOfNames,
1308 schema_cache_Invoke,
1309 schema_cache_add,
1310 schema_cache_get,
1311 schema_cache_remove,
1312 schema_cache_get_length,
1313 schema_cache_get_namespaceURI,
1314 schema_cache_addCollection,
1315 schema_cache_get__newEnum,
1316 schema_cache_validate,
1317 schema_cache_put_validateOnLoad,
1318 schema_cache_get_validateOnLoad,
1319 schema_cache_getSchema,
1320 schema_cache_getDeclaration
1323 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1325 xmlSchemaElementPtr decl = NULL;
1326 xmlChar const* nsURI = get_node_nsURI(node);
1328 TRACE("(%p, %p)\n", schema, node);
1330 if (xmlStrEqual(nsURI, schema->targetNamespace))
1331 decl = xmlHashLookup(schema->elemDecl, node->name);
1333 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1335 FIXME("declaration not found in main schema - need to check schema imports!\n");
1336 /*xmlSchemaImportPtr import;
1337 if (nsURI == NULL)
1338 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1339 else
1340 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1342 if (import != NULL)
1343 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1346 return decl;
1349 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1351 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1352 while (decl != NULL && decl->refDecl != NULL)
1353 decl = decl->refDecl;
1354 return (decl != NULL)? decl->node : NULL;
1357 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1359 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1360 xmlSchemaPtr schema;
1362 TRACE("(%p, %p)\n", This, tree);
1364 if (!tree)
1365 return E_POINTER;
1367 if (tree->type == XML_DOCUMENT_NODE)
1368 tree = xmlDocGetRootElement(tree->doc);
1370 schema = get_node_schema(This, tree);
1371 /* TODO: if the ns is not in the cache, and it's a URL,
1372 * do we try to load from that? */
1373 if (schema)
1374 return Schema_validate_tree(schema, tree);
1375 else
1376 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1378 return E_FAIL;
1381 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1383 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1384 xmlSchemaPtr schema = get_node_schema(This, node);
1385 XDR_DT dt = DT_INVALID;
1387 TRACE("(%p, %p)\n", This, node);
1389 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1391 dt = str_to_dt(node->name, -1);
1393 else if (schema)
1395 xmlChar* str;
1396 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1398 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1399 if (str)
1401 dt = str_to_dt(str, -1);
1402 xmlFree(str);
1406 return dt;
1409 HRESULT SchemaCache_create(const GUID *clsid, IUnknown* pUnkOuter, void** ppObj)
1411 schema_cache* This = heap_alloc(sizeof(schema_cache));
1412 if (!This)
1413 return E_OUTOFMEMORY;
1415 This->lpVtbl = &schema_cache_vtbl;
1416 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1417 This->ref = 1;
1419 if (IsEqualCLSID(clsid, &CLSID_XMLSchemaCache30))
1420 This->version = MSXML3;
1421 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument40))
1422 This->version = MSXML4;
1423 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument60))
1424 This->version = MSXML6;
1425 else
1426 This->version = MSXML_DEFAULT;
1428 *ppObj = &This->lpVtbl;
1429 return S_OK;
1432 #else
1434 HRESULT SchemaCache_create(const GUID *clsid, 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