localspl: Remove a bunch of casts.
[wine.git] / dlls / msxml3 / schema.c
blob903f311310baaba6a2eb51504d7a291d40f7f35b
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 xmlChar* 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 = 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 const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl;
791 static inline schema_cache* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2* iface)
793 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
796 static inline schema_cache* impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection* iface)
798 return CONTAINING_RECORD(iface, schema_cache, IXMLDOMSchemaCollection2_iface);
801 static inline schema_cache* unsafe_impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection *iface)
803 return iface->lpVtbl == (void*)&XMLDOMSchemaCollection2Vtbl ? impl_from_IXMLDOMSchemaCollection(iface) : NULL;
806 static inline CacheEntryType cache_type_from_xmlDocPtr(xmlDocPtr schema)
808 xmlNodePtr root = NULL;
809 if (schema)
810 root = xmlDocGetRootElement(schema);
811 if (root && root->ns)
814 if (xmlStrEqual(root->name, XDR_schema) &&
815 xmlStrEqual(root->ns->href, XDR_nsURI))
817 return CacheEntryType_XDR;
819 else if (xmlStrEqual(root->name, XSD_schema) &&
820 xmlStrEqual(root->ns->href, XSD_nsURI))
822 return CacheEntryType_XSD;
825 return CacheEntryType_Invalid;
828 static BOOL link_datatypes(xmlDocPtr schema)
830 xmlNodePtr root, next, child;
831 xmlNsPtr ns;
833 assert((void*)xmlGetExternalEntityLoader() == (void*)external_entity_loader);
834 root = xmlDocGetRootElement(schema);
835 if (!root)
836 return FALSE;
838 for (ns = root->nsDef; ns != NULL; ns = ns->next)
840 if (xmlStrEqual(ns->href, DT_nsURI))
841 break;
844 if (!ns)
845 return FALSE;
847 next = xmlFirstElementChild(root);
848 child = xmlNewChild(root, NULL, BAD_CAST "import", NULL);
849 if (next) child = xmlAddPrevSibling(next, child);
850 xmlSetProp(child, BAD_CAST "namespace", DT_nsURI);
851 xmlSetProp(child, BAD_CAST "schemaLocation", DT_nsURI);
853 return TRUE;
856 static cache_entry* cache_entry_from_xsd_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION v)
858 cache_entry* entry = heap_alloc(sizeof(cache_entry));
859 xmlSchemaParserCtxtPtr spctx;
860 xmlDocPtr new_doc = xmlCopyDoc(doc, 1);
862 link_datatypes(new_doc);
864 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
865 * do we need to do something special here? */
866 entry->type = CacheEntryType_XSD;
867 entry->ref = 0;
868 spctx = xmlSchemaNewDocParserCtxt(new_doc);
870 if ((entry->schema = Schema_parse(spctx)))
872 xmldoc_init(entry->schema->doc, v);
873 entry->doc = entry->schema->doc;
874 xmldoc_add_ref(entry->doc);
876 else
878 FIXME("failed to parse doc\n");
879 xmlFreeDoc(new_doc);
880 heap_free(entry);
881 entry = NULL;
883 xmlSchemaFreeParserCtxt(spctx);
884 return entry;
887 static cache_entry* cache_entry_from_xdr_doc(xmlDocPtr doc, xmlChar const* nsURI, MSXML_VERSION version)
889 cache_entry* entry = heap_alloc(sizeof(cache_entry));
890 xmlSchemaParserCtxtPtr spctx;
891 xmlDocPtr new_doc = xmlCopyDoc(doc, 1), xsd_doc = XDR_to_XSD_doc(doc, nsURI);
893 link_datatypes(xsd_doc);
895 entry->type = CacheEntryType_XDR;
896 entry->ref = 0;
897 spctx = xmlSchemaNewDocParserCtxt(xsd_doc);
899 if ((entry->schema = Schema_parse(spctx)))
901 entry->doc = new_doc;
902 xmldoc_init(entry->schema->doc, version);
903 xmldoc_init(entry->doc, version);
904 xmldoc_add_ref(entry->doc);
905 xmldoc_add_ref(entry->schema->doc);
907 else
909 FIXME("failed to parse doc\n");
910 xmlFreeDoc(new_doc);
911 xmlFreeDoc(xsd_doc);
912 heap_free(entry);
913 entry = NULL;
915 xmlSchemaFreeParserCtxt(spctx);
917 return entry;
920 static cache_entry* cache_entry_from_url(VARIANT url, xmlChar const* nsURI, MSXML_VERSION version)
922 cache_entry* entry;
923 IXMLDOMDocument3* domdoc = NULL;
924 xmlDocPtr doc = NULL;
925 HRESULT hr = DOMDocument_create(version, NULL, (void**)&domdoc);
926 VARIANT_BOOL b = VARIANT_FALSE;
927 CacheEntryType type = CacheEntryType_Invalid;
929 if (hr != S_OK)
931 FIXME("failed to create domdoc\n");
932 return NULL;
934 assert(domdoc != NULL);
935 assert(V_VT(&url) == VT_BSTR);
937 hr = IXMLDOMDocument3_load(domdoc, url, &b);
938 if (hr != S_OK)
940 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr);
941 if (b != VARIANT_TRUE)
943 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url)));
944 IXMLDOMDocument3_Release(domdoc);
945 return NULL;
948 doc = xmlNodePtr_from_domnode((IXMLDOMNode*)domdoc, XML_DOCUMENT_NODE)->doc;
949 type = cache_type_from_xmlDocPtr(doc);
951 switch (type)
953 case CacheEntryType_XSD:
954 entry = cache_entry_from_xsd_doc(doc, nsURI, version);
955 break;
956 case CacheEntryType_XDR:
957 entry = cache_entry_from_xdr_doc(doc, nsURI, version);
958 break;
959 default:
960 entry = NULL;
961 FIXME("invalid schema\n");
962 break;
964 IXMLDOMDocument3_Release(domdoc);
966 return entry;
969 static void cache_free(void* data, xmlChar* name /* ignored */)
971 cache_entry_release((cache_entry*)data);
974 /* This one adds all namespaces defined in document to a cache, without anything
975 associated with uri obviously.
976 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
977 it uses additional node type to describe namespace definition attribute while
978 in msxml it's expected to be a normal attribute - as a workaround document is
979 queried at libxml2 level here. */
980 HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node)
982 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
983 static const xmlChar query[] = "//*/namespace::*";
984 xmlXPathObjectPtr nodeset;
985 xmlXPathContextPtr ctxt;
987 This->read_only = 1;
989 ctxt = xmlXPathNewContext(node->node->doc);
991 nodeset = xmlXPathEvalExpression(query, ctxt);
992 xmlXPathFreeContext(ctxt);
994 if (nodeset)
996 int pos = 0, len = xmlXPathNodeSetGetLength(nodeset->nodesetval);
998 if (len == 0) return S_OK;
1000 while (pos < len)
1002 xmlNodePtr node = xmlXPathNodeSetItem(nodeset->nodesetval, pos);
1003 if (node->type == XML_NAMESPACE_DECL)
1005 static const xmlChar defns[] = "http://www.w3.org/XML/1998/namespace";
1006 xmlNsPtr ns = (xmlNsPtr)node;
1007 cache_entry *entry;
1009 /* filter out default uri */
1010 if (xmlStrEqual(ns->href, defns))
1012 pos++;
1013 continue;
1016 entry = heap_alloc(sizeof(cache_entry));
1017 entry->type = CacheEntryType_NS;
1018 entry->ref = 1;
1019 entry->schema = NULL;
1020 entry->doc = NULL;
1022 xmlHashRemoveEntry(This->cache, ns->href, cache_free);
1023 xmlHashAddEntry(This->cache, ns->href, entry);
1025 pos++;
1028 xmlXPathFreeObject(nodeset);
1031 return S_OK;
1034 static HRESULT WINAPI schema_cache_QueryInterface(IXMLDOMSchemaCollection2* iface,
1035 REFIID riid, void** ppvObject)
1037 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1039 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1041 if ( IsEqualIID(riid, &IID_IUnknown) ||
1042 IsEqualIID(riid, &IID_IDispatch) ||
1043 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection) ||
1044 IsEqualIID(riid, &IID_IXMLDOMSchemaCollection2) )
1046 *ppvObject = iface;
1048 else if (dispex_query_interface(&This->dispex, riid, ppvObject))
1050 return *ppvObject ? S_OK : E_NOINTERFACE;
1052 else
1054 FIXME("interface %s not implemented\n", debugstr_guid(riid));
1055 *ppvObject = NULL;
1056 return E_NOINTERFACE;
1059 IXMLDOMSchemaCollection2_AddRef(iface);
1061 return S_OK;
1064 static ULONG WINAPI schema_cache_AddRef(IXMLDOMSchemaCollection2* iface)
1066 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1067 LONG ref = InterlockedIncrement(&This->ref);
1068 TRACE("(%p)->(%d)\n", This, ref);
1069 return ref;
1072 static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface)
1074 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1075 LONG ref = InterlockedDecrement(&This->ref);
1076 TRACE("(%p)->(%d)\n", This, ref);
1078 if (ref == 0)
1080 xmlHashFree(This->cache, cache_free);
1081 release_dispex(&This->dispex);
1082 heap_free(This);
1085 return ref;
1088 static HRESULT WINAPI schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2* iface,
1089 UINT* pctinfo)
1091 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1092 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1095 static HRESULT WINAPI schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2* iface,
1096 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1098 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1099 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
1100 iTInfo, lcid, ppTInfo);
1103 static HRESULT WINAPI schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2* iface,
1104 REFIID riid, LPOLESTR* rgszNames,
1105 UINT cNames, LCID lcid, DISPID* rgDispId)
1107 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1108 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
1109 riid, rgszNames, cNames, lcid, rgDispId);
1112 static HRESULT WINAPI schema_cache_Invoke(IXMLDOMSchemaCollection2* iface,
1113 DISPID dispIdMember, REFIID riid, LCID lcid,
1114 WORD wFlags, DISPPARAMS* pDispParams,
1115 VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
1116 UINT* puArgErr)
1118 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1119 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
1120 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1123 static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri, VARIANT var)
1125 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1126 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1127 TRACE("(%p)->(%s %s)\n", This, debugstr_w(uri), debugstr_variant(&var));
1129 if (This->read_only) return E_FAIL;
1131 switch (V_VT(&var))
1133 case VT_NULL:
1135 xmlHashRemoveEntry(This->cache, name, cache_free);
1137 break;
1139 case VT_BSTR:
1141 cache_entry* entry = cache_entry_from_url(var, name, This->version);
1143 if (entry)
1145 cache_entry_add_ref(entry);
1147 else
1149 heap_free(name);
1150 return E_FAIL;
1153 xmlHashRemoveEntry(This->cache, name, cache_free);
1154 xmlHashAddEntry(This->cache, name, entry);
1156 break;
1158 case VT_DISPATCH:
1160 xmlDocPtr doc = NULL;
1161 cache_entry* entry;
1162 CacheEntryType type;
1163 IXMLDOMNode* domnode = NULL;
1164 IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IXMLDOMNode, (void**)&domnode);
1166 if (domnode)
1167 doc = xmlNodePtr_from_domnode(domnode, XML_DOCUMENT_NODE)->doc;
1169 if (!doc)
1171 IXMLDOMNode_Release(domnode);
1172 heap_free(name);
1173 return E_INVALIDARG;
1175 type = cache_type_from_xmlDocPtr(doc);
1177 if (type == CacheEntryType_XSD)
1179 entry = cache_entry_from_xsd_doc(doc, name, This->version);
1181 else if (type == CacheEntryType_XDR)
1183 entry = cache_entry_from_xdr_doc(doc, name, This->version);
1185 else
1187 WARN("invalid schema!\n");
1188 entry = NULL;
1191 IXMLDOMNode_Release(domnode);
1193 if (entry)
1195 cache_entry_add_ref(entry);
1197 else
1199 heap_free(name);
1200 return E_FAIL;
1203 xmlHashRemoveEntry(This->cache, name, cache_free);
1204 xmlHashAddEntry(This->cache, name, entry);
1206 break;
1208 default:
1210 heap_free(name);
1211 return E_INVALIDARG;
1214 heap_free(name);
1215 return S_OK;
1218 static HRESULT WINAPI schema_cache_get(IXMLDOMSchemaCollection2* iface, BSTR uri,
1219 IXMLDOMNode** node)
1221 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1222 cache_entry* entry;
1223 xmlChar* name;
1225 TRACE("(%p)->(%s %p)\n", This, debugstr_w(uri), node);
1227 if (This->version == MSXML6) return E_NOTIMPL;
1229 if (!node)
1230 return E_POINTER;
1232 name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1233 entry = (cache_entry*) xmlHashLookup(This->cache, name);
1234 heap_free(name);
1236 /* TODO: this should be read-only */
1237 if (entry && entry->doc)
1238 return get_domdoc_from_xmldoc(entry->doc, (IXMLDOMDocument3**)node);
1240 *node = NULL;
1241 return S_OK;
1244 static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR uri)
1246 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1247 xmlChar* name = uri ? xmlchar_from_wchar(uri) : xmlchar_from_wchar(emptyW);
1248 TRACE("(%p)->(%s)\n", This, debugstr_w(uri));
1250 if (This->version == MSXML6) return E_NOTIMPL;
1252 xmlHashRemoveEntry(This->cache, name, cache_free);
1253 heap_free(name);
1254 return S_OK;
1257 static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, LONG* length)
1259 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1260 TRACE("(%p)->(%p)\n", This, length);
1262 if (!length)
1263 return E_POINTER;
1264 *length = xmlHashSize(This->cache);
1265 return S_OK;
1268 static void cache_index(void* data /* ignored */, void* index, xmlChar* name)
1270 cache_index_data* index_data = (cache_index_data*)index;
1272 if (index_data->index-- == 0)
1273 *index_data->out = bstr_from_xmlChar(name);
1276 static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface,
1277 LONG index, BSTR* len)
1279 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1280 cache_index_data data = {index, len};
1281 TRACE("(%p)->(%i %p)\n", This, index, len);
1283 if (!len)
1284 return E_POINTER;
1286 if (index >= xmlHashSize(This->cache))
1287 return E_FAIL;
1289 *len = NULL;
1290 xmlHashScan(This->cache, cache_index, &data);
1291 return S_OK;
1294 static void cache_copy(void* data, void* dest, xmlChar* name)
1296 schema_cache* This = (schema_cache*) dest;
1297 cache_entry* entry = (cache_entry*) data;
1299 if (xmlHashLookup(This->cache, name) == NULL)
1301 cache_entry_add_ref(entry);
1302 xmlHashAddEntry(This->cache, name, entry);
1306 static HRESULT WINAPI schema_cache_addCollection(IXMLDOMSchemaCollection2* iface,
1307 IXMLDOMSchemaCollection* collection)
1309 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1310 schema_cache* That;
1312 TRACE("(%p)->(%p)\n", This, collection);
1314 if (!collection)
1315 return E_POINTER;
1317 That = unsafe_impl_from_IXMLDOMSchemaCollection(collection);
1318 if (!That)
1320 ERR("external collection implementation\n");
1321 return E_FAIL;
1324 /* TODO: detect errors while copying & return E_FAIL */
1325 xmlHashScan(That->cache, cache_copy, This);
1327 return S_OK;
1330 static HRESULT WINAPI schema_cache_get__newEnum(IXMLDOMSchemaCollection2* iface,
1331 IUnknown** ppUnk)
1333 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1334 FIXME("(%p)->(%p): stub\n", This, ppUnk);
1335 if (ppUnk)
1336 *ppUnk = NULL;
1337 return E_NOTIMPL;
1340 static HRESULT WINAPI schema_cache_validate(IXMLDOMSchemaCollection2* iface)
1342 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1343 FIXME("(%p): stub\n", This);
1344 return E_NOTIMPL;
1347 static HRESULT WINAPI schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1348 VARIANT_BOOL value)
1350 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1351 FIXME("(%p)->(%d): stub\n", This, value);
1353 This->validateOnLoad = value;
1354 /* it's ok to disable it, cause we don't validate on load anyway */
1355 if (value == VARIANT_FALSE) return S_OK;
1357 return E_NOTIMPL;
1360 static HRESULT WINAPI schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2* iface,
1361 VARIANT_BOOL* value)
1363 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1364 TRACE("(%p)->(%p)\n", This, value);
1366 if (!value) return E_POINTER;
1367 *value = This->validateOnLoad;
1369 return S_OK;
1372 static HRESULT WINAPI schema_cache_getSchema(IXMLDOMSchemaCollection2* iface,
1373 BSTR namespaceURI, ISchema** schema)
1375 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1376 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(namespaceURI), schema);
1377 if (schema)
1378 *schema = NULL;
1379 return E_NOTIMPL;
1382 static HRESULT WINAPI schema_cache_getDeclaration(IXMLDOMSchemaCollection2* iface,
1383 IXMLDOMNode* node, ISchemaItem** item)
1385 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1386 FIXME("(%p)->(%p %p): stub\n", This, node, item);
1387 if (item)
1388 *item = NULL;
1389 return E_NOTIMPL;
1392 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl =
1394 schema_cache_QueryInterface,
1395 schema_cache_AddRef,
1396 schema_cache_Release,
1397 schema_cache_GetTypeInfoCount,
1398 schema_cache_GetTypeInfo,
1399 schema_cache_GetIDsOfNames,
1400 schema_cache_Invoke,
1401 schema_cache_add,
1402 schema_cache_get,
1403 schema_cache_remove,
1404 schema_cache_get_length,
1405 schema_cache_get_namespaceURI,
1406 schema_cache_addCollection,
1407 schema_cache_get__newEnum,
1408 schema_cache_validate,
1409 schema_cache_put_validateOnLoad,
1410 schema_cache_get_validateOnLoad,
1411 schema_cache_getSchema,
1412 schema_cache_getDeclaration
1415 static xmlSchemaElementPtr lookup_schema_elemDecl(xmlSchemaPtr schema, xmlNodePtr node)
1417 xmlSchemaElementPtr decl = NULL;
1418 xmlChar const* nsURI = get_node_nsURI(node);
1420 TRACE("(%p, %p)\n", schema, node);
1422 if (xmlStrEqual(nsURI, schema->targetNamespace))
1423 decl = xmlHashLookup(schema->elemDecl, node->name);
1425 if (!decl && xmlHashSize(schema->schemasImports) > 1)
1427 FIXME("declaration not found in main schema - need to check schema imports!\n");
1428 /*xmlSchemaImportPtr import;
1429 if (nsURI == NULL)
1430 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1431 else
1432 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1434 if (import != NULL)
1435 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1438 return decl;
1441 static inline xmlNodePtr lookup_schema_element(xmlSchemaPtr schema, xmlNodePtr node)
1443 xmlSchemaElementPtr decl = lookup_schema_elemDecl(schema, node);
1444 while (decl != NULL && decl->refDecl != NULL)
1445 decl = decl->refDecl;
1446 return (decl != NULL)? decl->node : NULL;
1449 HRESULT SchemaCache_validate_tree(IXMLDOMSchemaCollection2* iface, xmlNodePtr tree)
1451 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1452 xmlSchemaPtr schema;
1454 TRACE("(%p, %p)\n", This, tree);
1456 if (!tree)
1457 return E_POINTER;
1459 if (tree->type == XML_DOCUMENT_NODE)
1460 tree = xmlDocGetRootElement(tree->doc);
1462 schema = get_node_schema(This, tree);
1463 /* TODO: if the ns is not in the cache, and it's a URL,
1464 * do we try to load from that? */
1465 if (schema)
1466 return Schema_validate_tree(schema, tree);
1467 else
1468 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree));
1470 return E_FAIL;
1473 XDR_DT SchemaCache_get_node_dt(IXMLDOMSchemaCollection2* iface, xmlNodePtr node)
1475 schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface);
1476 xmlSchemaPtr schema = get_node_schema(This, node);
1477 XDR_DT dt = DT_INVALID;
1479 TRACE("(%p, %p)\n", This, node);
1481 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
1483 dt = str_to_dt(node->name, -1);
1485 else if (schema)
1487 xmlChar* str;
1488 xmlNodePtr schema_node = lookup_schema_element(schema, node);
1490 str = xmlGetNsProp(schema_node, BAD_CAST "dt", DT_nsURI);
1491 if (str)
1493 dt = str_to_dt(str, -1);
1494 xmlFree(str);
1498 return dt;
1501 static const tid_t schemacache_iface_tids[] = {
1502 IXMLDOMSchemaCollection2_tid,
1506 static dispex_static_data_t schemacache_dispex = {
1507 NULL,
1508 IXMLDOMSchemaCollection2_tid,
1509 NULL,
1510 schemacache_iface_tids
1513 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1515 schema_cache* This = heap_alloc(sizeof(schema_cache));
1516 if (!This)
1517 return E_OUTOFMEMORY;
1519 TRACE("(%d %p %p)\n", version, outer, obj);
1521 This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl;
1522 This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE);
1523 This->ref = 1;
1524 This->version = version;
1525 This->validateOnLoad = VARIANT_TRUE;
1526 This->read_only = 0;
1527 init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMSchemaCollection2_iface, &schemacache_dispex);
1529 *obj = &This->IXMLDOMSchemaCollection2_iface;
1530 return S_OK;
1533 #else
1535 HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj)
1537 MESSAGE("This program tried to use a SchemaCache object, but\n"
1538 "libxml2 support was not present at compile time.\n");
1539 return E_NOTIMPL;
1542 #endif