dbghelp: Fix a couple of traces in dwarf line info parsing.
[wine/multimedia.git] / dlls / msxml3 / schema.c
blob253f901b85caf484578add56134df56bcdba0c04
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 # include <libxml/xpath.h>
39 #endif
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winuser.h"
44 #include "ole2.h"
45 #include "msxml6.h"
47 #include "wine/debug.h"
49 #include "msxml_private.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
53 /* We use a chained hashtable, which can hold any number of schemas
54 * TODO: grow/shrink hashtable depending on load factor
55 * TODO: implement read-only where appropriate
58 /* This is just the number of buckets, should be prime */
59 #define DEFAULT_HASHTABLE_SIZE 17
61 #ifdef HAVE_LIBXML2
63 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI);
65 static const xmlChar XSD_schema[] = "schema";
66 static const xmlChar XSD_nsURI[] = "http://www.w3.org/2001/XMLSchema";
67 static const xmlChar XDR_schema[] = "Schema";
68 static const xmlChar XDR_nsURI[] = "urn:schemas-microsoft-com:xml-data";
69 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
71 static xmlChar const* datatypes_src;
72 static int datatypes_len;
73 static HGLOBAL datatypes_handle;
74 static HRSRC datatypes_rsrc;
75 static xmlSchemaPtr datatypes_schema;
77 static const WCHAR emptyW[] = {0};
79 /* Supported types:
80 * msxml3 - XDR only
81 * msxml4 - XDR & XSD
82 * msxml5 - XDR & XSD
83 * mxsml6 - XSD only
85 * CacheType_NS is a special type used for read-only collection build with
86 * IXMLDOMDocument2::namespaces()
88 typedef enum {
89 CacheEntryType_Invalid,
90 CacheEntryType_XDR,
91 CacheEntryType_XSD,
92 CacheEntryType_NS
93 } CacheEntryType;
95 typedef struct
97 DispatchEx dispex;
98 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface;
99 LONG ref;
101 MSXML_VERSION version;
102 xmlHashTablePtr cache;
104 VARIANT_BOOL validateOnLoad;
105 int read_only;
106 } schema_cache;
108 typedef struct
110 CacheEntryType type;
111 xmlSchemaPtr schema;
112 xmlDocPtr doc;
113 LONG ref;
114 } cache_entry;
116 typedef struct
118 LONG index;
119 BSTR* out;
120 } cache_index_data;
122 /* datatypes lookup stuff
123 * generated with help from gperf */
124 #define DT_MIN_STR_LEN 2
125 #define DT_MAX_STR_LEN 11
126 #define DT_MIN_HASH_VALUE 2
127 #define DT_MAX_HASH_VALUE 115
129 static const xmlChar DT_bin_base64[] = "bin.base64";
130 static const xmlChar DT_bin_hex[] = "bin.hex";
131 static const xmlChar DT_boolean[] = "boolean";
132 static const xmlChar DT_char[] = "char";
133 static const xmlChar DT_date[] = "date";
134 static const xmlChar DT_date_tz[] = "date.tz";
135 static const xmlChar DT_dateTime[] = "dateTime";
136 static const xmlChar DT_dateTime_tz[] = "dateTime.tz";
137 static const xmlChar DT_entity[] = "entity";
138 static const xmlChar DT_entities[] = "entities";
139 static const xmlChar DT_enumeration[] = "enumeration";
140 static const xmlChar DT_fixed_14_4[] = "fixed.14.4";
141 static const xmlChar DT_float[] = "float";
142 static const xmlChar DT_i1[] = "i1";
143 static const xmlChar DT_i2[] = "i2";
144 static const xmlChar DT_i4[] = "i4";
145 static const xmlChar DT_i8[] = "i8";
146 static const xmlChar DT_id[] = "id";
147 static const xmlChar DT_idref[] = "idref";
148 static const xmlChar DT_idrefs[] = "idrefs";
149 static const xmlChar DT_int[] = "int";
150 static const xmlChar DT_nmtoken[] = "nmtoken";
151 static const xmlChar DT_nmtokens[] = "nmtokens";
152 static const xmlChar DT_notation[] = "notation";
153 static const xmlChar DT_number[] = "number";
154 static const xmlChar DT_r4[] = "r4";
155 static const xmlChar DT_r8[] = "r8";
156 static const xmlChar DT_string[] = "string";
157 static const xmlChar DT_time[] = "time";
158 static const xmlChar DT_time_tz[] = "time.tz";
159 static const xmlChar DT_ui1[] = "ui1";
160 static const xmlChar DT_ui2[] = "ui2";
161 static const xmlChar DT_ui4[] = "ui4";
162 static const xmlChar DT_ui8[] = "ui8";
163 static const xmlChar DT_uri[] = "uri";
164 static const xmlChar DT_uuid[] = "uuid";
166 static const OLECHAR wDT_bin_base64[] = {'b','i','n','.','b','a','s','e','6','4',0};
167 static const OLECHAR wDT_bin_hex[] = {'b','i','n','.','h','e','x',0};
168 static const OLECHAR wDT_boolean[] = {'b','o','o','l','e','a','n',0};
169 static const OLECHAR wDT_char[] = {'c','h','a','r',0};
170 static const OLECHAR wDT_date[] = {'d','a','t','e',0};
171 static const OLECHAR wDT_date_tz[] = {'d','a','t','e','.','t','z',0};
172 static const OLECHAR wDT_dateTime[] = {'d','a','t','e','T','i','m','e',0};
173 static const OLECHAR wDT_dateTime_tz[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
174 static const OLECHAR wDT_entity[] = {'e','n','t','i','t','y',0};
175 static const OLECHAR wDT_entities[] = {'e','n','t','i','t','i','e','s',0};
176 static const OLECHAR wDT_enumeration[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
177 static const OLECHAR wDT_fixed_14_4[] = {'f','i','x','e','d','.','1','4','.','4',0};
178 static const OLECHAR wDT_float[] = {'f','l','o','a','t',0};
179 static const OLECHAR wDT_i1[] = {'i','1',0};
180 static const OLECHAR wDT_i2[] = {'i','2',0};
181 static const OLECHAR wDT_i4[] = {'i','4',0};
182 static const OLECHAR wDT_i8[] = {'i','8',0};
183 static const OLECHAR wDT_id[] = {'i','d',0};
184 static const OLECHAR wDT_idref[] = {'i','d','r','e','f',0};
185 static const OLECHAR wDT_idrefs[] = {'i','d','r','e','f','s',0};
186 static const OLECHAR wDT_int[] = {'i','n','t',0};
187 static const OLECHAR wDT_nmtoken[] = {'n','m','t','o','k','e','n',0};
188 static const OLECHAR wDT_nmtokens[] = {'n','m','t','o','k','e','n','s',0};
189 static const OLECHAR wDT_notation[] = {'n','o','t','a','t','i','o','n',0};
190 static const OLECHAR wDT_number[] = {'n','u','m','b','e','r',0};
191 static const OLECHAR wDT_r4[] = {'r','4',0};
192 static const OLECHAR wDT_r8[] = {'r','8',0};
193 static const OLECHAR wDT_string[] = {'s','t','r','i','n','g',0};
194 static const OLECHAR wDT_time[] = {'t','i','m','e',0};
195 static const OLECHAR wDT_time_tz[] = {'t','i','m','e','.','t','z',0};
196 static const OLECHAR wDT_ui1[] = {'u','i','1',0};
197 static const OLECHAR wDT_ui2[] = {'u','i','2',0};
198 static const OLECHAR wDT_ui4[] = {'u','i','4',0};
199 static const OLECHAR wDT_ui8[] = {'u','i','8',0};
200 static const OLECHAR wDT_uri[] = {'u','r','i',0};
201 static const OLECHAR wDT_uuid[] = {'u','u','i','d',0};
203 static const BYTE hash_assoc_values[] =
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, 10, 116, 116, 55,
210 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
211 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
212 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
213 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
214 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
215 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
216 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
217 0, 0, 10, 116, 116, 116, 116, 116, 116, 116,
218 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
219 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
220 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
221 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
222 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
223 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
224 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
225 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
226 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
227 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
228 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
229 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
230 116, 116, 116, 116, 116, 116
233 static void LIBXML2_LOG_CALLBACK parser_error(void* ctx, char const* msg, ...)
235 va_list ap;
236 va_start(ap, msg);
237 LIBXML2_CALLBACK_ERR(Schema_parse, msg, ap);
238 va_end(ap);
241 static void LIBXML2_LOG_CALLBACK parser_warning(void* ctx, char const* msg, ...)
243 va_list ap;
244 va_start(ap, msg);
245 LIBXML2_CALLBACK_WARN(Schema_parse, msg, ap);
246 va_end(ap);
249 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
250 static void parser_serror(void* ctx, xmlErrorPtr err)
252 LIBXML2_CALLBACK_SERROR(Schema_parse, err);
254 #endif
256 static inline xmlSchemaPtr Schema_parse(xmlSchemaParserCtxtPtr spctx)
258 TRACE("(%p)\n", spctx);
260 xmlSchemaSetParserErrors(spctx, parser_error, parser_warning, NULL);
261 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
262 xmlSchemaSetParserStructuredErrors(spctx, parser_serror, NULL);
263 #endif
265 return xmlSchemaParse(spctx);
268 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
270 va_list ap;
271 va_start(ap, msg);
272 LIBXML2_CALLBACK_ERR(Schema_validate_tree, msg, ap);
273 va_end(ap);
276 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
278 va_list ap;
279 va_start(ap, msg);
280 LIBXML2_CALLBACK_WARN(Schema_validate_tree, msg, ap);
281 va_end(ap);
284 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
285 static void validate_serror(void* ctx, xmlErrorPtr err)
287 LIBXML2_CALLBACK_SERROR(Schema_validate_tree, err);
289 #endif
291 static inline HRESULT Schema_validate_tree(xmlSchemaPtr schema, xmlNodePtr tree)
293 xmlSchemaValidCtxtPtr svctx;
294 int err;
296 TRACE("(%p, %p)\n", schema, tree);
297 /* TODO: if validateOnLoad property is false,
298 * we probably need to validate the schema here. */
299 svctx = xmlSchemaNewValidCtxt(schema);
300 xmlSchemaSetValidErrors(svctx, validate_error, validate_warning, NULL);
301 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
302 xmlSchemaSetValidStructuredErrors(svctx, validate_serror, NULL);
303 #endif
305 if (tree->type == XML_DOCUMENT_NODE)
306 err = xmlSchemaValidateDoc(svctx, (xmlDocPtr)tree);
307 else
308 err = xmlSchemaValidateOneElement(svctx, tree);
310 xmlSchemaFreeValidCtxt(svctx);
311 return err? S_FALSE : S_OK;
314 static DWORD dt_hash(xmlChar const* str, int len /* calculated if -1 */)
316 DWORD hval = (len == -1)? xmlStrlen(str) : len;
318 switch (hval)
320 default:
321 hval += hash_assoc_values[str[10]];
322 /*FALLTHROUGH*/
323 case 10:
324 hval += hash_assoc_values[str[9]];
325 /*FALLTHROUGH*/
326 case 9:
327 hval += hash_assoc_values[str[8]];
328 /*FALLTHROUGH*/
329 case 8:
330 hval += hash_assoc_values[str[7]];
331 /*FALLTHROUGH*/
332 case 7:
333 hval += hash_assoc_values[str[6]];
334 /*FALLTHROUGH*/
335 case 6:
336 hval += hash_assoc_values[str[5]];
337 /*FALLTHROUGH*/
338 case 5:
339 hval += hash_assoc_values[str[4]];
340 /*FALLTHROUGH*/
341 case 4:
342 hval += hash_assoc_values[str[3]];
343 /*FALLTHROUGH*/
344 case 3:
345 hval += hash_assoc_values[str[2]];
346 /*FALLTHROUGH*/
347 case 2:
348 hval += hash_assoc_values[str[1]];
349 /*FALLTHROUGH*/
350 case 1:
351 hval += hash_assoc_values[str[0]];
352 break;
354 return hval;
357 static DWORD dt_hash_bstr(OLECHAR const* bstr, int len /* calculated if -1 */)
359 DWORD hval = (len == -1)? lstrlenW(bstr) : len;
361 switch (hval)
363 default:
364 hval += (bstr[10] & 0xFF00)? 116 : hash_assoc_values[bstr[10]];
365 /*FALLTHROUGH*/
366 case 10:
367 hval += (bstr[9] & 0xFF00)? 116 : hash_assoc_values[bstr[9]];
368 /*FALLTHROUGH*/
369 case 9:
370 hval += (bstr[8] & 0xFF00)? 116 : hash_assoc_values[bstr[8]];
371 /*FALLTHROUGH*/
372 case 8:
373 hval += (bstr[7] & 0xFF00)? 116 : hash_assoc_values[bstr[7]];
374 /*FALLTHROUGH*/
375 case 7:
376 hval += (bstr[6] & 0xFF00)? 116 : hash_assoc_values[bstr[6]];
377 /*FALLTHROUGH*/
378 case 6:
379 hval += (bstr[5] & 0xFF00)? 116 : hash_assoc_values[bstr[5]];
380 /*FALLTHROUGH*/
381 case 5:
382 hval += (bstr[4] & 0xFF00)? 116 : hash_assoc_values[bstr[4]];
383 /*FALLTHROUGH*/
384 case 4:
385 hval += (bstr[3] & 0xFF00)? 116 : hash_assoc_values[bstr[3]];
386 /*FALLTHROUGH*/
387 case 3:
388 hval += (bstr[2] & 0xFF00)? 116 : hash_assoc_values[bstr[2]];
389 /*FALLTHROUGH*/
390 case 2:
391 hval += (bstr[1] & 0xFF00)? 116 : hash_assoc_values[bstr[1]];
392 /*FALLTHROUGH*/
393 case 1:
394 hval += (bstr[0] & 0xFF00)? 116 : hash_assoc_values[bstr[0]];
395 break;
397 return hval;
400 static const xmlChar *const DT_string_table[LAST_DT] =
402 DT_bin_base64,
403 DT_bin_hex,
404 DT_boolean,
405 DT_char,
406 DT_date,
407 DT_date_tz,
408 DT_dateTime,
409 DT_dateTime_tz,
410 DT_entity,
411 DT_entities,
412 DT_enumeration,
413 DT_fixed_14_4,
414 DT_float,
415 DT_i1,
416 DT_i2,
417 DT_i4,
418 DT_i8,
419 DT_id,
420 DT_idref,
421 DT_idrefs,
422 DT_int,
423 DT_nmtoken,
424 DT_nmtokens,
425 DT_notation,
426 DT_number,
427 DT_r4,
428 DT_r8,
429 DT_string,
430 DT_time,
431 DT_time_tz,
432 DT_ui1,
433 DT_ui2,
434 DT_ui4,
435 DT_ui8,
436 DT_uri,
437 DT_uuid
440 static const WCHAR *const DT_wstring_table[LAST_DT] =
442 wDT_bin_base64,
443 wDT_bin_hex,
444 wDT_boolean,
445 wDT_char,
446 wDT_date,
447 wDT_date_tz,
448 wDT_dateTime,
449 wDT_dateTime_tz,
450 wDT_entity,
451 wDT_entities,
452 wDT_enumeration,
453 wDT_fixed_14_4,
454 wDT_float,
455 wDT_i1,
456 wDT_i2,
457 wDT_i4,
458 wDT_i8,
459 wDT_id,
460 wDT_idref,
461 wDT_idrefs,
462 wDT_int,
463 wDT_nmtoken,
464 wDT_nmtokens,
465 wDT_notation,
466 wDT_number,
467 wDT_r4,
468 wDT_r8,
469 wDT_string,
470 wDT_time,
471 wDT_time_tz,
472 wDT_ui1,
473 wDT_ui2,
474 wDT_ui4,
475 wDT_ui8,
476 wDT_uri,
477 wDT_uuid
480 static const XDR_DT DT_lookup_table[] =
482 -1, -1,
483 DT_I8,
484 DT_UI8,
485 DT_TIME,
486 -1, -1,
487 DT_I4,
488 DT_UI4,
489 -1, -1, -1,
490 DT_R8,
491 DT_URI,
493 DT_FLOAT,
495 DT_R4,
496 DT_INT,
497 DT_CHAR,
499 DT_ENTITY,
500 DT_ID,
501 DT_ENTITIES,
502 DT_UUID,
503 -1, -1,
504 DT_TIME_TZ,
506 DT_DATE,
508 DT_NUMBER,
509 DT_BIN_HEX,
510 DT_DATETIME,
512 DT_IDREF,
513 DT_IDREFS,
514 DT_BOOLEAN,
515 -1, -1, -1,
516 DT_STRING,
517 DT_NMTOKEN,
518 DT_NMTOKENS,
520 DT_BIN_BASE64,
522 DT_I2,
523 DT_UI2,
524 -1, -1, -1,
525 DT_DATE_TZ,
526 DT_NOTATION,
527 -1, -1,
528 DT_DATETIME_TZ,
529 DT_I1,
530 DT_UI1,
531 -1, -1,
532 DT_ENUMERATION,
533 -1, -1, -1, -1, -1, -1, -1, -1, -1,
534 -1, -1, -1, -1, -1, -1, -1, -1, -1,
535 -1, -1, -1, -1, -1, -1, -1, -1, -1,
536 -1, -1, -1, -1, -1, -1, -1, -1, -1,
537 -1, -1, -1, -1, -1, -1, -1, -1, -1,
538 -1, -1, -1, -1, -1, -1, -1, -1,
539 DT_FIXED_14_4
542 XDR_DT str_to_dt(xmlChar const* str, int len /* calculated if -1 */)
544 DWORD hash = dt_hash(str, len);
545 XDR_DT dt = DT_INVALID;
547 if (hash <= DT_MAX_HASH_VALUE)
548 dt = DT_lookup_table[hash];
550 if (dt != DT_INVALID && xmlStrcasecmp(str, DT_string_table[dt]) == 0)
551 return dt;
553 return DT_INVALID;
556 XDR_DT bstr_to_dt(OLECHAR const* bstr, int len /* calculated if -1 */)
558 DWORD hash = dt_hash_bstr(bstr, len);
559 XDR_DT dt = DT_INVALID;
561 if (hash <= DT_MAX_HASH_VALUE)
562 dt = DT_lookup_table[hash];
564 if (dt != DT_INVALID && lstrcmpiW(bstr, DT_wstring_table[dt]) == 0)
565 return dt;
567 return DT_INVALID;
570 xmlChar const* dt_to_str(XDR_DT dt)
572 if (dt == DT_INVALID)
573 return NULL;
575 return DT_string_table[dt];
578 OLECHAR const* dt_to_bstr(XDR_DT dt)
580 if (dt == DT_INVALID)
581 return NULL;
583 return DT_wstring_table[dt];
586 const char* debugstr_dt(XDR_DT dt)
588 return debugstr_a(dt != DT_INVALID ? (const char*)DT_string_table[dt] : NULL);
591 HRESULT dt_validate(XDR_DT dt, xmlChar const* content)
593 xmlDocPtr tmp_doc;
594 xmlNodePtr node;
595 xmlNsPtr ns;
596 HRESULT hr;
598 TRACE("(dt:%s, %s)\n", debugstr_dt(dt), debugstr_a((char const*)content));
600 if (!datatypes_schema)
602 xmlSchemaParserCtxtPtr spctx;
603 assert(datatypes_src != NULL);
604 spctx = xmlSchemaNewMemParserCtxt((char const*)datatypes_src, datatypes_len);
605 datatypes_schema = Schema_parse(spctx);
606 xmlSchemaFreeParserCtxt(spctx);
609 switch (dt)
611 case DT_INVALID:
612 return E_FAIL;
613 case DT_BIN_BASE64:
614 case DT_BIN_HEX:
615 case DT_BOOLEAN:
616 case DT_CHAR:
617 case DT_DATE:
618 case DT_DATE_TZ:
619 case DT_DATETIME:
620 case DT_DATETIME_TZ:
621 case DT_FIXED_14_4:
622 case DT_FLOAT:
623 case DT_I1:
624 case DT_I2:
625 case DT_I4:
626 case DT_I8:
627 case DT_INT:
628 case DT_NMTOKEN:
629 case DT_NMTOKENS:
630 case DT_NUMBER:
631 case DT_R4:
632 case DT_R8:
633 case DT_STRING:
634 case DT_TIME:
635 case DT_TIME_TZ:
636 case DT_UI1:
637 case DT_UI2:
638 case DT_UI4:
639 case DT_UI8:
640 case DT_URI:
641 case DT_UUID:
642 if (!datatypes_schema)
644 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
645 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION "\n");
647 /* Hopefully they don't need much in the way of XDR datatypes support... */
648 return S_OK;
651 if (content && xmlStrlen(content))
653 tmp_doc = xmlNewDoc(NULL);
654 node = xmlNewChild((xmlNodePtr)tmp_doc, NULL, dt_to_str(dt), content);
655 ns = xmlNewNs(node, DT_nsURI, BAD_CAST "dt");
656 xmlSetNs(node, ns);
657 xmlDocSetRootElement(tmp_doc, node);
659 hr = Schema_validate_tree(datatypes_schema, (xmlNodePtr)tmp_doc);
660 xmlFreeDoc(tmp_doc);
662 else
663 { /* probably the node is being created manually and has no content yet */
664 hr = S_OK;
666 return hr;
667 default:
668 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
669 return S_OK;
673 static inline xmlChar const* get_node_nsURI(xmlNodePtr node)
675 return (node->ns != NULL)? node->ns->href : NULL;
678 static inline cache_entry* get_entry(schema_cache* This, xmlChar const* nsURI)
680 return (!nsURI)? xmlHashLookup(This->cache, BAD_CAST "") :
681 xmlHashLookup(This->cache, nsURI);
684 static inline xmlSchemaPtr get_node_schema(schema_cache* This, xmlNodePtr node)
686 cache_entry* entry = get_entry(This, get_node_nsURI(node));
687 return (!entry)? NULL : entry->schema;
690 static xmlExternalEntityLoader _external_entity_loader;
692 static xmlParserInputPtr external_entity_loader(const char *URL, const char *ID,
693 xmlParserCtxtPtr ctxt)
695 xmlParserInputPtr input;
697 TRACE("(%s %s %p)\n", debugstr_a(URL), debugstr_a(ID), ctxt);
699 assert(MSXML_hInstance != NULL);
700 assert(datatypes_rsrc != NULL);
701 assert(datatypes_handle != NULL);
702 assert(datatypes_src != NULL);
704 /* TODO: if the desired schema is in the cache, load it from there */
705 if (lstrcmpA(URL, "urn:schemas-microsoft-com:datatypes") == 0)
707 TRACE("loading built-in schema for %s\n", URL);
708 input = xmlNewStringInputStream(ctxt, datatypes_src);
710 else
712 input = _external_entity_loader(URL, ID, ctxt);
715 return input;
718 void schemasInit(void)
720 int len;
721 char* buf;
722 if (!(datatypes_rsrc = FindResourceA(MSXML_hInstance, "DATATYPES", "XML")))
724 FIXME("failed to find resource for %s\n", DT_nsURI);
725 return;
728 if (!(datatypes_handle = LoadResource(MSXML_hInstance, datatypes_rsrc)))
730 FIXME("failed to load resource for %s\n", DT_nsURI);
731 return;
733 buf = LockResource(datatypes_handle);
734 len = SizeofResource(MSXML_hInstance, datatypes_rsrc) - 1;
736 /* Resource is loaded as raw data,
737 * need a null-terminated string */
738 while (buf[len] != '>')
739 buf[len--] = 0;
740 datatypes_src = BAD_CAST buf;
741 datatypes_len = len + 1;
743 if (xmlGetExternalEntityLoader() != external_entity_loader)
745 _external_entity_loader = xmlGetExternalEntityLoader();
746 xmlSetExternalEntityLoader(external_entity_loader);
750 void schemasCleanup(void)
752 xmlSchemaFree(datatypes_schema);
753 xmlSetExternalEntityLoader(_external_entity_loader);
756 static LONG cache_entry_add_ref(cache_entry* entry)
758 LONG ref = InterlockedIncrement(&entry->ref);
759 TRACE("(%p)->(%d)\n", entry, ref);
760 return ref;
763 static LONG cache_entry_release(cache_entry* entry)
765 LONG ref = InterlockedDecrement(&entry->ref);
766 TRACE("(%p)->(%d)\n", entry, ref);
768 if (ref == 0)
770 if (entry->type == CacheEntryType_XSD)
772 xmldoc_release(entry->doc);
773 entry->schema->doc = NULL;
774 xmlSchemaFree(entry->schema);
776 else if (entry->type == CacheEntryType_XDR)
778 xmldoc_release(entry->doc);
779 xmldoc_release(entry->schema->doc);
780 entry->schema->doc = NULL;
781 xmlSchemaFree(entry->schema);
784 heap_free(entry);
786 return ref;
789 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
791 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
794 static inline CacheEntryType cache_type_from_xmlDocPtr(xmlDocPtr schema)
796 xmlNodePtr root = NULL;
797 if (schema)
798 root = xmlDocGetRootElement(schema);
799 if (root && root->ns)
802 if (xmlStrEqual(root->name, XDR_schema) &&
803 xmlStrEqual(root->ns->href, XDR_nsURI))
805 return CacheEntryType_XDR;
807 else if (xmlStrEqual(root->name, XSD_schema) &&
808 xmlStrEqual(root->ns->href, XSD_nsURI))
810 return CacheEntryType_XSD;
813 return CacheEntryType_Invalid;
816 static BOOL link_datatypes(xmlDocPtr schema)
818 xmlNodePtr root, next, child;
819 xmlNsPtr ns;
821 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
822 root = xmlDocGetRootElement(schema);
823 if (!root)
824 return FALSE;
826 for (ns = root->nsDef; ns != NULL; ns = ns->next)
828 if (xmlStrEqual(ns->href, DT_nsURI))
829 break;
832 if (!ns)
833 return FALSE;
835 next = xmlFirstElementChild(root);
836 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
837 if (next) child = xmlAddPrevSibling(next, child);
838 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
839 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
841 return TRUE;
844 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
846 cache_entry* entry = heap_alloc(sizeof(cache_entry));
847 xmlSchemaParserCtxtPtr spctx;
848 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
850 link_datatypes(new_doc);
852 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
853 * do we need to do something special here? */
854 entry->type = CacheEntryType_XSD;
855 entry->ref = 0;
856 spctx = xmlSchemaNewDocParserCtxt(new_doc);
858 if ((entry->schema = Schema_parse(spctx)))
860 xmldoc_init(entry->schema->doc, v);
861 entry->doc = entry->schema->doc;
862 xmldoc_add_ref(entry->doc);
864 else
866 FIXME("failed to parse doc\n");
867 xmlFreeDoc(new_doc);
868 heap_free(entry);
869 entry = NULL;
871 xmlSchemaFreeParserCtxt(spctx);
872 return entry;
875 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
877 cache_entry* entry = heap_alloc(sizeof(cache_entry));
878 xmlSchemaParserCtxtPtr spctx;
879 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
881 link_datatypes(xsd_doc);
883 entry->type = CacheEntryType_XDR;
884 entry->ref = 0;
885 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
887 if ((entry->schema = Schema_parse(spctx)))
889 entry->doc = new_doc;
890 xmldoc_init(entry->schema->doc, version);
891 xmldoc_init(entry->doc, version);
892 xmldoc_add_ref(entry->doc);
893 xmldoc_add_ref(entry->schema->doc);
895 else
897 FIXME("failed to parse doc\n");
898 xmlFreeDoc(new_doc);
899 xmlFreeDoc(xsd_doc);
900 heap_free(entry);
901 entry = NULL;
903 xmlSchemaFreeParserCtxt(spctx);
905 return entry;
908 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
910 cache_entry* entry;
911 IXMLDOMDocument3* domdoc = NULL;
912 xmlDocPtr doc = NULL;
913 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
914 VARIANT_BOOL b = VARIANT_FALSE;
915 CacheEntryType type = CacheEntryType_Invalid;
917 if (hr != S_OK)
919 FIXME("failed to create domdoc\n");
920 return NULL;
922 assert(domdoc != NULL);
923 assert(V_VT(&url) == VT_BSTR);
925 hr = IXMLDOMDocument3_load(domdoc, url, &b);
926 if (hr != S_OK)
928 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
929 if (b != VARIANT_TRUE)
931 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url)));
932 IXMLDOMDocument3_Release(domdoc);
933 return NULL;
936 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
937 type = cache_type_from_xmlDocPtr(doc);
939 switch (type)
941 case CacheEntryType_XSD:
942 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
943 break;
944 case CacheEntryType_XDR:
945 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
946 break;
947 default:
948 entry = NULL;
949 FIXME("invalid schema\n");
950 break;
952 IXMLDOMDocument3_Release(domdoc);
954 return entry;
957 static void cache_free(void* data, xmlChar* name /* ignored */)
959 cache_entry_release((cache_entry*)data);
962 /* This one adds all namespaces defined in document to a cache, without anything
963 associated with uri obviously.
964 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
965 it uses additional node type to describe namespace definition attribute while
966 in msxml it's expected to be a normal attribute - as a workaround document is
967 queried at libxml2 level here. */
968 HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node)
970 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
971 static const xmlChar query[] = "//*/namespace::*";
972 xmlXPathObjectPtr nodeset;
973 xmlXPathContextPtr ctxt;
975 This->read_only = 1;
977 ctxt = xmlXPathNewContext(node->node->doc);
979 nodeset = xmlXPathEvalExpression(query, ctxt);
980 xmlXPathFreeContext(ctxt);
982 if (nodeset)
984 int pos = 0, len = xmlXPathNodeSetGetLength(nodeset->nodesetval);
986 if (len == 0) return S_OK;
988 while (pos < len)
990 xmlNodePtr node = xmlXPathNodeSetItem(nodeset->nodesetval, pos);
991 if (node->type == XML_NAMESPACE_DECL)
993 static const xmlChar defns[] = "http://www.w3.org/XML/1998/namespace";
994 xmlNsPtr ns = (xmlNsPtr)node;
995 cache_entry *entry;
997 /* filter out default uri */
998 if (xmlStrEqual(ns->href, defns))
1000 pos++;
1001 continue;
1004 entry = heap_alloc(sizeof(cache_entry));
1005 entry->type = CacheEntryType_NS;
1006 entry->ref = 1;
1007 entry->schema = NULL;
1008 entry->doc = NULL;
1010 xmlHashRemoveEntry(This->cache, ns->href, cache_free);
1011 xmlHashAddEntry(This->cache, ns->href, entry);
1013 pos++;
1016 xmlXPathFreeObject(nodeset);
1019 return S_OK;
1022 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
1023 REFIID riid, void** ppvObject)
1025 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1027 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1029 if ( IsEqualIID(riid, &IID_IUnknown) ||
1030 IsEqualIID(riid, &IID_IDispatch) ||
1031 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
1032 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
1034 *ppvObject = iface;
1036 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
1038 return *ppvObject ? S_OK : E_NOINTERFACE;
1040 else
1042 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1043 *ppvObject = NULL;
1044 return E_NOINTERFACE;
1047 IXMLDOMSchemaCollection2_AddRef(iface);
1049 return S_OK;
1052 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
1054 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1055 LONG ref = InterlockedIncrement(&This->ref);
1056 TRACE("(%p)->(%d)\n", This, ref);
1057 return ref;
1060 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
1062 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1063 LONG ref = InterlockedDecrement(&This->ref);
1064 TRACE("(%p)->(%d)\n", This, ref);
1066 if (ref == 0)
1068 xmlHashFree(This->cache, cache_free);
1069 release_dispex(&This->dispex);
1070 heap_free(This);
1073 return ref;
1076 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1077 UINT* pctinfo)
1079 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1080 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1083 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1084 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1086 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1087 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
1088 iTInfo, lcid, ppTInfo);
1091 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1092 REFIID riid, LPOLESTR* rgszNames,
1093 UINT cNames, LCID lcid, DISPID* rgDispId)
1095 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1096 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1097 riid, rgszNames, cNames, lcid, rgDispId);
1100 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1101 DISPID dispIdMember, REFIID riid, LCID lcid,
1102 WORD wFlags, DISPPARAMS* pDispParams,
1103 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1104 UINT* puArgErr)
1106 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1107 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1108 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1111 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1113 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1114 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1115 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1117 if (This->read_only) return E_FAIL;
1119 switch (V_VT(&var))
1121 case VT_NULL:
1123 xmlHashRemoveEntry(This->cache, name, cache_free);
1125 break;
1127 case VT_BSTR:
1129 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1131 if (entry)
1133 cache_entry_add_ref(entry);
1135 else
1137 heap_free(name);
1138 return E_FAIL;
1141 xmlHashRemoveEntry(This->cache, name, cache_free);
1142 xmlHashAddEntry(This->cache, name, entry);
1144 break;
1146 case VT_DISPATCH:
1148 xmlDocPtr doc = NULL;
1149 cache_entry* entry;
1150 CacheEntryType type;
1151 IXMLDOMNode* domnode = NULL;
1152 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1154 if (domnode)
1155 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1157 if (!doc)
1159 IXMLDOMNode_Release(domnode);
1160 heap_free(name);
1161 return E_INVALIDARG;
1163 type = cache_type_from_xmlDocPtr(doc);
1165 if (type == CacheEntryType_XSD)
1167 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1169 else if (type == CacheEntryType_XDR)
1171 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1173 else
1175 WARN("invalid schema!\n");
1176 entry = NULL;
1179 IXMLDOMNode_Release(domnode);
1181 if (entry)
1183 cache_entry_add_ref(entry);
1185 else
1187 heap_free(name);
1188 return E_FAIL;
1191 xmlHashRemoveEntry(This->cache, name, cache_free);
1192 xmlHashAddEntry(This->cache, name, entry);
1194 break;
1196 default:
1198 heap_free(name);
1199 return E_INVALIDARG;
1202 heap_free(name);
1203 return S_OK;
1206 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1207 IXMLDOMNode** node)
1209 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1210 cache_entry* entry;
1211 xmlChar* name;
1213 TRACE("(%p)->(%s %p)\n", This, debugstr_w(uri), node);
1215 if (This->version == MSXML6) return E_NOTIMPL;
1217 if (!node)
1218 return E_POINTER;
1220 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1221 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1222 heap_free(name);
1224 /* TODO: this should be read-only */
1225 if (entry && entry->doc)
1226 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1228 *node = NULL;
1229 return S_OK;
1232 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1234 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1235 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1236 TRACE("(%p)->(%s)\n", This, debugstr_w(uri));
1238 if (This->version == MSXML6) return E_NOTIMPL;
1240 xmlHashRemoveEntry(This->cache, name, cache_free);
1241 heap_free(name);
1242 return S_OK;
1245 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1247 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1248 TRACE("(%p)->(%p)\n", This, length);
1250 if (!length)
1251 return E_POINTER;
1252 *length = xmlHashSize(This->cache);
1253 return S_OK;
1256 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1258 cache_index_data* index_data = (cache_index_data*)index;
1260 if (index_data->index-- == 0)
1261 *index_data->out = bstr_from_xmlChar(name);
1264 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1265 LONG index, BSTR* len)
1267 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1268 cache_index_data data = {index, len};
1269 TRACE("(%p)->(%i %p)\n", This, index, len);
1271 if (!len)
1272 return E_POINTER;
1274 if (index >= xmlHashSize(This->cache))
1275 return E_FAIL;
1277 *len = NULL;
1278 xmlHashScan(This->cache, cache_index, &data);
1279 return S_OK;
1282 static void cache_copy(void* data, void* dest, xmlChar* name)
1284 schema_cache* This = (schema_cache*) dest;
1285 cache_entry* entry = (cache_entry*) data;
1287 if (xmlHashLookup(This->cache, name) == NULL)
1289 cache_entry_add_ref(entry);
1290 xmlHashAddEntry(This->cache, name, entry);
1294 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1295 IXMLDOMSchemaCollection* otherCollection)
1297 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1298 schema_cache* That = impl_from_IXMLDOMSchemaCollection2((IXMLDOMSchemaCollection2*)otherCollection);
1299 TRACE("(%p)->(%p)\n", This, That);
1301 if (!otherCollection)
1302 return E_POINTER;
1304 /* TODO: detect errors while copying & return E_FAIL */
1305 xmlHashScan(That->cache, cache_copy, This);
1307 return S_OK;
1310 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1311 IUnknown** ppUnk)
1313 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1314 FIXME("(%p)->(%p): stub\n", This, ppUnk);
1315 if (ppUnk)
1316 *ppUnk = NULL;
1317 return E_NOTIMPL;
1320 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1322 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1323 FIXME("(%p): stub\n", This);
1324 return E_NOTIMPL;
1327 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1328 VARIANT_BOOL value)
1330 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1331 FIXME("(%p)->(%d): stub\n", This, value);
1333 This->validateOnLoad = value;
1334 /* it's ok to disable it, cause we don't validate on load anyway */
1335 if (value == VARIANT_FALSE) return S_OK;
1337 return E_NOTIMPL;
1340 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1341 VARIANT_BOOL* value)
1343 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1344 TRACE("(%p)->(%p)\n", This, value);
1346 if (!value) return E_POINTER;
1347 *value = This->validateOnLoad;
1349 return S_OK;
1352 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1353 BSTR namespaceURI, ISchema** schema)
1355 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1356 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1357 if (schema)
1358 *schema = NULL;
1359 return E_NOTIMPL;
1362 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1363 IXMLDOMNode* node, ISchemaItem** item)
1365 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1366 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1367 if (item)
1368 *item = NULL;
1369 return E_NOTIMPL;
1372 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl =
1374 schema_cache_QueryInterface,
1375 schema_cache_AddRef,
1376 schema_cache_Release,
1377 schema_cache_GetTypeInfoCount,
1378 schema_cache_GetTypeInfo,
1379 schema_cache_GetIDsOfNames,
1380 schema_cache_Invoke,
1381 schema_cache_add,
1382 schema_cache_get,
1383 schema_cache_remove,
1384 schema_cache_get_length,
1385 schema_cache_get_namespaceURI,
1386 schema_cache_addCollection,
1387 schema_cache_get__newEnum,
1388 schema_cache_validate,
1389 schema_cache_put_validateOnLoad,
1390 schema_cache_get_validateOnLoad,
1391 schema_cache_getSchema,
1392 schema_cache_getDeclaration
1395 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1397 xmlSchemaElementPtr decl = NULL;
1398 xmlChar const* nsURI = get_node_nsURI(node);
1400 TRACE("(%p, %p)\n", schema, node);
1402 if (xmlStrEqual(nsURI, schema->targetNamespace))
1403 decl = xmlHashLookup(schema->elemDecl, node->name);
1405 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1407 FIXME("declaration not found in main schema - need to check schema imports!\n");
1408 /*xmlSchemaImportPtr import;
1409 if (nsURI == NULL)
1410 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1411 else
1412 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1414 if (import != NULL)
1415 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1418 return decl;
1421 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1423 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1424 while (decl != NULL && decl->refDecl != NULL)
1425 decl = decl->refDecl;
1426 return (decl != NULL)? decl->node : NULL;
1429 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1431 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1432 xmlSchemaPtr schema;
1434 TRACE("(%p, %p)\n", This, tree);
1436 if (!tree)
1437 return E_POINTER;
1439 if (tree->type == XML_DOCUMENT_NODE)
1440 tree = xmlDocGetRootElement(tree->doc);
1442 schema = get_node_schema(This, tree);
1443 /* TODO: if the ns is not in the cache, and it's a URL,
1444 * do we try to load from that? */
1445 if (schema)
1446 return Schema_validate_tree(schema, tree);
1447 else
1448 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1450 return E_FAIL;
1453 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1455 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1456 xmlSchemaPtr schema = get_node_schema(This, node);
1457 XDR_DT dt = DT_INVALID;
1459 TRACE("(%p, %p)\n", This, node);
1461 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1463 dt = str_to_dt(node->name, -1);
1465 else if (schema)
1467 xmlChar* str;
1468 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1470 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1471 if (str)
1473 dt = str_to_dt(str, -1);
1474 xmlFree(str);
1478 return dt;
1481 static const tid_t schemacache_iface_tids[] = {
1482 IXMLDOMSchemaCollection2_tid,
1486 static dispex_static_data_t schemacache_dispex = {
1487 NULL,
1488 IXMLDOMSchemaCollection2_tid,
1489 NULL,
1490 schemacache_iface_tids
1493 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1495 schema_cache* This = heap_alloc(sizeof(schema_cache));
1496 if (!This)
1497 return E_OUTOFMEMORY;
1499 TRACE("(%d %p %p)\n", version, outer, obj);
1501 This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl;
1502 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1503 This->ref = 1;
1504 This->version = version;
1505 This->validateOnLoad = VARIANT_TRUE;
1506 This->read_only = 0;
1507 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSchemaCollection2_iface, &schemacache_dispex);
1509 *obj = &This->IXMLDOMSchemaCollection2_iface;
1510 return S_OK;
1513 #else
1515 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1517 MESSAGE("This program tried to use a SchemaCache object, but\n"
1518 "libxml2 support was not present at compile time.\n");
1519 return E_NOTIMPL;
1522 #endif