cabinet: Call FCI function pointers explicitly instead of hiding them inside macros.
[wine.git] / dlls / msxml3 / schema.c
blobfa4208dd99cfcde8acfe42087bf7794752480a98
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 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "msxml6.h"
34 #include "wine/debug.h"
36 #include "msxml_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
40 /* We use a chained hashtable, which can hold any number of schemas
41 * TODO: grow/shrink hashtable depending on load factor
42 * TODO: implement read-only where appropriate
45 /* This is just the number of buckets, should be prime */
46 #define DEFAULT_HASHTABLE_SIZE 17
48 #ifdef HAVE_LIBXML2
50 #include <libxml/tree.h>
51 #include <libxml/xmlschemas.h>
52 #include <libxml/schemasInternals.h>
53 #include <libxml/hash.h>
54 #include <libxml/parser.h>
55 #include <libxml/parserInternals.h>
56 #include <libxml/xmlIO.h>
58 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI);
60 static const xmlChar XSD_schema[] = "schema";
61 static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
62 static const xmlChar XDR_schema[] = "Schema";
63 static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
64 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
66 static xmlChar const* datatypes_src = NULL;
67 static int datatypes_len = 0;
68 static HGLOBAL datatypes_handle = NULL;
69 static HRSRC datatypes_rsrc = NULL;
70 static xmlSchemaPtr datatypes_schema = NULL;
72 /* Supported Types:
73 * msxml3 - XDR only
74 * msxml4 - XDR & XSD
75 * msxml5 - XDR & XSD
76 * mxsml6 - XSD only
78 typedef enum _SCHEMA_TYPE {
79 SCHEMA_TYPE_INVALID,
80 SCHEMA_TYPE_XDR,
81 SCHEMA_TYPE_XSD
82 } SCHEMA_TYPE;
84 typedef struct _schema_cache
86 const struct IXMLDOMSchemaCollection2Vtbl* lpVtbl;
87 MSXML_VERSION version;
88 xmlHashTablePtr cache;
89 LONG ref;
90 } schema_cache;
92 typedef struct _cache_entry
94 SCHEMA_TYPE type;
95 xmlSchemaPtr schema;
96 xmlDocPtr doc;
97 LONG ref;
98 } cache_entry;
100 typedef struct _cache_index_data
102 LONG index;
103 BSTR* out;
104 } cache_index_data;
106 /* datatypes lookup stuff
107 * generated with help from gperf */
108 #define DT_MIN_STR_LEN 2
109 #define DT_MAX_STR_LEN 11
110 #define DT_MIN_HASH_VALUE 2
111 #define DT_MAX_HASH_VALUE 115
113 static const xmlChar DT_bin_base64[] = "bin.base64";
114 static const xmlChar DT_bin_hex[] = "bin.hex";
115 static const xmlChar DT_boolean[] = "boolean";
116 static const xmlChar DT_char[] = "char";
117 static const xmlChar DT_date[] = "date";
118 static const xmlChar DT_date_tz[] = "date.tz";
119 static const xmlChar DT_dateTime[] = "dateTime";
120 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
121 static const xmlChar DT_entity[] = "entity";
122 static const xmlChar DT_entities[] = "entities";
123 static const xmlChar DT_enumeration[] = "enumeration";
124 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
125 static const xmlChar DT_float[] = "float";
126 static const xmlChar DT_i1[] = "i1";
127 static const xmlChar DT_i2[] = "i2";
128 static const xmlChar DT_i4[] = "i4";
129 static const xmlChar DT_i8[] = "i8";
130 static const xmlChar DT_id[] = "id";
131 static const xmlChar DT_idref[] = "idref";
132 static const xmlChar DT_idrefs[] = "idrefs";
133 static const xmlChar DT_int[] = "int";
134 static const xmlChar DT_nmtoken[] = "nmtoken";
135 static const xmlChar DT_nmtokens[] = "nmtokens";
136 static const xmlChar DT_notation[] = "notation";
137 static const xmlChar DT_number[] = "number";
138 static const xmlChar DT_r4[] = "r4";
139 static const xmlChar DT_r8[] = "r8";
140 static const xmlChar DT_string[] = "string";
141 static const xmlChar DT_time[] = "time";
142 static const xmlChar DT_time_tz[] = "time.tz";
143 static const xmlChar DT_ui1[] = "ui1";
144 static const xmlChar DT_ui2[] = "ui2";
145 static const xmlChar DT_ui4[] = "ui4";
146 static const xmlChar DT_ui8[] = "ui8";
147 static const xmlChar DT_uri[] = "uri";
148 static const xmlChar DT_uuid[] = "uuid";
150 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
151 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
152 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
153 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
154 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
155 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
156 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
157 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
158 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
159 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
160 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
161 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
162 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
163 static const OLECHAR wDT_i1[] = {'i','1',0};
164 static const OLECHAR wDT_i2[] = {'i','2',0};
165 static const OLECHAR wDT_i4[] = {'i','4',0};
166 static const OLECHAR wDT_i8[] = {'i','8',0};
167 static const OLECHAR wDT_id[] = {'i','d',0};
168 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
169 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
170 static const OLECHAR wDT_int[] = {'i','n','t',0};
171 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
172 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
173 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
174 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
175 static const OLECHAR wDT_r4[] = {'r','4',0};
176 static const OLECHAR wDT_r8[] = {'r','8',0};
177 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
178 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
179 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
180 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
181 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
182 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
183 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
184 static const OLECHAR wDT_uri[] = {'u','r','i',0};
185 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
187 static const BYTE hash_assoc_values[] =
189 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
190 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
191 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
192 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
193 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
194 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
195 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
196 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
197 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
198 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
199 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
200 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
201 0, 0, 10, 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, 116, 116, 116, 116,
204 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
205 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
206 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
207 116, 116, 116, 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
217 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
219 va_list ap;
220 va_start(ap, msg);
221 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
222 va_end(ap);
225 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
227 va_list ap;
228 va_start(ap, msg);
229 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
230 va_end(ap);
233 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
234 static void parser_serror(void* ctx, xmlErrorPtr err)
236 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
238 #endif
240 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
242 TRACE("(%p)\n", spctx);
244 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
245 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
246 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
247 #endif
249 return xmlSchemaParse(spctx);
252 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
254 va_list ap;
255 va_start(ap, msg);
256 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
257 va_end(ap);
260 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
262 va_list ap;
263 va_start(ap, msg);
264 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
265 va_end(ap);
268 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
269 static void validate_serror(void* ctx, xmlErrorPtr err)
271 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
273 #endif
275 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
277 xmlSchemaValidCtxtPtr svctx;
278 int err;
280 TRACE("(%p, %p)\n", schema, tree);
281 /* TODO: if validateOnLoad property is false,
282 * we probably need to validate the schema here. */
283 svctx = xmlSchemaNewValidCtxt(schema);
284 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
285 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
286 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
287 #endif
289 if (tree->type == XML_DOCUMENT_NODE)
290 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
291 else
292 err = xmlSchemaValidateOneElement(svctx, tree);
294 xmlSchemaFreeValidCtxt(svctx);
295 return err? S_FALSE : S_OK;
298 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
300 DWORD hval = (len == -1)? xmlStrlen(str) : len;
302 switch (hval)
304 default:
305 hval += hash_assoc_values[str[10]];
306 /*FALLTHROUGH*/
307 case 10:
308 hval += hash_assoc_values[str[9]];
309 /*FALLTHROUGH*/
310 case 9:
311 hval += hash_assoc_values[str[8]];
312 /*FALLTHROUGH*/
313 case 8:
314 hval += hash_assoc_values[str[7]];
315 /*FALLTHROUGH*/
316 case 7:
317 hval += hash_assoc_values[str[6]];
318 /*FALLTHROUGH*/
319 case 6:
320 hval += hash_assoc_values[str[5]];
321 /*FALLTHROUGH*/
322 case 5:
323 hval += hash_assoc_values[str[4]];
324 /*FALLTHROUGH*/
325 case 4:
326 hval += hash_assoc_values[str[3]];
327 /*FALLTHROUGH*/
328 case 3:
329 hval += hash_assoc_values[str[2]];
330 /*FALLTHROUGH*/
331 case 2:
332 hval += hash_assoc_values[str[1]];
333 /*FALLTHROUGH*/
334 case 1:
335 hval += hash_assoc_values[str[0]];
336 break;
338 return hval;
341 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
343 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
345 switch (hval)
347 default:
348 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
349 /*FALLTHROUGH*/
350 case 10:
351 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
352 /*FALLTHROUGH*/
353 case 9:
354 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
355 /*FALLTHROUGH*/
356 case 8:
357 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
358 /*FALLTHROUGH*/
359 case 7:
360 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
361 /*FALLTHROUGH*/
362 case 6:
363 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
364 /*FALLTHROUGH*/
365 case 5:
366 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
367 /*FALLTHROUGH*/
368 case 4:
369 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
370 /*FALLTHROUGH*/
371 case 3:
372 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
373 /*FALLTHROUGH*/
374 case 2:
375 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
376 /*FALLTHROUGH*/
377 case 1:
378 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
379 break;
381 return hval;
384 static const xmlChar const* DT_string_table[DT__N_TYPES] =
386 DT_bin_base64,
387 DT_bin_hex,
388 DT_boolean,
389 DT_char,
390 DT_date,
391 DT_date_tz,
392 DT_dateTime,
393 DT_dateTime_tz,
394 DT_entity,
395 DT_entities,
396 DT_enumeration,
397 DT_fixed_14_4,
398 DT_float,
399 DT_i1,
400 DT_i2,
401 DT_i4,
402 DT_i8,
403 DT_id,
404 DT_idref,
405 DT_idrefs,
406 DT_int,
407 DT_nmtoken,
408 DT_nmtokens,
409 DT_notation,
410 DT_number,
411 DT_r4,
412 DT_r8,
413 DT_string,
414 DT_time,
415 DT_time_tz,
416 DT_ui1,
417 DT_ui2,
418 DT_ui4,
419 DT_ui8,
420 DT_uri,
421 DT_uuid
424 static const WCHAR const* DT_wstring_table[DT__N_TYPES] =
426 wDT_bin_base64,
427 wDT_bin_hex,
428 wDT_boolean,
429 wDT_char,
430 wDT_date,
431 wDT_date_tz,
432 wDT_dateTime,
433 wDT_dateTime_tz,
434 wDT_entity,
435 wDT_entities,
436 wDT_enumeration,
437 wDT_fixed_14_4,
438 wDT_float,
439 wDT_i1,
440 wDT_i2,
441 wDT_i4,
442 wDT_i8,
443 wDT_id,
444 wDT_idref,
445 wDT_idrefs,
446 wDT_int,
447 wDT_nmtoken,
448 wDT_nmtokens,
449 wDT_notation,
450 wDT_number,
451 wDT_r4,
452 wDT_r8,
453 wDT_string,
454 wDT_time,
455 wDT_time_tz,
456 wDT_ui1,
457 wDT_ui2,
458 wDT_ui4,
459 wDT_ui8,
460 wDT_uri,
461 wDT_uuid
464 static const XDR_DT DT_lookup_table[] =
466 -1, -1,
467 DT_I8,
468 DT_UI8,
469 DT_TIME,
470 -1, -1,
471 DT_I4,
472 DT_UI4,
473 -1, -1, -1,
474 DT_R8,
475 DT_URI,
477 DT_FLOAT,
479 DT_R4,
480 DT_INT,
481 DT_CHAR,
483 DT_ENTITY,
484 DT_ID,
485 DT_ENTITIES,
486 DT_UUID,
487 -1, -1,
488 DT_TIME_TZ,
490 DT_DATE,
492 DT_NUMBER,
493 DT_BIN_HEX,
494 DT_DATETIME,
496 DT_IDREF,
497 DT_IDREFS,
498 DT_BOOLEAN,
499 -1, -1, -1,
500 DT_STRING,
501 DT_NMTOKEN,
502 DT_NMTOKENS,
504 DT_BIN_BASE64,
506 DT_I2,
507 DT_UI2,
508 -1, -1, -1,
509 DT_DATE_TZ,
510 DT_NOTATION,
511 -1, -1,
512 DT_DATETIME_TZ,
513 DT_I1,
514 DT_UI1,
515 -1, -1,
516 DT_ENUMERATION,
517 -1, -1, -1, -1, -1, -1, -1, -1, -1,
518 -1, -1, -1, -1, -1, -1, -1, -1, -1,
519 -1, -1, -1, -1, -1, -1, -1, -1, -1,
520 -1, -1, -1, -1, -1, -1, -1, -1, -1,
521 -1, -1, -1, -1, -1, -1, -1, -1, -1,
522 -1, -1, -1, -1, -1, -1, -1, -1,
523 DT_FIXED_14_4
526 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
528 DWORD hash = dt_hash(str, len);
529 XDR_DT dt = DT_INVALID;
531 if (hash <= DT_MAX_HASH_VALUE)
532 dt = DT_lookup_table[hash];
534 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
535 return dt;
537 return DT_INVALID;
540 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
542 DWORD hash = dt_hash_bstr(bstr, len);
543 XDR_DT dt = DT_INVALID;
545 if (hash <= DT_MAX_HASH_VALUE)
546 dt = DT_lookup_table[hash];
548 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
549 return dt;
551 return DT_INVALID;
554 xmlChar const* dt_to_str(XDR_DT dt)
556 if (dt == DT_INVALID)
557 return NULL;
559 return DT_string_table[dt];
562 OLECHAR const* dt_to_bstr(XDR_DT dt)
564 if (dt == DT_INVALID)
565 return NULL;
567 return DT_wstring_table[dt];
570 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
572 xmlDocPtr tmp_doc;
573 xmlNodePtr node;
574 xmlNsPtr ns;
575 HRESULT hr;
577 TRACE("(dt:%s, %s)\n", dt_to_str(dt), wine_dbgstr_a((char const*)content));
579 if (!datatypes_schema)
581 xmlSchemaParserCtxtPtr spctx;
582 assert(datatypes_src != NULL);
583 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
584 datatypes_schema = Schema_parse(spctx);
585 xmlSchemaFreeParserCtxt(spctx);
588 switch (dt)
590 case DT_INVALID:
591 return E_FAIL;
592 case DT_BIN_BASE64:
593 case DT_BIN_HEX:
594 case DT_BOOLEAN:
595 case DT_CHAR:
596 case DT_DATE:
597 case DT_DATE_TZ:
598 case DT_DATETIME:
599 case DT_DATETIME_TZ:
600 case DT_FIXED_14_4:
601 case DT_FLOAT:
602 case DT_I1:
603 case DT_I2:
604 case DT_I4:
605 case DT_I8:
606 case DT_INT:
607 case DT_NMTOKEN:
608 case DT_NMTOKENS:
609 case DT_NUMBER:
610 case DT_R4:
611 case DT_R8:
612 case DT_STRING:
613 case DT_TIME:
614 case DT_TIME_TZ:
615 case DT_UI1:
616 case DT_UI2:
617 case DT_UI4:
618 case DT_UI8:
619 case DT_URI:
620 case DT_UUID:
621 assert(datatypes_schema != NULL);
622 if (content && xmlStrlen(content))
624 tmp_doc = xmlNewDoc(NULL);
625 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
626 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
627 xmlSetNs(node, ns);
628 xmlDocSetRootElement(tmp_doc, node);
630 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
631 xmlFreeDoc(tmp_doc);
633 else
634 { /* probably the node is being created manually and has no content yet */
635 hr = S_OK;
637 return hr;
638 default:
639 FIXME("need to handle dt:%s\n", dt_to_str(dt));
640 return S_OK;
644 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
646 return (node->ns != NULL)? node->ns->href : NULL;
649 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
651 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
652 xmlHashLookup(This->cache, nsURI);
655 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
657 cache_entry* entry = get_entry(This, get_node_nsURI(node));
658 return (!entry)? NULL : entry->schema;
661 xmlExternalEntityLoader _external_entity_loader = NULL;
663 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
664 xmlParserCtxtPtr ctxt)
666 xmlParserInputPtr input;
668 TRACE("(%s, %s, %p)\n", wine_dbgstr_a(URL), wine_dbgstr_a(ID), ctxt);
670 assert(MSXML_hInstance != NULL);
671 assert(datatypes_rsrc != NULL);
672 assert(datatypes_handle != NULL);
673 assert(datatypes_src != NULL);
675 /* TODO: if the desired schema is in the cache, load it from there */
676 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
678 TRACE("loading built-in schema for %s\n", URL);
679 input = xmlNewStringInputStream(ctxt, datatypes_src);
681 else
683 input = _external_entity_loader(URL, ID, ctxt);
686 return input;
689 void schemasInit(void)
691 int len;
692 char* buf;
693 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
695 FIXME("failed to find resource for %s\n", DT_nsURI);
696 return;
699 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
701 FIXME("failed to load resource for %s\n", DT_nsURI);
702 return;
704 buf = LockResource(datatypes_handle);
705 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
707 /* Resource is loaded as raw data,
708 * need a null-terminated string */
709 while (buf[len] != '>')
710 buf[len--] = 0;
711 datatypes_src = BAD_CAST buf;
712 datatypes_len = len + 1;
714 if ((void*)xmlGetExternalEntityLoader() != (void*)external_entity_loader)
716 _external_entity_loader = xmlGetExternalEntityLoader();
717 xmlSetExternalEntityLoader(external_entity_loader);
721 void schemasCleanup(void)
723 if (datatypes_handle)
724 FreeResource(datatypes_handle);
725 if (datatypes_schema)
726 xmlSchemaFree(datatypes_schema);
727 xmlSetExternalEntityLoader(_external_entity_loader);
730 static LONG cache_entry_add_ref(cache_entry* entry)
732 LONG ref = InterlockedIncrement(&entry->ref);
733 TRACE("%p new ref %d\n", entry, ref);
734 return ref;
737 static LONG cache_entry_release(cache_entry* entry)
739 LONG ref = InterlockedDecrement(&entry->ref);
740 TRACE("%p new ref %d\n", entry, ref);
742 if (ref == 0)
744 if (entry->type == SCHEMA_TYPE_XSD)
746 xmldoc_release(entry->doc);
747 entry->schema->doc = NULL;
748 xmlSchemaFree(entry->schema);
749 heap_free(entry);
751 else /* SCHEMA_TYPE_XDR */
753 xmldoc_release(entry->doc);
754 xmldoc_release(entry->schema->doc);
755 entry->schema->doc = NULL;
756 xmlSchemaFree(entry->schema);
757 heap_free(entry);
760 return ref;
763 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
765 return (schema_cache*)((char*)iface - FIELD_OFFSET(schema_cache, lpVtbl));
768 static inline SCHEMA_TYPE schema_type_from_xmlDocPtr(xmlDocPtr schema)
770 xmlNodePtr root = NULL;
771 if (schema)
772 root = xmlDocGetRootElement(schema);
773 if (root && root->ns)
776 if (xmlStrEqual(root->name, XDR_schema) &&
777 xmlStrEqual(root->ns->href, XDR_nsURI))
779 return SCHEMA_TYPE_XDR;
781 else if (xmlStrEqual(root->name, XSD_schema) &&
782 xmlStrEqual(root->ns->href, XSD_nsURI))
784 return SCHEMA_TYPE_XSD;
787 return SCHEMA_TYPE_INVALID;
790 static BOOL link_datatypes(xmlDocPtr schema)
792 xmlNodePtr root, next, child;
793 xmlNsPtr ns;
795 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
796 root = xmlDocGetRootElement(schema);
797 if (!root)
798 return FALSE;
800 for (ns = root->nsDef; ns != NULL; ns = ns->next)
802 if (xmlStrEqual(ns->href, DT_nsURI))
803 break;
806 if (!ns)
807 return FALSE;
809 next = xmlFirstElementChild(root);
810 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
811 if (next) child = xmlAddPrevSibling(next, child);
812 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
813 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
815 return TRUE;
818 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
820 cache_entry* entry = heap_alloc(sizeof(cache_entry));
821 xmlSchemaParserCtxtPtr spctx;
822 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
824 link_datatypes(new_doc);
826 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
827 * do we need to do something special here? */
828 entry->type = SCHEMA_TYPE_XSD;
829 entry->ref = 0;
830 spctx = xmlSchemaNewDocParserCtxt(new_doc);
832 if ((entry->schema = Schema_parse(spctx)))
834 xmldoc_init(entry->schema->doc, DOMDocument_version(v));
835 entry->doc = entry->schema->doc;
836 xmldoc_add_ref(entry->doc);
838 else
840 FIXME("failed to parse doc\n");
841 xmlFreeDoc(new_doc);
842 heap_free(entry);
843 entry = NULL;
845 xmlSchemaFreeParserCtxt(spctx);
846 return entry;
849 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
851 cache_entry* entry = heap_alloc(sizeof(cache_entry));
852 xmlSchemaParserCtxtPtr spctx;
853 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
855 link_datatypes(xsd_doc);
857 entry->type = SCHEMA_TYPE_XDR;
858 entry->ref = 0;
859 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
861 if ((entry->schema = Schema_parse(spctx)))
863 entry->doc = new_doc;
864 xmldoc_init(entry->schema->doc, DOMDocument_version(v));
865 xmldoc_init(entry->doc, DOMDocument_version(v));
866 xmldoc_add_ref(entry->doc);
867 xmldoc_add_ref(entry->schema->doc);
869 else
871 FIXME("failed to parse doc\n");
872 xmlFreeDoc(new_doc);
873 xmlFreeDoc(xsd_doc);
874 heap_free(entry);
875 entry = NULL;
877 xmlSchemaFreeParserCtxt(spctx);
879 return entry;
882 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION v)
884 cache_entry* entry;
885 IXMLDOMDocument3* domdoc = NULL;
886 xmlDocPtr doc = NULL;
887 HRESULT hr = DOMDocument_create(DOMDocument_version(v), NULL, (void**)&domdoc);
888 VARIANT_BOOL b = VARIANT_FALSE;
889 SCHEMA_TYPE type = SCHEMA_TYPE_INVALID;
891 if (hr != S_OK)
893 FIXME("failed to create domdoc\n");
894 return NULL;
896 assert(domdoc != NULL);
897 assert(V_VT(&url) == VT_BSTR);
899 hr = IXMLDOMDocument3_load(domdoc, url, &b);
900 if (hr != S_OK)
902 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
903 if (b != VARIANT_TRUE)
905 FIXME("Failed to load doc at %s\n", wine_dbgstr_w(V_BSTR(&url)));
906 IXMLDOMDocument3_Release(domdoc);
907 return NULL;
910 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
911 type = schema_type_from_xmlDocPtr(doc);
913 switch (type)
915 case SCHEMA_TYPE_XSD:
916 entry = cache_entry_from_xsd_doc(doc, nsURI, v);
917 break;
918 case SCHEMA_TYPE_XDR:
919 entry = cache_entry_from_xdr_doc(doc, nsURI, v);
920 break;
921 case SCHEMA_TYPE_INVALID:
922 entry = NULL;
923 FIXME("invalid schema\n");
924 break;
926 IXMLDOMDocument3_Release(domdoc);
928 return entry;
931 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
932 REFIID riid, void** ppvObject)
934 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
936 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
938 if ( IsEqualIID(riid, &IID_IUnknown) ||
939 IsEqualIID(riid, &IID_IDispatch) ||
940 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
941 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
943 *ppvObject = iface;
945 else
947 FIXME("interface %s not implemented\n", debugstr_guid(riid));
948 return E_NOINTERFACE;
951 IXMLDOMSchemaCollection2_AddRef(iface);
953 return S_OK;
956 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
958 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
959 LONG ref = InterlockedIncrement(&This->ref);
960 TRACE("%p new ref %d\n", This, ref);
961 return ref;
964 static void cache_free(void* data, xmlChar* name /* ignored */)
966 cache_entry_release((cache_entry*)data);
969 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
971 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
972 LONG ref = InterlockedDecrement(&This->ref);
973 TRACE("%p new ref %d\n", This, ref);
975 if (ref == 0)
977 xmlHashFree(This->cache, cache_free);
978 heap_free(This);
981 return ref;
984 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
985 UINT* pctinfo)
987 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
989 TRACE("(%p)->(%p)\n", This, pctinfo);
991 *pctinfo = 1;
993 return S_OK;
996 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
997 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
999 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1000 HRESULT hr;
1002 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1004 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, ppTInfo);
1006 return hr;
1009 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1010 REFIID riid, LPOLESTR* rgszNames,
1011 UINT cNames, LCID lcid, DISPID* rgDispId)
1013 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1014 ITypeInfo* typeinfo;
1015 HRESULT hr;
1017 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1018 lcid, rgDispId);
1020 if(!rgszNames || cNames == 0 || !rgDispId)
1021 return E_INVALIDARG;
1023 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1024 if(SUCCEEDED(hr))
1026 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1027 ITypeInfo_Release(typeinfo);
1030 return hr;
1033 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1034 DISPID dispIdMember, REFIID riid, LCID lcid,
1035 WORD wFlags, DISPPARAMS* pDispParams,
1036 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1037 UINT* puArgErr)
1039 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1040 ITypeInfo* typeinfo;
1041 HRESULT hr;
1043 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1044 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1046 hr = get_typeinfo(IXMLDOMSchemaCollection_tid, &typeinfo);
1047 if(SUCCEEDED(hr))
1049 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1050 pVarResult, pExcepInfo, puArgErr);
1051 ITypeInfo_Release(typeinfo);
1054 return hr;
1057 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1059 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1060 xmlChar* name = xmlChar_from_wchar(uri);
1061 TRACE("(%p)->(%s, var(vt %x))\n", This, debugstr_w(uri), V_VT(&var));
1063 switch (V_VT(&var))
1065 case VT_NULL:
1067 xmlHashRemoveEntry(This->cache, name, cache_free);
1069 break;
1071 case VT_BSTR:
1073 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1075 if (entry)
1077 cache_entry_add_ref(entry);
1079 else
1081 heap_free(name);
1082 return E_FAIL;
1085 xmlHashRemoveEntry(This->cache, name, cache_free);
1086 xmlHashAddEntry(This->cache, name, entry);
1088 break;
1090 case VT_DISPATCH:
1092 xmlDocPtr doc = NULL;
1093 cache_entry* entry;
1094 SCHEMA_TYPE type;
1095 IXMLDOMNode* domnode = NULL;
1096 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1098 if (domnode)
1099 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1101 if (!doc)
1103 IXMLDOMNode_Release(domnode);
1104 heap_free(name);
1105 return E_INVALIDARG;
1107 type = schema_type_from_xmlDocPtr(doc);
1109 if (type == SCHEMA_TYPE_XSD)
1111 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1113 else if (type == SCHEMA_TYPE_XDR)
1115 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1117 else
1119 WARN("invalid schema!\n");
1120 entry = NULL;
1123 IXMLDOMNode_Release(domnode);
1125 if (entry)
1127 cache_entry_add_ref(entry);
1129 else
1131 heap_free(name);
1132 return E_FAIL;
1135 xmlHashRemoveEntry(This->cache, name, cache_free);
1136 xmlHashAddEntry(This->cache, name, entry);
1138 break;
1140 default:
1142 heap_free(name);
1143 return E_INVALIDARG;
1146 heap_free(name);
1147 return S_OK;
1150 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1151 IXMLDOMNode** node)
1153 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1154 xmlChar* name;
1155 cache_entry* entry;
1156 TRACE("(%p)->(%s, %p)\n", This, wine_dbgstr_w(uri), node);
1158 if (!node)
1159 return E_POINTER;
1161 name = xmlChar_from_wchar(uri);
1162 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1163 heap_free(name);
1165 /* TODO: this should be read-only */
1166 if (entry)
1167 return DOMDocument_create_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1169 *node = NULL;
1170 return S_OK;
1173 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1175 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1176 xmlChar* name = xmlChar_from_wchar(uri);
1177 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(uri));
1179 xmlHashRemoveEntry(This->cache, name, cache_free);
1180 heap_free(name);
1181 return S_OK;
1184 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1186 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1187 TRACE("(%p)->(%p)\n", This, length);
1189 if (!length)
1190 return E_POINTER;
1191 *length = xmlHashSize(This->cache);
1192 return S_OK;
1195 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1197 cache_index_data* index_data = (cache_index_data*)index;
1199 if (index_data->index-- == 0)
1200 *index_data->out = bstr_from_xmlChar(name);
1203 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1204 LONG index, BSTR* len)
1206 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1207 cache_index_data data = {index,len};
1208 TRACE("(%p)->(%i, %p)\n", This, index, len);
1210 if (!len)
1211 return E_POINTER;
1212 *len = NULL;
1214 if (index >= xmlHashSize(This->cache))
1215 return E_FAIL;
1217 xmlHashScan(This->cache, cache_index, &data);
1218 return S_OK;
1221 static void cache_copy(void* data, void* dest, xmlChar* name)
1223 schema_cache* This = (schema_cache*) dest;
1224 cache_entry* entry = (cache_entry*) data;
1226 if (xmlHashLookup(This->cache, name) == NULL)
1228 cache_entry_add_ref(entry);
1229 xmlHashAddEntry(This->cache, name, entry);
1233 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1234 IXMLDOMSchemaCollection* otherCollection)
1236 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1237 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1238 TRACE("(%p)->(%p)\n", This, That);
1240 if (!otherCollection)
1241 return E_POINTER;
1243 /* TODO: detect errors while copying & return E_FAIL */
1244 xmlHashScan(That->cache, cache_copy, This);
1246 return S_OK;
1249 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1250 IUnknown** ppUnk)
1252 FIXME("stub\n");
1253 if (ppUnk)
1254 *ppUnk = NULL;
1255 return E_NOTIMPL;
1258 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1260 FIXME("stub\n");
1261 return E_NOTIMPL;
1264 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1265 VARIANT_BOOL validateOnLoad)
1267 FIXME("stub\n");
1268 return E_NOTIMPL;
1271 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1272 VARIANT_BOOL* validateOnLoad)
1274 FIXME("stub\n");
1275 return E_NOTIMPL;
1278 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1279 BSTR namespaceURI, ISchema** schema)
1281 FIXME("stub\n");
1282 if (schema)
1283 *schema = NULL;
1284 return E_NOTIMPL;
1287 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1288 IXMLDOMNode* node, ISchemaItem** item)
1290 FIXME("stub\n");
1291 if (item)
1292 *item = NULL;
1293 return E_NOTIMPL;
1296 static const struct IXMLDOMSchemaCollection2Vtbl schema_cache_vtbl =
1298 schema_cache_QueryInterface,
1299 schema_cache_AddRef,
1300 schema_cache_Release,
1301 schema_cache_GetTypeInfoCount,
1302 schema_cache_GetTypeInfo,
1303 schema_cache_GetIDsOfNames,
1304 schema_cache_Invoke,
1305 schema_cache_add,
1306 schema_cache_get,
1307 schema_cache_remove,
1308 schema_cache_get_length,
1309 schema_cache_get_namespaceURI,
1310 schema_cache_addCollection,
1311 schema_cache_get__newEnum,
1312 schema_cache_validate,
1313 schema_cache_put_validateOnLoad,
1314 schema_cache_get_validateOnLoad,
1315 schema_cache_getSchema,
1316 schema_cache_getDeclaration
1319 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1321 xmlSchemaElementPtr decl = NULL;
1322 xmlChar const* nsURI = get_node_nsURI(node);
1324 TRACE("(%p, %p)\n", schema, node);
1326 if (xmlStrEqual(nsURI, schema->targetNamespace))
1327 decl = xmlHashLookup(schema->elemDecl, node->name);
1329 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1331 FIXME("declaration not found in main schema - need to check schema imports!\n");
1332 /*xmlSchemaImportPtr import;
1333 if (nsURI == NULL)
1334 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1335 else
1336 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1338 if (import != NULL)
1339 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1342 return decl;
1345 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1347 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1348 while (decl != NULL && decl->refDecl != NULL)
1349 decl = decl->refDecl;
1350 return (decl != NULL)? decl->node : NULL;
1353 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1355 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1356 xmlSchemaPtr schema;
1358 TRACE("(%p, %p)\n", This, tree);
1360 if (!tree)
1361 return E_POINTER;
1363 if (tree->type == XML_DOCUMENT_NODE)
1364 tree = xmlDocGetRootElement(tree->doc);
1366 schema = get_node_schema(This, tree);
1367 /* TODO: if the ns is not in the cache, and it's a URL,
1368 * do we try to load from that? */
1369 if (schema)
1370 return Schema_validate_tree(schema, tree);
1371 else
1372 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1374 return E_FAIL;
1377 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1379 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1380 xmlSchemaPtr schema = get_node_schema(This, node);
1381 XDR_DT dt = DT_INVALID;
1383 TRACE("(%p, %p)\n", This, node);
1385 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1387 dt = str_to_dt(node->name, -1);
1389 else if (schema)
1391 xmlChar* str;
1392 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1394 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1395 if (str)
1397 dt = str_to_dt(str, -1);
1398 xmlFree(str);
1402 return dt;
1405 HRESULT SchemaCache_create(const GUID *clsid, IUnknown* pUnkOuter, void** ppObj)
1407 schema_cache* This = heap_alloc(sizeof(schema_cache));
1408 if (!This)
1409 return E_OUTOFMEMORY;
1411 This->lpVtbl = &schema_cache_vtbl;
1412 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1413 This->ref = 1;
1415 if (IsEqualCLSID(clsid, &CLSID_XMLSchemaCache30))
1416 This->version = MSXML3;
1417 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument40))
1418 This->version = MSXML4;
1419 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument60))
1420 This->version = MSXML6;
1421 else
1422 This->version = MSXML_DEFAULT;
1424 *ppObj = &This->lpVtbl;
1425 return S_OK;
1428 #else
1430 HRESULT SchemaCache_create(const GUID *clsid, IUnknown* pUnkOuter, void** ppObj)
1432 MESSAGE("This program tried to use a SchemaCache object, but\n"
1433 "libxml2 support was not present at compile time.\n");
1434 return E_NOTIMPL;
1437 #endif