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
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>
47 #include "wine/debug.h"
49 #include "msxml_private.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(msxml
);
55 #if LIBXML_VERSION >= 20908
56 #define XMLHASH_CONST const
61 /* We use a chained hashtable, which can hold any number of schemas
62 * TODO: grow/shrink hashtable depending on load factor
63 * TODO: implement read-only where appropriate
66 /* This is just the number of buckets, should be prime */
67 #define DEFAULT_HASHTABLE_SIZE 17
69 xmlDocPtr
XDR_to_XSD_doc(xmlDocPtr xdr_doc
, xmlChar
const* nsURI
);
71 static const xmlChar XSD_schema
[] = "schema";
72 static const xmlChar XSD_nsURI
[] = "http://www.w3.org/2001/XMLSchema";
73 static const xmlChar XDR_schema
[] = "Schema";
74 static const xmlChar XDR_nsURI
[] = "urn:schemas-microsoft-com:xml-data";
75 static const xmlChar DT_nsURI
[] = "urn:schemas-microsoft-com:datatypes";
77 static xmlChar
* datatypes_src
;
78 static int datatypes_len
;
79 static HGLOBAL datatypes_handle
;
80 static HRSRC datatypes_rsrc
;
81 static xmlSchemaPtr datatypes_schema
;
83 static const WCHAR emptyW
[] = {0};
91 * CacheType_NS is a special type used for read-only collection build with
92 * IXMLDOMDocument2::namespaces()
95 CacheEntryType_Invalid
,
104 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface
;
107 MSXML_VERSION version
;
108 xmlHashTablePtr cache
;
113 VARIANT_BOOL validateOnLoad
;
125 static const tid_t schema_cache_se_tids
[] = {
126 IXMLDOMSchemaCollection_tid
,
127 IXMLDOMSchemaCollection2_tid
,
131 /* datatypes lookup stuff
132 * generated with help from gperf */
133 #define DT_MIN_STR_LEN 2
134 #define DT_MAX_STR_LEN 11
135 #define DT_MIN_HASH_VALUE 2
136 #define DT_MAX_HASH_VALUE 115
138 static const xmlChar DT_bin_base64
[] = "bin.base64";
139 static const xmlChar DT_bin_hex
[] = "bin.hex";
140 static const xmlChar DT_boolean
[] = "boolean";
141 static const xmlChar DT_char
[] = "char";
142 static const xmlChar DT_date
[] = "date";
143 static const xmlChar DT_date_tz
[] = "date.tz";
144 static const xmlChar DT_dateTime
[] = "dateTime";
145 static const xmlChar DT_dateTime_tz
[] = "dateTime.tz";
146 static const xmlChar DT_entity
[] = "entity";
147 static const xmlChar DT_entities
[] = "entities";
148 static const xmlChar DT_enumeration
[] = "enumeration";
149 static const xmlChar DT_fixed_14_4
[] = "fixed.14.4";
150 static const xmlChar DT_float
[] = "float";
151 static const xmlChar DT_i1
[] = "i1";
152 static const xmlChar DT_i2
[] = "i2";
153 static const xmlChar DT_i4
[] = "i4";
154 static const xmlChar DT_i8
[] = "i8";
155 static const xmlChar DT_id
[] = "id";
156 static const xmlChar DT_idref
[] = "idref";
157 static const xmlChar DT_idrefs
[] = "idrefs";
158 static const xmlChar DT_int
[] = "int";
159 static const xmlChar DT_nmtoken
[] = "nmtoken";
160 static const xmlChar DT_nmtokens
[] = "nmtokens";
161 static const xmlChar DT_notation
[] = "notation";
162 static const xmlChar DT_number
[] = "number";
163 static const xmlChar DT_r4
[] = "r4";
164 static const xmlChar DT_r8
[] = "r8";
165 static const xmlChar DT_string
[] = "string";
166 static const xmlChar DT_time
[] = "time";
167 static const xmlChar DT_time_tz
[] = "time.tz";
168 static const xmlChar DT_ui1
[] = "ui1";
169 static const xmlChar DT_ui2
[] = "ui2";
170 static const xmlChar DT_ui4
[] = "ui4";
171 static const xmlChar DT_ui8
[] = "ui8";
172 static const xmlChar DT_uri
[] = "uri";
173 static const xmlChar DT_uuid
[] = "uuid";
175 static const OLECHAR wDT_bin_base64
[] = {'b','i','n','.','b','a','s','e','6','4',0};
176 static const OLECHAR wDT_bin_hex
[] = {'b','i','n','.','h','e','x',0};
177 static const OLECHAR wDT_boolean
[] = {'b','o','o','l','e','a','n',0};
178 static const OLECHAR wDT_char
[] = {'c','h','a','r',0};
179 static const OLECHAR wDT_date
[] = {'d','a','t','e',0};
180 static const OLECHAR wDT_date_tz
[] = {'d','a','t','e','.','t','z',0};
181 static const OLECHAR wDT_dateTime
[] = {'d','a','t','e','T','i','m','e',0};
182 static const OLECHAR wDT_dateTime_tz
[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
183 static const OLECHAR wDT_entity
[] = {'e','n','t','i','t','y',0};
184 static const OLECHAR wDT_entities
[] = {'e','n','t','i','t','i','e','s',0};
185 static const OLECHAR wDT_enumeration
[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
186 static const OLECHAR wDT_fixed_14_4
[] = {'f','i','x','e','d','.','1','4','.','4',0};
187 static const OLECHAR wDT_float
[] = {'f','l','o','a','t',0};
188 static const OLECHAR wDT_i1
[] = {'i','1',0};
189 static const OLECHAR wDT_i2
[] = {'i','2',0};
190 static const OLECHAR wDT_i4
[] = {'i','4',0};
191 static const OLECHAR wDT_i8
[] = {'i','8',0};
192 static const OLECHAR wDT_id
[] = {'i','d',0};
193 static const OLECHAR wDT_idref
[] = {'i','d','r','e','f',0};
194 static const OLECHAR wDT_idrefs
[] = {'i','d','r','e','f','s',0};
195 static const OLECHAR wDT_int
[] = {'i','n','t',0};
196 static const OLECHAR wDT_nmtoken
[] = {'n','m','t','o','k','e','n',0};
197 static const OLECHAR wDT_nmtokens
[] = {'n','m','t','o','k','e','n','s',0};
198 static const OLECHAR wDT_notation
[] = {'n','o','t','a','t','i','o','n',0};
199 static const OLECHAR wDT_number
[] = {'n','u','m','b','e','r',0};
200 static const OLECHAR wDT_r4
[] = {'r','4',0};
201 static const OLECHAR wDT_r8
[] = {'r','8',0};
202 static const OLECHAR wDT_string
[] = {'s','t','r','i','n','g',0};
203 static const OLECHAR wDT_time
[] = {'t','i','m','e',0};
204 static const OLECHAR wDT_time_tz
[] = {'t','i','m','e','.','t','z',0};
205 static const OLECHAR wDT_ui1
[] = {'u','i','1',0};
206 static const OLECHAR wDT_ui2
[] = {'u','i','2',0};
207 static const OLECHAR wDT_ui4
[] = {'u','i','4',0};
208 static const OLECHAR wDT_ui8
[] = {'u','i','8',0};
209 static const OLECHAR wDT_uri
[] = {'u','r','i',0};
210 static const OLECHAR wDT_uuid
[] = {'u','u','i','d',0};
212 static const BYTE hash_assoc_values
[] =
214 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
215 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
216 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
217 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
218 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
219 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
220 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
221 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
222 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
223 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
224 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
225 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
226 0, 0, 10, 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, 116, 116, 116, 116,
231 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
232 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
233 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
234 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
235 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
236 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
237 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
238 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
239 116, 116, 116, 116, 116, 116
242 static void LIBXML2_LOG_CALLBACK
parser_error(void* ctx
, char const* msg
, ...)
246 LIBXML2_CALLBACK_ERR(Schema_parse
, msg
, ap
);
250 static void LIBXML2_LOG_CALLBACK
parser_warning(void* ctx
, char const* msg
, ...)
254 LIBXML2_CALLBACK_WARN(Schema_parse
, msg
, ap
);
258 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
259 static void parser_serror(void* ctx
, xmlErrorPtr err
)
261 LIBXML2_CALLBACK_SERROR(Schema_parse
, err
);
265 static inline xmlSchemaPtr
Schema_parse(xmlSchemaParserCtxtPtr spctx
)
267 TRACE("(%p)\n", spctx
);
269 xmlSchemaSetParserErrors(spctx
, parser_error
, parser_warning
, NULL
);
270 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
271 xmlSchemaSetParserStructuredErrors(spctx
, parser_serror
, NULL
);
274 return xmlSchemaParse(spctx
);
277 static void LIBXML2_LOG_CALLBACK
validate_error(void* ctx
, char const* msg
, ...)
281 LIBXML2_CALLBACK_ERR(Schema_validate_tree
, msg
, ap
);
285 static void LIBXML2_LOG_CALLBACK
validate_warning(void* ctx
, char const* msg
, ...)
289 LIBXML2_CALLBACK_WARN(Schema_validate_tree
, msg
, ap
);
293 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
294 static void validate_serror(void* ctx
, xmlErrorPtr err
)
296 LIBXML2_CALLBACK_SERROR(Schema_validate_tree
, err
);
300 static HRESULT
schema_cache_get_item(IUnknown
*iface
, LONG index
, VARIANT
*item
)
302 V_VT(item
) = VT_BSTR
;
303 return IXMLDOMSchemaCollection2_get_namespaceURI((IXMLDOMSchemaCollection2
*)iface
, index
, &V_BSTR(item
));
306 static const struct enumvariant_funcs schemacache_enumvariant
= {
307 schema_cache_get_item
,
311 static inline HRESULT
Schema_validate_tree(xmlSchemaPtr schema
, xmlNodePtr tree
)
313 xmlSchemaValidCtxtPtr svctx
;
316 TRACE("(%p, %p)\n", schema
, tree
);
317 /* TODO: if validateOnLoad property is false,
318 * we probably need to validate the schema here. */
319 svctx
= xmlSchemaNewValidCtxt(schema
);
320 xmlSchemaSetValidErrors(svctx
, validate_error
, validate_warning
, NULL
);
321 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
322 xmlSchemaSetValidStructuredErrors(svctx
, validate_serror
, NULL
);
325 if (tree
->type
== XML_DOCUMENT_NODE
)
326 err
= xmlSchemaValidateDoc(svctx
, (xmlDocPtr
)tree
);
328 err
= xmlSchemaValidateOneElement(svctx
, tree
);
330 xmlSchemaFreeValidCtxt(svctx
);
331 return err
? S_FALSE
: S_OK
;
334 static DWORD
dt_hash(xmlChar
const* str
, int len
/* calculated if -1 */)
336 DWORD hval
= (len
== -1)? xmlStrlen(str
) : len
;
341 hval
+= hash_assoc_values
[str
[10]];
344 hval
+= hash_assoc_values
[str
[9]];
347 hval
+= hash_assoc_values
[str
[8]];
350 hval
+= hash_assoc_values
[str
[7]];
353 hval
+= hash_assoc_values
[str
[6]];
356 hval
+= hash_assoc_values
[str
[5]];
359 hval
+= hash_assoc_values
[str
[4]];
362 hval
+= hash_assoc_values
[str
[3]];
365 hval
+= hash_assoc_values
[str
[2]];
368 hval
+= hash_assoc_values
[str
[1]];
371 hval
+= hash_assoc_values
[str
[0]];
377 static DWORD
dt_hash_bstr(OLECHAR
const* bstr
, int len
/* calculated if -1 */)
379 DWORD hval
= (len
== -1)? lstrlenW(bstr
) : len
;
384 hval
+= (bstr
[10] & 0xFF00)? 116 : hash_assoc_values
[bstr
[10]];
387 hval
+= (bstr
[9] & 0xFF00)? 116 : hash_assoc_values
[bstr
[9]];
390 hval
+= (bstr
[8] & 0xFF00)? 116 : hash_assoc_values
[bstr
[8]];
393 hval
+= (bstr
[7] & 0xFF00)? 116 : hash_assoc_values
[bstr
[7]];
396 hval
+= (bstr
[6] & 0xFF00)? 116 : hash_assoc_values
[bstr
[6]];
399 hval
+= (bstr
[5] & 0xFF00)? 116 : hash_assoc_values
[bstr
[5]];
402 hval
+= (bstr
[4] & 0xFF00)? 116 : hash_assoc_values
[bstr
[4]];
405 hval
+= (bstr
[3] & 0xFF00)? 116 : hash_assoc_values
[bstr
[3]];
408 hval
+= (bstr
[2] & 0xFF00)? 116 : hash_assoc_values
[bstr
[2]];
411 hval
+= (bstr
[1] & 0xFF00)? 116 : hash_assoc_values
[bstr
[1]];
414 hval
+= (bstr
[0] & 0xFF00)? 116 : hash_assoc_values
[bstr
[0]];
420 static const xmlChar
*const DT_string_table
[LAST_DT
] =
460 static const WCHAR
*const DT_wstring_table
[LAST_DT
] =
500 static const XDR_DT DT_lookup_table
[] =
553 -1, -1, -1, -1, -1, -1, -1, -1, -1,
554 -1, -1, -1, -1, -1, -1, -1, -1, -1,
555 -1, -1, -1, -1, -1, -1, -1, -1, -1,
556 -1, -1, -1, -1, -1, -1, -1, -1, -1,
557 -1, -1, -1, -1, -1, -1, -1, -1, -1,
558 -1, -1, -1, -1, -1, -1, -1, -1,
562 XDR_DT
str_to_dt(xmlChar
const* str
, int len
/* calculated if -1 */)
564 DWORD hash
= dt_hash(str
, len
);
565 XDR_DT dt
= DT_INVALID
;
567 if (hash
<= DT_MAX_HASH_VALUE
)
568 dt
= DT_lookup_table
[hash
];
570 if (dt
!= DT_INVALID
&& xmlStrcasecmp(str
, DT_string_table
[dt
]) == 0)
576 XDR_DT
bstr_to_dt(OLECHAR
const* bstr
, int len
/* calculated if -1 */)
578 DWORD hash
= dt_hash_bstr(bstr
, len
);
579 XDR_DT dt
= DT_INVALID
;
581 if (hash
<= DT_MAX_HASH_VALUE
)
582 dt
= DT_lookup_table
[hash
];
584 if (dt
!= DT_INVALID
&& lstrcmpiW(bstr
, DT_wstring_table
[dt
]) == 0)
590 xmlChar
const* dt_to_str(XDR_DT dt
)
592 if (dt
== DT_INVALID
)
595 return DT_string_table
[dt
];
598 OLECHAR
const* dt_to_bstr(XDR_DT dt
)
600 if (dt
== DT_INVALID
)
603 return DT_wstring_table
[dt
];
606 const char* debugstr_dt(XDR_DT dt
)
608 return debugstr_a(dt
!= DT_INVALID
? (const char*)DT_string_table
[dt
] : NULL
);
611 HRESULT
dt_validate(XDR_DT dt
, xmlChar
const* content
)
618 TRACE("(dt:%s, %s)\n", debugstr_dt(dt
), debugstr_a((char const*)content
));
620 if (!datatypes_schema
)
622 xmlSchemaParserCtxtPtr spctx
;
623 assert(datatypes_src
!= NULL
);
624 spctx
= xmlSchemaNewMemParserCtxt((char const*)datatypes_src
, datatypes_len
);
625 datatypes_schema
= Schema_parse(spctx
);
626 xmlSchemaFreeParserCtxt(spctx
);
662 if (!datatypes_schema
)
664 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
665 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION
"\n");
667 /* Hopefully they don't need much in the way of XDR datatypes support... */
671 if (content
&& xmlStrlen(content
))
673 tmp_doc
= xmlNewDoc(NULL
);
674 node
= xmlNewChild((xmlNodePtr
)tmp_doc
, NULL
, dt_to_str(dt
), content
);
675 ns
= xmlNewNs(node
, DT_nsURI
, BAD_CAST
"dt");
677 xmlDocSetRootElement(tmp_doc
, node
);
679 hr
= Schema_validate_tree(datatypes_schema
, (xmlNodePtr
)tmp_doc
);
683 { /* probably the node is being created manually and has no content yet */
688 FIXME("need to handle dt:%s\n", debugstr_dt(dt
));
693 static inline xmlChar
const* get_node_nsURI(xmlNodePtr node
)
695 return (node
->ns
!= NULL
)? node
->ns
->href
: NULL
;
698 static inline cache_entry
* get_entry(schema_cache
* This
, xmlChar
const* nsURI
)
700 return (!nsURI
)? xmlHashLookup(This
->cache
, BAD_CAST
"") :
701 xmlHashLookup(This
->cache
, nsURI
);
704 static inline xmlSchemaPtr
get_node_schema(schema_cache
* This
, xmlNodePtr node
)
706 cache_entry
* entry
= get_entry(This
, get_node_nsURI(node
));
707 return (!entry
)? NULL
: entry
->schema
;
710 static xmlExternalEntityLoader _external_entity_loader
;
712 static xmlParserInputPtr
external_entity_loader(const char *URL
, const char *ID
,
713 xmlParserCtxtPtr ctxt
)
715 xmlParserInputPtr input
;
717 TRACE("(%s %s %p)\n", debugstr_a(URL
), debugstr_a(ID
), ctxt
);
719 assert(MSXML_hInstance
!= NULL
);
720 assert(datatypes_rsrc
!= NULL
);
721 assert(datatypes_handle
!= NULL
);
722 assert(datatypes_src
!= NULL
);
724 /* TODO: if the desired schema is in the cache, load it from there */
725 if (lstrcmpA(URL
, "urn:schemas-microsoft-com:datatypes") == 0)
727 TRACE("loading built-in schema for %s\n", URL
);
728 input
= xmlNewStringInputStream(ctxt
, datatypes_src
);
732 input
= _external_entity_loader(URL
, ID
, ctxt
);
738 void schemasInit(void)
741 if (!(datatypes_rsrc
= FindResourceA(MSXML_hInstance
, "DATATYPES", "XML")))
743 FIXME("failed to find resource for %s\n", DT_nsURI
);
747 if (!(datatypes_handle
= LoadResource(MSXML_hInstance
, datatypes_rsrc
)))
749 FIXME("failed to load resource for %s\n", DT_nsURI
);
752 buf
= LockResource(datatypes_handle
);
753 datatypes_len
= SizeofResource(MSXML_hInstance
, datatypes_rsrc
);
755 /* Resource is loaded as raw data,
756 * need a null-terminated string */
757 while (buf
[datatypes_len
- 1] != '>') datatypes_len
--;
758 datatypes_src
= heap_alloc(datatypes_len
+ 1);
759 memcpy(datatypes_src
, buf
, datatypes_len
);
760 datatypes_src
[datatypes_len
] = 0;
762 if (xmlGetExternalEntityLoader() != external_entity_loader
)
764 _external_entity_loader
= xmlGetExternalEntityLoader();
765 xmlSetExternalEntityLoader(external_entity_loader
);
769 void schemasCleanup(void)
771 xmlSchemaFree(datatypes_schema
);
772 heap_free(datatypes_src
);
773 xmlSetExternalEntityLoader(_external_entity_loader
);
776 static LONG
cache_entry_add_ref(cache_entry
* entry
)
778 LONG ref
= InterlockedIncrement(&entry
->ref
);
779 TRACE("(%p)->(%d)\n", entry
, ref
);
783 static LONG
cache_entry_release(cache_entry
* entry
)
785 LONG ref
= InterlockedDecrement(&entry
->ref
);
786 TRACE("(%p)->(%d)\n", entry
, ref
);
790 if (entry
->type
== CacheEntryType_XSD
)
792 xmldoc_release(entry
->doc
);
793 entry
->schema
->doc
= NULL
;
794 xmlSchemaFree(entry
->schema
);
796 else if (entry
->type
== CacheEntryType_XDR
)
798 xmldoc_release(entry
->doc
);
799 xmldoc_release(entry
->schema
->doc
);
800 entry
->schema
->doc
= NULL
;
801 xmlSchemaFree(entry
->schema
);
809 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl
;
811 static inline schema_cache
* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2
* iface
)
813 return CONTAINING_RECORD(iface
, schema_cache
, IXMLDOMSchemaCollection2_iface
);
816 static inline schema_cache
* impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection
* iface
)
818 return CONTAINING_RECORD(iface
, schema_cache
, IXMLDOMSchemaCollection2_iface
);
821 static inline schema_cache
* unsafe_impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection
*iface
)
823 return iface
->lpVtbl
== (void*)&XMLDOMSchemaCollection2Vtbl
? impl_from_IXMLDOMSchemaCollection(iface
) : NULL
;
826 static inline CacheEntryType
cache_type_from_xmlDocPtr(xmlDocPtr schema
)
828 xmlNodePtr root
= NULL
;
830 root
= xmlDocGetRootElement(schema
);
831 if (root
&& root
->ns
)
834 if (xmlStrEqual(root
->name
, XDR_schema
) &&
835 xmlStrEqual(root
->ns
->href
, XDR_nsURI
))
837 return CacheEntryType_XDR
;
839 else if (xmlStrEqual(root
->name
, XSD_schema
) &&
840 xmlStrEqual(root
->ns
->href
, XSD_nsURI
))
842 return CacheEntryType_XSD
;
845 return CacheEntryType_Invalid
;
848 static BOOL
link_datatypes(xmlDocPtr schema
)
850 xmlNodePtr root
, next
, child
;
853 assert(xmlGetExternalEntityLoader() == external_entity_loader
);
854 root
= xmlDocGetRootElement(schema
);
858 for (ns
= root
->nsDef
; ns
!= NULL
; ns
= ns
->next
)
860 if (xmlStrEqual(ns
->href
, DT_nsURI
))
867 next
= xmlFirstElementChild(root
);
868 child
= xmlNewChild(root
, NULL
, BAD_CAST
"import", NULL
);
869 if (next
) child
= xmlAddPrevSibling(next
, child
);
870 xmlSetProp(child
, BAD_CAST
"namespace", DT_nsURI
);
871 xmlSetProp(child
, BAD_CAST
"schemaLocation", DT_nsURI
);
876 static cache_entry
* cache_entry_from_xsd_doc(xmlDocPtr doc
, xmlChar
const* nsURI
, MSXML_VERSION v
)
878 cache_entry
* entry
= heap_alloc(sizeof(cache_entry
));
879 xmlSchemaParserCtxtPtr spctx
;
880 xmlDocPtr new_doc
= xmlCopyDoc(doc
, 1);
882 link_datatypes(new_doc
);
884 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
885 * do we need to do something special here? */
886 entry
->type
= CacheEntryType_XSD
;
888 spctx
= xmlSchemaNewDocParserCtxt(new_doc
);
890 if ((entry
->schema
= Schema_parse(spctx
)))
892 xmldoc_init(entry
->schema
->doc
, v
);
893 entry
->doc
= entry
->schema
->doc
;
894 xmldoc_add_ref(entry
->doc
);
898 FIXME("failed to parse doc\n");
903 xmlSchemaFreeParserCtxt(spctx
);
907 static cache_entry
* cache_entry_from_xdr_doc(xmlDocPtr doc
, xmlChar
const* nsURI
, MSXML_VERSION version
)
909 cache_entry
* entry
= heap_alloc(sizeof(cache_entry
));
910 xmlSchemaParserCtxtPtr spctx
;
911 xmlDocPtr new_doc
= xmlCopyDoc(doc
, 1), xsd_doc
= XDR_to_XSD_doc(doc
, nsURI
);
913 link_datatypes(xsd_doc
);
915 entry
->type
= CacheEntryType_XDR
;
917 spctx
= xmlSchemaNewDocParserCtxt(xsd_doc
);
919 if ((entry
->schema
= Schema_parse(spctx
)))
921 entry
->doc
= new_doc
;
922 xmldoc_init(entry
->schema
->doc
, version
);
923 xmldoc_init(entry
->doc
, version
);
924 xmldoc_add_ref(entry
->doc
);
925 xmldoc_add_ref(entry
->schema
->doc
);
929 FIXME("failed to parse doc\n");
935 xmlSchemaFreeParserCtxt(spctx
);
940 static cache_entry
* cache_entry_from_url(VARIANT url
, xmlChar
const* nsURI
, MSXML_VERSION version
)
943 IXMLDOMDocument3
* domdoc
= NULL
;
944 xmlDocPtr doc
= NULL
;
945 HRESULT hr
= DOMDocument_create(version
, (void**)&domdoc
);
946 VARIANT_BOOL b
= VARIANT_FALSE
;
947 CacheEntryType type
= CacheEntryType_Invalid
;
951 FIXME("failed to create domdoc\n");
954 assert(domdoc
!= NULL
);
955 assert(V_VT(&url
) == VT_BSTR
);
957 hr
= IXMLDOMDocument3_load(domdoc
, url
, &b
);
960 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr
);
961 if (b
!= VARIANT_TRUE
)
963 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url
)));
964 IXMLDOMDocument3_Release(domdoc
);
968 doc
= xmlNodePtr_from_domnode((IXMLDOMNode
*)domdoc
, XML_DOCUMENT_NODE
)->doc
;
969 type
= cache_type_from_xmlDocPtr(doc
);
973 case CacheEntryType_XSD
:
974 entry
= cache_entry_from_xsd_doc(doc
, nsURI
, version
);
976 case CacheEntryType_XDR
:
977 entry
= cache_entry_from_xdr_doc(doc
, nsURI
, version
);
981 FIXME("invalid schema\n");
984 IXMLDOMDocument3_Release(domdoc
);
989 static void cache_free(void* data
, XMLHASH_CONST xmlChar
* name
/* ignored */)
991 cache_entry_release((cache_entry
*)data
);
994 /* returns index or -1 if not found */
995 static int cache_free_uri(schema_cache
*cache
, const xmlChar
*uri
)
999 for (i
= 0; i
< cache
->count
; i
++)
1000 if (xmlStrEqual(cache
->uris
[i
], uri
))
1002 heap_free(cache
->uris
[i
]);
1009 static void cache_add_entry(schema_cache
*cache
, const xmlChar
*uri
, cache_entry
*entry
)
1013 /* meaning no entry found with this name */
1014 if (xmlHashRemoveEntry(cache
->cache
, uri
, cache_free
))
1016 if (cache
->count
== cache
->allocated
)
1018 cache
->allocated
*= 2;
1019 cache
->uris
= heap_realloc(cache
->uris
, cache
->allocated
*sizeof(xmlChar
*));
1024 i
= cache_free_uri(cache
, uri
);
1026 cache
->uris
[i
] = heap_strdupxmlChar(uri
);
1027 xmlHashAddEntry(cache
->cache
, uri
, entry
);
1030 static void cache_remove_entry(schema_cache
*cache
, const xmlChar
*uri
)
1032 /* adjust index if entry was really removed */
1033 if (xmlHashRemoveEntry(cache
->cache
, uri
, cache_free
) == 0)
1035 int i
= cache_free_uri(cache
, uri
);
1036 if (i
== -1) return;
1038 if (i
!= --cache
->count
)
1039 memmove(&cache
->uris
[i
], &cache
->uris
[i
+1], (cache
->count
-i
)*sizeof(xmlChar
*));
1043 /* This one adds all namespaces defined in document to a cache, without anything
1044 associated with uri obviously.
1045 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
1046 it uses additional node type to describe namespace definition attribute while
1047 in msxml it's expected to be a normal attribute - as a workaround document is
1048 queried at libxml2 level here. */
1049 HRESULT
cache_from_doc_ns(IXMLDOMSchemaCollection2
*iface
, xmlnode
*node
)
1051 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1052 static const xmlChar query
[] = "//*/namespace::*";
1053 xmlXPathObjectPtr nodeset
;
1054 xmlXPathContextPtr ctxt
;
1056 This
->read_only
= 1;
1058 ctxt
= xmlXPathNewContext(node
->node
->doc
);
1060 nodeset
= xmlXPathEvalExpression(query
, ctxt
);
1061 xmlXPathFreeContext(ctxt
);
1065 int pos
= 0, len
= xmlXPathNodeSetGetLength(nodeset
->nodesetval
);
1069 xmlNodePtr node
= xmlXPathNodeSetItem(nodeset
->nodesetval
, pos
);
1070 if (node
->type
== XML_NAMESPACE_DECL
)
1072 static const xmlChar defns
[] = "http://www.w3.org/XML/1998/namespace";
1073 xmlNsPtr ns
= (xmlNsPtr
)node
;
1076 /* filter out default uri */
1077 if (xmlStrEqual(ns
->href
, defns
))
1083 entry
= heap_alloc(sizeof(cache_entry
));
1084 entry
->type
= CacheEntryType_NS
;
1086 entry
->schema
= NULL
;
1089 cache_add_entry(This
, ns
->href
, entry
);
1094 xmlXPathFreeObject(nodeset
);
1100 static HRESULT WINAPI
schema_cache_QueryInterface(IXMLDOMSchemaCollection2
* iface
,
1101 REFIID riid
, void** ppvObject
)
1103 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1105 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1107 if ( IsEqualIID(riid
, &IID_IUnknown
) ||
1108 IsEqualIID(riid
, &IID_IDispatch
) ||
1109 IsEqualIID(riid
, &IID_IXMLDOMSchemaCollection
) ||
1110 IsEqualIID(riid
, &IID_IXMLDOMSchemaCollection2
) )
1114 else if(This
->version
== MSXML6
&& IsEqualIID(riid
, &CLSID_XMLSchemaCache60
))
1117 * Version 6 can be queried for an interface with IID equal to CLSID.
1118 * There is no public interface with that IID and returned pointer
1119 * is equal to returned IXMLDOMSchemaCollection2 iface. We assume
1120 * that it's just another way for querying IXMLDOMSchemaCollection2
1121 * interface. Office 2013 ClickToRun installer uses this.
1123 WARN("riid CLSID_XMLSchemaCache60, returning IXMLDOMSchemaCollection2 interface.\n");
1126 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
1128 return *ppvObject
? S_OK
: E_NOINTERFACE
;
1130 else if(IsEqualGUID( riid
, &IID_ISupportErrorInfo
))
1132 return node_create_supporterrorinfo(schema_cache_se_tids
, ppvObject
);
1136 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
1138 return E_NOINTERFACE
;
1141 IXMLDOMSchemaCollection2_AddRef(iface
);
1146 static ULONG WINAPI
schema_cache_AddRef(IXMLDOMSchemaCollection2
* iface
)
1148 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1149 LONG ref
= InterlockedIncrement(&This
->ref
);
1150 TRACE("(%p)->(%d)\n", This
, ref
);
1154 static ULONG WINAPI
schema_cache_Release(IXMLDOMSchemaCollection2
* iface
)
1156 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1157 LONG ref
= InterlockedDecrement(&This
->ref
);
1158 TRACE("(%p)->(%d)\n", This
, ref
);
1164 for (i
= 0; i
< This
->count
; i
++)
1165 heap_free(This
->uris
[i
]);
1166 heap_free(This
->uris
);
1167 xmlHashFree(This
->cache
, cache_free
);
1174 static HRESULT WINAPI
schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2
* iface
,
1177 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1178 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
1181 static HRESULT WINAPI
schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2
* iface
,
1182 UINT iTInfo
, LCID lcid
, ITypeInfo
** ppTInfo
)
1184 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1185 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
1186 iTInfo
, lcid
, ppTInfo
);
1189 static HRESULT WINAPI
schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2
* iface
,
1190 REFIID riid
, LPOLESTR
* rgszNames
,
1191 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
1193 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1194 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
1195 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
1198 static HRESULT WINAPI
schema_cache_Invoke(IXMLDOMSchemaCollection2
* iface
,
1199 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
1200 WORD wFlags
, DISPPARAMS
* pDispParams
,
1201 VARIANT
* pVarResult
, EXCEPINFO
* pExcepInfo
,
1204 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1205 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
1206 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1209 static HRESULT WINAPI
schema_cache_add(IXMLDOMSchemaCollection2
* iface
, BSTR uri
, VARIANT var
)
1211 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1214 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(uri
), debugstr_variant(&var
));
1216 if (This
->read_only
) return E_FAIL
;
1218 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1224 cache_remove_entry(This
, name
);
1230 cache_entry
* entry
= cache_entry_from_url(var
, name
, This
->version
);
1234 cache_entry_add_ref(entry
);
1242 cache_add_entry(This
, name
, entry
);
1249 xmlDocPtr doc
= NULL
;
1251 CacheEntryType type
;
1252 IXMLDOMNode
* domnode
= NULL
;
1253 IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IXMLDOMNode
, (void**)&domnode
);
1259 IXMLDOMNode_get_nodeType(domnode
, &type
);
1264 IXMLDOMDocument
*domdoc
;
1268 IXMLDOMNode_get_xml(domnode
, &xml
);
1269 DOMDocument_create(This
->version
, (void**)&domdoc
);
1270 IXMLDOMDocument_loadXML(domdoc
, xml
, &b
);
1272 doc
= xmlNodePtr_from_domnode((IXMLDOMNode
*)domdoc
, XML_DOCUMENT_NODE
)->doc
;
1276 doc
= xmlNodePtr_from_domnode(domnode
, XML_DOCUMENT_NODE
)->doc
;
1283 IXMLDOMNode_Release(domnode
);
1285 return E_INVALIDARG
;
1287 type
= cache_type_from_xmlDocPtr(doc
);
1289 if (type
== CacheEntryType_XSD
)
1291 entry
= cache_entry_from_xsd_doc(doc
, name
, This
->version
);
1293 else if (type
== CacheEntryType_XDR
)
1295 entry
= cache_entry_from_xdr_doc(doc
, name
, This
->version
);
1299 WARN("invalid schema!\n");
1303 IXMLDOMNode_Release(domnode
);
1307 cache_entry_add_ref(entry
);
1315 cache_add_entry(This
, name
, entry
);
1320 FIXME("arg type is not supported, %s\n", debugstr_variant(&var
));
1322 return E_INVALIDARG
;
1328 static HRESULT WINAPI
schema_cache_get(IXMLDOMSchemaCollection2
* iface
, BSTR uri
,
1331 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1335 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(uri
), node
);
1337 if (This
->version
== MSXML6
)
1339 if (node
) *node
= NULL
;
1348 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1349 entry
= (cache_entry
*) xmlHashLookup(This
->cache
, name
);
1352 /* TODO: this should be read-only */
1353 if (entry
&& entry
->doc
)
1354 return get_domdoc_from_xmldoc(entry
->doc
, (IXMLDOMDocument3
**)node
);
1359 static HRESULT WINAPI
schema_cache_remove(IXMLDOMSchemaCollection2
* iface
, BSTR uri
)
1361 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1364 TRACE("(%p)->(%s)\n", This
, debugstr_w(uri
));
1366 if (This
->version
== MSXML6
) return E_NOTIMPL
;
1368 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1369 cache_remove_entry(This
, name
);
1374 static HRESULT WINAPI
schema_cache_get_length(IXMLDOMSchemaCollection2
* iface
, LONG
* length
)
1376 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1377 TRACE("(%p)->(%p)\n", This
, length
);
1382 *length
= This
->count
;
1386 static HRESULT WINAPI
schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2
* iface
,
1387 LONG index
, BSTR
* uri
)
1389 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1391 TRACE("(%p)->(%i %p)\n", This
, index
, uri
);
1396 if (This
->version
== MSXML6
)
1399 if (index
>= This
->count
)
1402 *uri
= bstr_from_xmlChar(This
->uris
[index
]);
1406 static void cache_copy(void* data
, void* dest
, XMLHASH_CONST xmlChar
* name
)
1408 schema_cache
* This
= (schema_cache
*) dest
;
1409 cache_entry
* entry
= (cache_entry
*) data
;
1411 if (xmlHashLookup(This
->cache
, name
) == NULL
)
1413 cache_entry_add_ref(entry
);
1414 cache_add_entry(This
, name
, entry
);
1418 static HRESULT WINAPI
schema_cache_addCollection(IXMLDOMSchemaCollection2
* iface
,
1419 IXMLDOMSchemaCollection
* collection
)
1421 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1424 TRACE("(%p)->(%p)\n", This
, collection
);
1429 That
= unsafe_impl_from_IXMLDOMSchemaCollection(collection
);
1432 ERR("external collection implementation\n");
1436 /* TODO: detect errors while copying & return E_FAIL */
1437 xmlHashScan(That
->cache
, cache_copy
, This
);
1442 static HRESULT WINAPI
schema_cache_get__newEnum(IXMLDOMSchemaCollection2
* iface
, IUnknown
** enumv
)
1444 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1445 TRACE("(%p)->(%p)\n", This
, enumv
);
1446 return create_enumvariant((IUnknown
*)iface
, TRUE
, &schemacache_enumvariant
, (IEnumVARIANT
**)enumv
);
1449 static HRESULT WINAPI
schema_cache_validate(IXMLDOMSchemaCollection2
* iface
)
1451 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1452 FIXME("(%p): stub\n", This
);
1456 static HRESULT WINAPI
schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2
* iface
,
1459 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1460 FIXME("(%p)->(%d): stub\n", This
, value
);
1462 This
->validateOnLoad
= value
;
1463 /* it's ok to disable it, cause we don't validate on load anyway */
1464 if (value
== VARIANT_FALSE
) return S_OK
;
1469 static HRESULT WINAPI
schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2
* iface
,
1470 VARIANT_BOOL
* value
)
1472 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1473 TRACE("(%p)->(%p)\n", This
, value
);
1475 if (!value
) return E_POINTER
;
1476 *value
= This
->validateOnLoad
;
1481 static HRESULT WINAPI
schema_cache_getSchema(IXMLDOMSchemaCollection2
* iface
,
1482 BSTR namespaceURI
, ISchema
** schema
)
1484 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1485 FIXME("(%p)->(%s %p): stub\n", This
, debugstr_w(namespaceURI
), schema
);
1491 static HRESULT WINAPI
schema_cache_getDeclaration(IXMLDOMSchemaCollection2
* iface
,
1492 IXMLDOMNode
* node
, ISchemaItem
** item
)
1494 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1495 FIXME("(%p)->(%p %p): stub\n", This
, node
, item
);
1501 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl
=
1503 schema_cache_QueryInterface
,
1504 schema_cache_AddRef
,
1505 schema_cache_Release
,
1506 schema_cache_GetTypeInfoCount
,
1507 schema_cache_GetTypeInfo
,
1508 schema_cache_GetIDsOfNames
,
1509 schema_cache_Invoke
,
1512 schema_cache_remove
,
1513 schema_cache_get_length
,
1514 schema_cache_get_namespaceURI
,
1515 schema_cache_addCollection
,
1516 schema_cache_get__newEnum
,
1517 schema_cache_validate
,
1518 schema_cache_put_validateOnLoad
,
1519 schema_cache_get_validateOnLoad
,
1520 schema_cache_getSchema
,
1521 schema_cache_getDeclaration
1524 static xmlSchemaElementPtr
lookup_schema_elemDecl(xmlSchemaPtr schema
, xmlNodePtr node
)
1526 xmlSchemaElementPtr decl
= NULL
;
1527 xmlChar
const* nsURI
= get_node_nsURI(node
);
1529 TRACE("(%p, %p)\n", schema
, node
);
1531 if (xmlStrEqual(nsURI
, schema
->targetNamespace
))
1532 decl
= xmlHashLookup(schema
->elemDecl
, node
->name
);
1534 if (!decl
&& xmlHashSize(schema
->schemasImports
) > 1)
1536 FIXME("declaration not found in main schema - need to check schema imports!\n");
1537 /*xmlSchemaImportPtr import;
1539 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1541 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1544 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1550 static inline xmlNodePtr
lookup_schema_element(xmlSchemaPtr schema
, xmlNodePtr node
)
1552 xmlSchemaElementPtr decl
= lookup_schema_elemDecl(schema
, node
);
1553 while (decl
!= NULL
&& decl
->refDecl
!= NULL
)
1554 decl
= decl
->refDecl
;
1555 return (decl
!= NULL
)? decl
->node
: NULL
;
1558 HRESULT
SchemaCache_validate_tree(IXMLDOMSchemaCollection2
* iface
, xmlNodePtr tree
)
1560 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1561 xmlSchemaPtr schema
;
1563 TRACE("(%p, %p)\n", This
, tree
);
1568 if (tree
->type
== XML_DOCUMENT_NODE
)
1569 tree
= xmlDocGetRootElement(tree
->doc
);
1571 schema
= get_node_schema(This
, tree
);
1572 /* TODO: if the ns is not in the cache, and it's a URL,
1573 * do we try to load from that? */
1575 return Schema_validate_tree(schema
, tree
);
1577 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree
));
1582 XDR_DT
SchemaCache_get_node_dt(IXMLDOMSchemaCollection2
* iface
, xmlNodePtr node
)
1584 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1585 xmlSchemaPtr schema
= get_node_schema(This
, node
);
1586 XDR_DT dt
= DT_INVALID
;
1588 TRACE("(%p, %p)\n", This
, node
);
1590 if (node
->ns
&& xmlStrEqual(node
->ns
->href
, DT_nsURI
))
1592 dt
= str_to_dt(node
->name
, -1);
1597 xmlNodePtr schema_node
= lookup_schema_element(schema
, node
);
1599 str
= xmlGetNsProp(schema_node
, BAD_CAST
"dt", DT_nsURI
);
1602 dt
= str_to_dt(str
, -1);
1610 static const tid_t schemacache_iface_tids
[] = {
1611 IXMLDOMSchemaCollection2_tid
,
1615 static dispex_static_data_t schemacache_dispex
= {
1617 IXMLDOMSchemaCollection2_tid
,
1619 schemacache_iface_tids
1622 HRESULT
SchemaCache_create(MSXML_VERSION version
, void** obj
)
1624 schema_cache
* This
= heap_alloc(sizeof(schema_cache
));
1626 return E_OUTOFMEMORY
;
1628 TRACE("(%d %p)\n", version
, obj
);
1630 This
->IXMLDOMSchemaCollection2_iface
.lpVtbl
= &XMLDOMSchemaCollection2Vtbl
;
1631 This
->cache
= xmlHashCreate(DEFAULT_HASHTABLE_SIZE
);
1632 This
->allocated
= 10;
1634 This
->uris
= heap_alloc(This
->allocated
*sizeof(xmlChar
*));
1636 This
->version
= version
;
1637 This
->validateOnLoad
= VARIANT_TRUE
;
1638 This
->read_only
= 0;
1639 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXMLDOMSchemaCollection2_iface
, &schemacache_dispex
);
1641 *obj
= &This
->IXMLDOMSchemaCollection2_iface
;
1647 HRESULT
SchemaCache_create(MSXML_VERSION version
, void** obj
)
1649 MESSAGE("This program tried to use a SchemaCache object, but\n"
1650 "libxml2 support was not present at compile time.\n");