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
27 # include <libxml/xmlschemas.h>
28 # include <libxml/schemasInternals.h>
29 # include <libxml/parserInternals.h>
30 # include <libxml/xpath.h>
33 /* We use a chained hashtable, which can hold any number of schemas
34 * TODO: grow/shrink hashtable depending on load factor
35 * TODO: implement read-only where appropriate
38 /* This is just the number of buckets, should be prime */
39 #define DEFAULT_HASHTABLE_SIZE 17
43 xmlDocPtr
XDR_to_XSD_doc(xmlDocPtr xdr_doc
, xmlChar
const* nsURI
);
45 static const xmlChar XSD_schema
[] = "schema";
46 static const xmlChar XSD_nsURI
[] = "http://www.w3.org/2001/XMLSchema";
47 static const xmlChar XDR_schema
[] = "Schema";
48 static const xmlChar XDR_nsURI
[] = "urn:schemas-microsoft-com:xml-data";
49 static const xmlChar DT_nsURI
[] = "urn:schemas-microsoft-com:datatypes";
51 static xmlChar
* datatypes_src
;
52 static int datatypes_len
;
53 static HGLOBAL datatypes_handle
;
54 static HRSRC datatypes_rsrc
;
55 static xmlSchemaPtr datatypes_schema
;
57 static const WCHAR emptyW
[] = {0};
65 * CacheType_NS is a special type used for read-only collection build with
66 * IXMLDOMDocument2::namespaces()
69 CacheEntryType_Invalid
,
78 IXMLDOMSchemaCollection2 IXMLDOMSchemaCollection2_iface
;
81 MSXML_VERSION version
;
82 xmlHashTablePtr cache
;
87 VARIANT_BOOL validateOnLoad
;
99 static const tid_t schema_cache_se_tids
[] = {
100 IXMLDOMSchemaCollection_tid
,
101 IXMLDOMSchemaCollection2_tid
,
105 /* datatypes lookup stuff
106 * generated with help from gperf */
107 #define DT_MIN_STR_LEN 2
108 #define DT_MAX_STR_LEN 11
109 #define DT_MIN_HASH_VALUE 2
110 #define DT_MAX_HASH_VALUE 115
112 static const xmlChar DT_bin_base64
[] = "bin.base64";
113 static const xmlChar DT_bin_hex
[] = "bin.hex";
114 static const xmlChar DT_boolean
[] = "boolean";
115 static const xmlChar DT_char
[] = "char";
116 static const xmlChar DT_date
[] = "date";
117 static const xmlChar DT_date_tz
[] = "date.tz";
118 static const xmlChar DT_dateTime
[] = "dateTime";
119 static const xmlChar DT_dateTime_tz
[] = "dateTime.tz";
120 static const xmlChar DT_entity
[] = "entity";
121 static const xmlChar DT_entities
[] = "entities";
122 static const xmlChar DT_enumeration
[] = "enumeration";
123 static const xmlChar DT_fixed_14_4
[] = "fixed.14.4";
124 static const xmlChar DT_float
[] = "float";
125 static const xmlChar DT_i1
[] = "i1";
126 static const xmlChar DT_i2
[] = "i2";
127 static const xmlChar DT_i4
[] = "i4";
128 static const xmlChar DT_i8
[] = "i8";
129 static const xmlChar DT_id
[] = "id";
130 static const xmlChar DT_idref
[] = "idref";
131 static const xmlChar DT_idrefs
[] = "idrefs";
132 static const xmlChar DT_int
[] = "int";
133 static const xmlChar DT_nmtoken
[] = "nmtoken";
134 static const xmlChar DT_nmtokens
[] = "nmtokens";
135 static const xmlChar DT_notation
[] = "notation";
136 static const xmlChar DT_number
[] = "number";
137 static const xmlChar DT_r4
[] = "r4";
138 static const xmlChar DT_r8
[] = "r8";
139 static const xmlChar DT_string
[] = "string";
140 static const xmlChar DT_time
[] = "time";
141 static const xmlChar DT_time_tz
[] = "time.tz";
142 static const xmlChar DT_ui1
[] = "ui1";
143 static const xmlChar DT_ui2
[] = "ui2";
144 static const xmlChar DT_ui4
[] = "ui4";
145 static const xmlChar DT_ui8
[] = "ui8";
146 static const xmlChar DT_uri
[] = "uri";
147 static const xmlChar DT_uuid
[] = "uuid";
149 static const OLECHAR wDT_bin_base64
[] = {'b','i','n','.','b','a','s','e','6','4',0};
150 static const OLECHAR wDT_bin_hex
[] = {'b','i','n','.','h','e','x',0};
151 static const OLECHAR wDT_boolean
[] = {'b','o','o','l','e','a','n',0};
152 static const OLECHAR wDT_char
[] = {'c','h','a','r',0};
153 static const OLECHAR wDT_date
[] = {'d','a','t','e',0};
154 static const OLECHAR wDT_date_tz
[] = {'d','a','t','e','.','t','z',0};
155 static const OLECHAR wDT_dateTime
[] = {'d','a','t','e','T','i','m','e',0};
156 static const OLECHAR wDT_dateTime_tz
[] = {'d','a','t','e','T','i','m','e','.','t','z',0};
157 static const OLECHAR wDT_entity
[] = {'e','n','t','i','t','y',0};
158 static const OLECHAR wDT_entities
[] = {'e','n','t','i','t','i','e','s',0};
159 static const OLECHAR wDT_enumeration
[] = {'e','n','u','m','e','r','a','t','i','o','n',0};
160 static const OLECHAR wDT_fixed_14_4
[] = {'f','i','x','e','d','.','1','4','.','4',0};
161 static const OLECHAR wDT_float
[] = {'f','l','o','a','t',0};
162 static const OLECHAR wDT_i1
[] = {'i','1',0};
163 static const OLECHAR wDT_i2
[] = {'i','2',0};
164 static const OLECHAR wDT_i4
[] = {'i','4',0};
165 static const OLECHAR wDT_i8
[] = {'i','8',0};
166 static const OLECHAR wDT_id
[] = {'i','d',0};
167 static const OLECHAR wDT_idref
[] = {'i','d','r','e','f',0};
168 static const OLECHAR wDT_idrefs
[] = {'i','d','r','e','f','s',0};
169 static const OLECHAR wDT_int
[] = {'i','n','t',0};
170 static const OLECHAR wDT_nmtoken
[] = {'n','m','t','o','k','e','n',0};
171 static const OLECHAR wDT_nmtokens
[] = {'n','m','t','o','k','e','n','s',0};
172 static const OLECHAR wDT_notation
[] = {'n','o','t','a','t','i','o','n',0};
173 static const OLECHAR wDT_number
[] = {'n','u','m','b','e','r',0};
174 static const OLECHAR wDT_r4
[] = {'r','4',0};
175 static const OLECHAR wDT_r8
[] = {'r','8',0};
176 static const OLECHAR wDT_string
[] = {'s','t','r','i','n','g',0};
177 static const OLECHAR wDT_time
[] = {'t','i','m','e',0};
178 static const OLECHAR wDT_time_tz
[] = {'t','i','m','e','.','t','z',0};
179 static const OLECHAR wDT_ui1
[] = {'u','i','1',0};
180 static const OLECHAR wDT_ui2
[] = {'u','i','2',0};
181 static const OLECHAR wDT_ui4
[] = {'u','i','4',0};
182 static const OLECHAR wDT_ui8
[] = {'u','i','8',0};
183 static const OLECHAR wDT_uri
[] = {'u','r','i',0};
184 static const OLECHAR wDT_uuid
[] = {'u','u','i','d',0};
186 static const BYTE hash_assoc_values
[] =
188 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
189 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
190 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
191 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
192 116, 116, 116, 116, 116, 116, 10, 116, 116, 55,
193 45, 116, 5, 116, 0, 116, 0, 116, 116, 116,
194 116, 116, 116, 116, 116, 5, 0, 0, 20, 0,
195 0, 10, 0, 0, 116, 0, 0, 0, 15, 5,
196 116, 116, 10, 0, 0, 0, 116, 116, 0, 0,
197 10, 116, 116, 116, 116, 116, 116, 5, 0, 0,
198 20, 0, 0, 10, 0, 0, 116, 0, 0, 0,
199 15, 5, 116, 116, 10, 0, 0, 0, 116, 116,
200 0, 0, 10, 116, 116, 116, 116, 116, 116, 116,
201 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
202 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
203 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
204 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
205 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
206 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
207 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
208 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
209 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
210 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
211 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
212 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
213 116, 116, 116, 116, 116, 116
216 static void LIBXML2_LOG_CALLBACK
parser_error(void* ctx
, char const* msg
, ...)
220 LIBXML2_CALLBACK_ERR(Schema_parse
, msg
, ap
);
224 static void LIBXML2_LOG_CALLBACK
parser_warning(void* ctx
, char const* msg
, ...)
228 LIBXML2_CALLBACK_WARN(Schema_parse
, msg
, ap
);
232 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
233 static void parser_serror(void* ctx
, xmlErrorPtr err
)
235 LIBXML2_CALLBACK_SERROR(Schema_parse
, err
);
239 static inline xmlSchemaPtr
Schema_parse(xmlSchemaParserCtxtPtr spctx
)
241 TRACE("(%p)\n", spctx
);
243 xmlSchemaSetParserErrors(spctx
, parser_error
, parser_warning
, NULL
);
244 #ifdef HAVE_XMLSCHEMASSETPARSERSTRUCTUREDERRORS
245 xmlSchemaSetParserStructuredErrors(spctx
, parser_serror
, NULL
);
248 return xmlSchemaParse(spctx
);
251 static void LIBXML2_LOG_CALLBACK
validate_error(void* ctx
, char const* msg
, ...)
255 LIBXML2_CALLBACK_ERR(Schema_validate_tree
, msg
, ap
);
259 static void LIBXML2_LOG_CALLBACK
validate_warning(void* ctx
, char const* msg
, ...)
263 LIBXML2_CALLBACK_WARN(Schema_validate_tree
, msg
, ap
);
267 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
268 static void validate_serror(void* ctx
, xmlErrorPtr err
)
270 LIBXML2_CALLBACK_SERROR(Schema_validate_tree
, err
);
274 static HRESULT
schema_cache_get_item(IUnknown
*iface
, LONG index
, VARIANT
*item
)
276 V_VT(item
) = VT_BSTR
;
277 return IXMLDOMSchemaCollection2_get_namespaceURI((IXMLDOMSchemaCollection2
*)iface
, index
, &V_BSTR(item
));
280 static const struct enumvariant_funcs schemacache_enumvariant
= {
281 schema_cache_get_item
,
285 static inline HRESULT
Schema_validate_tree(xmlSchemaPtr schema
, xmlNodePtr tree
)
287 xmlSchemaValidCtxtPtr svctx
;
290 TRACE("(%p, %p)\n", schema
, tree
);
291 /* TODO: if validateOnLoad property is false,
292 * we probably need to validate the schema here. */
293 svctx
= xmlSchemaNewValidCtxt(schema
);
294 xmlSchemaSetValidErrors(svctx
, validate_error
, validate_warning
, NULL
);
295 #ifdef HAVE_XMLSCHEMASSETVALIDSTRUCTUREDERRORS
296 xmlSchemaSetValidStructuredErrors(svctx
, validate_serror
, NULL
);
299 if (tree
->type
== XML_DOCUMENT_NODE
)
300 err
= xmlSchemaValidateDoc(svctx
, (xmlDocPtr
)tree
);
302 err
= xmlSchemaValidateOneElement(svctx
, tree
);
304 xmlSchemaFreeValidCtxt(svctx
);
305 return err
? S_FALSE
: S_OK
;
308 static DWORD
dt_hash(xmlChar
const* str
, int len
/* calculated if -1 */)
310 DWORD hval
= (len
== -1)? xmlStrlen(str
) : len
;
315 hval
+= hash_assoc_values
[str
[10]];
318 hval
+= hash_assoc_values
[str
[9]];
321 hval
+= hash_assoc_values
[str
[8]];
324 hval
+= hash_assoc_values
[str
[7]];
327 hval
+= hash_assoc_values
[str
[6]];
330 hval
+= hash_assoc_values
[str
[5]];
333 hval
+= hash_assoc_values
[str
[4]];
336 hval
+= hash_assoc_values
[str
[3]];
339 hval
+= hash_assoc_values
[str
[2]];
342 hval
+= hash_assoc_values
[str
[1]];
345 hval
+= hash_assoc_values
[str
[0]];
351 static DWORD
dt_hash_bstr(OLECHAR
const* bstr
, int len
/* calculated if -1 */)
353 DWORD hval
= (len
== -1)? lstrlenW(bstr
) : len
;
358 hval
+= (bstr
[10] & 0xFF00)? 116 : hash_assoc_values
[bstr
[10]];
361 hval
+= (bstr
[9] & 0xFF00)? 116 : hash_assoc_values
[bstr
[9]];
364 hval
+= (bstr
[8] & 0xFF00)? 116 : hash_assoc_values
[bstr
[8]];
367 hval
+= (bstr
[7] & 0xFF00)? 116 : hash_assoc_values
[bstr
[7]];
370 hval
+= (bstr
[6] & 0xFF00)? 116 : hash_assoc_values
[bstr
[6]];
373 hval
+= (bstr
[5] & 0xFF00)? 116 : hash_assoc_values
[bstr
[5]];
376 hval
+= (bstr
[4] & 0xFF00)? 116 : hash_assoc_values
[bstr
[4]];
379 hval
+= (bstr
[3] & 0xFF00)? 116 : hash_assoc_values
[bstr
[3]];
382 hval
+= (bstr
[2] & 0xFF00)? 116 : hash_assoc_values
[bstr
[2]];
385 hval
+= (bstr
[1] & 0xFF00)? 116 : hash_assoc_values
[bstr
[1]];
388 hval
+= (bstr
[0] & 0xFF00)? 116 : hash_assoc_values
[bstr
[0]];
394 static const xmlChar
*const DT_string_table
[LAST_DT
] =
434 static const WCHAR
*const DT_wstring_table
[LAST_DT
] =
474 static const XDR_DT DT_lookup_table
[] =
527 -1, -1, -1, -1, -1, -1, -1, -1, -1,
528 -1, -1, -1, -1, -1, -1, -1, -1, -1,
529 -1, -1, -1, -1, -1, -1, -1, -1, -1,
530 -1, -1, -1, -1, -1, -1, -1, -1, -1,
531 -1, -1, -1, -1, -1, -1, -1, -1, -1,
532 -1, -1, -1, -1, -1, -1, -1, -1,
536 XDR_DT
str_to_dt(xmlChar
const* str
, int len
/* calculated if -1 */)
538 DWORD hash
= dt_hash(str
, len
);
539 XDR_DT dt
= DT_INVALID
;
541 if (hash
<= DT_MAX_HASH_VALUE
)
542 dt
= DT_lookup_table
[hash
];
544 if (dt
!= DT_INVALID
&& xmlStrcasecmp(str
, DT_string_table
[dt
]) == 0)
550 XDR_DT
bstr_to_dt(OLECHAR
const* bstr
, int len
/* calculated if -1 */)
552 DWORD hash
= dt_hash_bstr(bstr
, len
);
553 XDR_DT dt
= DT_INVALID
;
555 if (hash
<= DT_MAX_HASH_VALUE
)
556 dt
= DT_lookup_table
[hash
];
558 if (dt
!= DT_INVALID
&& lstrcmpiW(bstr
, DT_wstring_table
[dt
]) == 0)
564 xmlChar
const* dt_to_str(XDR_DT dt
)
566 if (dt
== DT_INVALID
)
569 return DT_string_table
[dt
];
572 OLECHAR
const* dt_to_bstr(XDR_DT dt
)
574 if (dt
== DT_INVALID
)
577 return DT_wstring_table
[dt
];
580 const char* debugstr_dt(XDR_DT dt
)
582 return debugstr_a(dt
!= DT_INVALID
? (const char*)DT_string_table
[dt
] : NULL
);
585 HRESULT
dt_validate(XDR_DT dt
, xmlChar
const* content
)
592 TRACE("(dt:%s, %s)\n", debugstr_dt(dt
), debugstr_a((char const*)content
));
594 if (!datatypes_schema
)
596 xmlSchemaParserCtxtPtr spctx
;
597 assert(datatypes_src
!= NULL
);
598 spctx
= xmlSchemaNewMemParserCtxt((char const*)datatypes_src
, datatypes_len
);
599 datatypes_schema
= Schema_parse(spctx
);
600 xmlSchemaFreeParserCtxt(spctx
);
636 if (!datatypes_schema
)
638 ERR("failed to load schema for urn:schemas-microsoft-com:datatypes, "
639 "you're probably using an old version of libxml2: " LIBXML_DOTTED_VERSION
"\n");
641 /* Hopefully they don't need much in the way of XDR datatypes support... */
645 if (content
&& xmlStrlen(content
))
647 tmp_doc
= xmlNewDoc(NULL
);
648 node
= xmlNewChild((xmlNodePtr
)tmp_doc
, NULL
, dt_to_str(dt
), content
);
649 ns
= xmlNewNs(node
, DT_nsURI
, BAD_CAST
"dt");
651 xmlDocSetRootElement(tmp_doc
, node
);
653 hr
= Schema_validate_tree(datatypes_schema
, (xmlNodePtr
)tmp_doc
);
657 { /* probably the node is being created manually and has no content yet */
662 FIXME("need to handle dt:%s\n", debugstr_dt(dt
));
667 static inline xmlChar
const* get_node_nsURI(xmlNodePtr node
)
669 return (node
->ns
!= NULL
)? node
->ns
->href
: NULL
;
672 static inline cache_entry
* get_entry(schema_cache
* This
, xmlChar
const* nsURI
)
674 return (!nsURI
)? xmlHashLookup(This
->cache
, BAD_CAST
"") :
675 xmlHashLookup(This
->cache
, nsURI
);
678 static inline xmlSchemaPtr
get_node_schema(schema_cache
* This
, xmlNodePtr node
)
680 cache_entry
* entry
= get_entry(This
, get_node_nsURI(node
));
681 return (!entry
)? NULL
: entry
->schema
;
684 static xmlExternalEntityLoader _external_entity_loader
;
686 static xmlParserInputPtr
external_entity_loader(const char *URL
, const char *ID
,
687 xmlParserCtxtPtr ctxt
)
689 xmlParserInputPtr input
;
691 TRACE("(%s %s %p)\n", debugstr_a(URL
), debugstr_a(ID
), ctxt
);
693 assert(MSXML_hInstance
!= NULL
);
694 assert(datatypes_rsrc
!= NULL
);
695 assert(datatypes_handle
!= NULL
);
696 assert(datatypes_src
!= NULL
);
698 /* TODO: if the desired schema is in the cache, load it from there */
699 if (lstrcmpA(URL
, "urn:schemas-microsoft-com:datatypes") == 0)
701 TRACE("loading built-in schema for %s\n", URL
);
702 input
= xmlNewStringInputStream(ctxt
, datatypes_src
);
706 input
= _external_entity_loader(URL
, ID
, ctxt
);
712 void schemasInit(void)
715 if (!(datatypes_rsrc
= FindResourceA(MSXML_hInstance
, "DATATYPES", "XML")))
717 FIXME("failed to find resource for %s\n", DT_nsURI
);
721 if (!(datatypes_handle
= LoadResource(MSXML_hInstance
, datatypes_rsrc
)))
723 FIXME("failed to load resource for %s\n", DT_nsURI
);
726 buf
= LockResource(datatypes_handle
);
727 datatypes_len
= SizeofResource(MSXML_hInstance
, datatypes_rsrc
);
729 /* Resource is loaded as raw data,
730 * need a null-terminated string */
731 while (buf
[datatypes_len
- 1] != '>') datatypes_len
--;
732 datatypes_src
= HeapAlloc(GetProcessHeap(), 0, datatypes_len
+ 1);
733 memcpy(datatypes_src
, buf
, datatypes_len
);
734 datatypes_src
[datatypes_len
] = 0;
736 if (xmlGetExternalEntityLoader() != external_entity_loader
)
738 _external_entity_loader
= xmlGetExternalEntityLoader();
739 xmlSetExternalEntityLoader(external_entity_loader
);
743 void schemasCleanup(void)
745 xmlSchemaFree(datatypes_schema
);
746 HeapFree(GetProcessHeap(), 0, datatypes_src
);
747 xmlSetExternalEntityLoader(_external_entity_loader
);
750 static LONG
cache_entry_add_ref(cache_entry
* entry
)
752 LONG ref
= InterlockedIncrement(&entry
->ref
);
753 TRACE("(%p)->(%d)\n", entry
, ref
);
757 static LONG
cache_entry_release(cache_entry
* entry
)
759 LONG ref
= InterlockedDecrement(&entry
->ref
);
760 TRACE("(%p)->(%d)\n", entry
, ref
);
764 if (entry
->type
== CacheEntryType_XSD
)
766 xmldoc_release(entry
->doc
);
767 entry
->schema
->doc
= NULL
;
768 xmlSchemaFree(entry
->schema
);
770 else if (entry
->type
== CacheEntryType_XDR
)
772 xmldoc_release(entry
->doc
);
773 xmldoc_release(entry
->schema
->doc
);
774 entry
->schema
->doc
= NULL
;
775 xmlSchemaFree(entry
->schema
);
783 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl
;
785 static inline schema_cache
* impl_from_IXMLDOMSchemaCollection2(IXMLDOMSchemaCollection2
* iface
)
787 return CONTAINING_RECORD(iface
, schema_cache
, IXMLDOMSchemaCollection2_iface
);
790 static inline schema_cache
* impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection
* iface
)
792 return CONTAINING_RECORD(iface
, schema_cache
, IXMLDOMSchemaCollection2_iface
);
795 static inline schema_cache
* unsafe_impl_from_IXMLDOMSchemaCollection(IXMLDOMSchemaCollection
*iface
)
797 return iface
->lpVtbl
== (void*)&XMLDOMSchemaCollection2Vtbl
? impl_from_IXMLDOMSchemaCollection(iface
) : NULL
;
800 static inline CacheEntryType
cache_type_from_xmlDocPtr(xmlDocPtr schema
)
802 xmlNodePtr root
= NULL
;
804 root
= xmlDocGetRootElement(schema
);
805 if (root
&& root
->ns
)
808 if (xmlStrEqual(root
->name
, XDR_schema
) &&
809 xmlStrEqual(root
->ns
->href
, XDR_nsURI
))
811 return CacheEntryType_XDR
;
813 else if (xmlStrEqual(root
->name
, XSD_schema
) &&
814 xmlStrEqual(root
->ns
->href
, XSD_nsURI
))
816 return CacheEntryType_XSD
;
819 return CacheEntryType_Invalid
;
822 static BOOL
link_datatypes(xmlDocPtr schema
)
824 xmlNodePtr root
, next
, child
;
827 assert(xmlGetExternalEntityLoader() == external_entity_loader
);
828 root
= xmlDocGetRootElement(schema
);
832 for (ns
= root
->nsDef
; ns
!= NULL
; ns
= ns
->next
)
834 if (xmlStrEqual(ns
->href
, DT_nsURI
))
841 next
= xmlFirstElementChild(root
);
842 child
= xmlNewChild(root
, NULL
, BAD_CAST
"import", NULL
);
843 if (next
) child
= xmlAddPrevSibling(next
, child
);
844 xmlSetProp(child
, BAD_CAST
"namespace", DT_nsURI
);
845 xmlSetProp(child
, BAD_CAST
"schemaLocation", DT_nsURI
);
850 static cache_entry
* cache_entry_from_xsd_doc(xmlDocPtr doc
, xmlChar
const* nsURI
, MSXML_VERSION v
)
852 cache_entry
* entry
= heap_alloc(sizeof(cache_entry
));
853 xmlSchemaParserCtxtPtr spctx
;
854 xmlDocPtr new_doc
= xmlCopyDoc(doc
, 1);
856 link_datatypes(new_doc
);
858 /* TODO: if the nsURI is different from the default xmlns or targetNamespace,
859 * do we need to do something special here? */
860 entry
->type
= CacheEntryType_XSD
;
862 spctx
= xmlSchemaNewDocParserCtxt(new_doc
);
864 if ((entry
->schema
= Schema_parse(spctx
)))
866 xmldoc_init(entry
->schema
->doc
, v
);
867 entry
->doc
= entry
->schema
->doc
;
868 xmldoc_add_ref(entry
->doc
);
872 FIXME("failed to parse doc\n");
877 xmlSchemaFreeParserCtxt(spctx
);
881 static cache_entry
* cache_entry_from_xdr_doc(xmlDocPtr doc
, xmlChar
const* nsURI
, MSXML_VERSION version
)
883 cache_entry
* entry
= heap_alloc(sizeof(cache_entry
));
884 xmlSchemaParserCtxtPtr spctx
;
885 xmlDocPtr new_doc
= xmlCopyDoc(doc
, 1), xsd_doc
= XDR_to_XSD_doc(doc
, nsURI
);
887 link_datatypes(xsd_doc
);
889 entry
->type
= CacheEntryType_XDR
;
891 spctx
= xmlSchemaNewDocParserCtxt(xsd_doc
);
893 if ((entry
->schema
= Schema_parse(spctx
)))
895 entry
->doc
= new_doc
;
896 xmldoc_init(entry
->schema
->doc
, version
);
897 xmldoc_init(entry
->doc
, version
);
898 xmldoc_add_ref(entry
->doc
);
899 xmldoc_add_ref(entry
->schema
->doc
);
903 FIXME("failed to parse doc\n");
909 xmlSchemaFreeParserCtxt(spctx
);
914 static cache_entry
* cache_entry_from_url(VARIANT url
, xmlChar
const* nsURI
, MSXML_VERSION version
)
917 IXMLDOMDocument3
* domdoc
= NULL
;
918 xmlDocPtr doc
= NULL
;
919 HRESULT hr
= DOMDocument_create(version
, (void**)&domdoc
);
920 VARIANT_BOOL b
= VARIANT_FALSE
;
921 CacheEntryType type
= CacheEntryType_Invalid
;
925 FIXME("failed to create domdoc\n");
928 assert(domdoc
!= NULL
);
929 assert(V_VT(&url
) == VT_BSTR
);
931 hr
= IXMLDOMDocument3_load(domdoc
, url
, &b
);
934 ERR("IXMLDOMDocument3_load() returned 0x%08x\n", hr
);
935 if (b
!= VARIANT_TRUE
)
937 FIXME("Failed to load doc at %s\n", debugstr_w(V_BSTR(&url
)));
938 IXMLDOMDocument3_Release(domdoc
);
942 doc
= xmlNodePtr_from_domnode((IXMLDOMNode
*)domdoc
, XML_DOCUMENT_NODE
)->doc
;
943 type
= cache_type_from_xmlDocPtr(doc
);
947 case CacheEntryType_XSD
:
948 entry
= cache_entry_from_xsd_doc(doc
, nsURI
, version
);
950 case CacheEntryType_XDR
:
951 entry
= cache_entry_from_xdr_doc(doc
, nsURI
, version
);
955 FIXME("invalid schema\n");
958 IXMLDOMDocument3_Release(domdoc
);
963 static void cache_free(void* data
, xmlChar
* name
/* ignored */)
965 cache_entry_release((cache_entry
*)data
);
968 /* returns index or -1 if not found */
969 static int cache_free_uri(schema_cache
*cache
, const xmlChar
*uri
)
973 for (i
= 0; i
< cache
->count
; i
++)
974 if (xmlStrEqual(cache
->uris
[i
], uri
))
976 heap_free(cache
->uris
[i
]);
983 static void cache_add_entry(schema_cache
*cache
, const xmlChar
*uri
, cache_entry
*entry
)
987 /* meaning no entry found with this name */
988 if (xmlHashRemoveEntry(cache
->cache
, uri
, cache_free
))
990 if (cache
->count
== cache
->allocated
)
992 cache
->allocated
*= 2;
993 cache
->uris
= heap_realloc(cache
->uris
, cache
->allocated
*sizeof(xmlChar
*));
998 i
= cache_free_uri(cache
, uri
);
1000 cache
->uris
[i
] = heap_strdupxmlChar(uri
);
1001 xmlHashAddEntry(cache
->cache
, uri
, entry
);
1004 static void cache_remove_entry(schema_cache
*cache
, const xmlChar
*uri
)
1006 /* adjust index if entry was really removed */
1007 if (xmlHashRemoveEntry(cache
->cache
, uri
, cache_free
) == 0)
1009 int i
= cache_free_uri(cache
, uri
);
1010 if (i
== -1) return;
1012 if (i
!= --cache
->count
)
1013 memmove(&cache
->uris
[i
], &cache
->uris
[i
+1], (cache
->count
-i
)*sizeof(xmlChar
*));
1017 /* This one adds all namespaces defined in document to a cache, without anything
1018 associated with uri obviously.
1019 Unfortunately namespace:: axis implementation in libxml2 differs from what we need,
1020 it uses additional node type to describe namespace definition attribute while
1021 in msxml it's expected to be a normal attribute - as a workaround document is
1022 queried at libxml2 level here. */
1023 HRESULT
cache_from_doc_ns(IXMLDOMSchemaCollection2
*iface
, xmlnode
*node
)
1025 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1026 static const xmlChar query
[] = "//*/namespace::*";
1027 xmlXPathObjectPtr nodeset
;
1028 xmlXPathContextPtr ctxt
;
1030 This
->read_only
= 1;
1032 ctxt
= xmlXPathNewContext(node
->node
->doc
);
1034 nodeset
= xmlXPathEvalExpression(query
, ctxt
);
1035 xmlXPathFreeContext(ctxt
);
1039 int pos
= 0, len
= xmlXPathNodeSetGetLength(nodeset
->nodesetval
);
1043 xmlNodePtr node
= xmlXPathNodeSetItem(nodeset
->nodesetval
, pos
);
1044 if (node
->type
== XML_NAMESPACE_DECL
)
1046 static const xmlChar defns
[] = "http://www.w3.org/XML/1998/namespace";
1047 xmlNsPtr ns
= (xmlNsPtr
)node
;
1050 /* filter out default uri */
1051 if (xmlStrEqual(ns
->href
, defns
))
1057 entry
= heap_alloc(sizeof(cache_entry
));
1058 entry
->type
= CacheEntryType_NS
;
1060 entry
->schema
= NULL
;
1063 cache_add_entry(This
, ns
->href
, entry
);
1068 xmlXPathFreeObject(nodeset
);
1074 static HRESULT WINAPI
schema_cache_QueryInterface(IXMLDOMSchemaCollection2
* iface
,
1075 REFIID riid
, void** ppvObject
)
1077 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1079 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
1081 if ( IsEqualIID(riid
, &IID_IUnknown
) ||
1082 IsEqualIID(riid
, &IID_IDispatch
) ||
1083 IsEqualIID(riid
, &IID_IXMLDOMSchemaCollection
) ||
1084 IsEqualIID(riid
, &IID_IXMLDOMSchemaCollection2
) )
1088 else if(This
->version
== MSXML6
&& IsEqualIID(riid
, &CLSID_XMLSchemaCache60
))
1091 * Version 6 can be queried for an interface with IID equal to CLSID.
1092 * There is no public interface with that IID and returned pointer
1093 * is equal to returned IXMLDOMSchemaCollection2 iface. We assume
1094 * that it's just another way for querying IXMLDOMSchemaCollection2
1095 * interface. Office 2013 ClickToRun installer uses this.
1097 WARN("riid CLSID_XMLSchemaCache60, returning IXMLDOMSchemaCollection2 interface.\n");
1100 else if (dispex_query_interface(&This
->dispex
, riid
, ppvObject
))
1102 return *ppvObject
? S_OK
: E_NOINTERFACE
;
1104 else if(IsEqualGUID( riid
, &IID_ISupportErrorInfo
))
1106 return node_create_supporterrorinfo(schema_cache_se_tids
, ppvObject
);
1110 FIXME("interface %s not implemented\n", debugstr_guid(riid
));
1112 return E_NOINTERFACE
;
1115 IXMLDOMSchemaCollection2_AddRef(iface
);
1120 static ULONG WINAPI
schema_cache_AddRef(IXMLDOMSchemaCollection2
* iface
)
1122 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1123 LONG ref
= InterlockedIncrement(&This
->ref
);
1124 TRACE("(%p)->(%d)\n", This
, ref
);
1128 static ULONG WINAPI
schema_cache_Release(IXMLDOMSchemaCollection2
* iface
)
1130 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1131 LONG ref
= InterlockedDecrement(&This
->ref
);
1132 TRACE("(%p)->(%d)\n", This
, ref
);
1138 for (i
= 0; i
< This
->count
; i
++)
1139 heap_free(This
->uris
[i
]);
1140 heap_free(This
->uris
);
1141 xmlHashFree(This
->cache
, cache_free
);
1148 static HRESULT WINAPI
schema_cache_GetTypeInfoCount(IXMLDOMSchemaCollection2
* iface
,
1151 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1152 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
1155 static HRESULT WINAPI
schema_cache_GetTypeInfo(IXMLDOMSchemaCollection2
* iface
,
1156 UINT iTInfo
, LCID lcid
, ITypeInfo
** ppTInfo
)
1158 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1159 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
,
1160 iTInfo
, lcid
, ppTInfo
);
1163 static HRESULT WINAPI
schema_cache_GetIDsOfNames(IXMLDOMSchemaCollection2
* iface
,
1164 REFIID riid
, LPOLESTR
* rgszNames
,
1165 UINT cNames
, LCID lcid
, DISPID
* rgDispId
)
1167 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1168 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
,
1169 riid
, rgszNames
, cNames
, lcid
, rgDispId
);
1172 static HRESULT WINAPI
schema_cache_Invoke(IXMLDOMSchemaCollection2
* iface
,
1173 DISPID dispIdMember
, REFIID riid
, LCID lcid
,
1174 WORD wFlags
, DISPPARAMS
* pDispParams
,
1175 VARIANT
* pVarResult
, EXCEPINFO
* pExcepInfo
,
1178 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1179 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
,
1180 dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1183 static HRESULT WINAPI
schema_cache_add(IXMLDOMSchemaCollection2
* iface
, BSTR uri
, VARIANT var
)
1185 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1188 TRACE("(%p)->(%s %s)\n", This
, debugstr_w(uri
), debugstr_variant(&var
));
1190 if (This
->read_only
) return E_FAIL
;
1192 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1198 cache_remove_entry(This
, name
);
1204 cache_entry
* entry
= cache_entry_from_url(var
, name
, This
->version
);
1208 cache_entry_add_ref(entry
);
1216 cache_add_entry(This
, name
, entry
);
1223 xmlDocPtr doc
= NULL
;
1225 CacheEntryType type
;
1226 IXMLDOMNode
* domnode
= NULL
;
1227 IUnknown_QueryInterface(V_UNKNOWN(&var
), &IID_IXMLDOMNode
, (void**)&domnode
);
1233 IXMLDOMNode_get_nodeType(domnode
, &type
);
1238 IXMLDOMDocument
*domdoc
;
1242 IXMLDOMNode_get_xml(domnode
, &xml
);
1243 DOMDocument_create(This
->version
, (void**)&domdoc
);
1244 IXMLDOMDocument_loadXML(domdoc
, xml
, &b
);
1246 doc
= xmlNodePtr_from_domnode((IXMLDOMNode
*)domdoc
, XML_DOCUMENT_NODE
)->doc
;
1250 doc
= xmlNodePtr_from_domnode(domnode
, XML_DOCUMENT_NODE
)->doc
;
1257 IXMLDOMNode_Release(domnode
);
1259 return E_INVALIDARG
;
1261 type
= cache_type_from_xmlDocPtr(doc
);
1263 if (type
== CacheEntryType_XSD
)
1265 entry
= cache_entry_from_xsd_doc(doc
, name
, This
->version
);
1267 else if (type
== CacheEntryType_XDR
)
1269 entry
= cache_entry_from_xdr_doc(doc
, name
, This
->version
);
1273 WARN("invalid schema!\n");
1277 IXMLDOMNode_Release(domnode
);
1281 cache_entry_add_ref(entry
);
1289 cache_add_entry(This
, name
, entry
);
1294 FIXME("arg type is not supported, %s\n", debugstr_variant(&var
));
1296 return E_INVALIDARG
;
1302 static HRESULT WINAPI
schema_cache_get(IXMLDOMSchemaCollection2
* iface
, BSTR uri
,
1305 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1309 TRACE("(%p)->(%s %p)\n", This
, debugstr_w(uri
), node
);
1311 if (This
->version
== MSXML6
)
1313 if (node
) *node
= NULL
;
1322 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1323 entry
= (cache_entry
*) xmlHashLookup(This
->cache
, name
);
1326 /* TODO: this should be read-only */
1327 if (entry
&& entry
->doc
)
1328 return get_domdoc_from_xmldoc(entry
->doc
, (IXMLDOMDocument3
**)node
);
1333 static HRESULT WINAPI
schema_cache_remove(IXMLDOMSchemaCollection2
* iface
, BSTR uri
)
1335 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1338 TRACE("(%p)->(%s)\n", This
, debugstr_w(uri
));
1340 if (This
->version
== MSXML6
) return E_NOTIMPL
;
1342 name
= uri
? xmlchar_from_wchar(uri
) : xmlchar_from_wchar(emptyW
);
1343 cache_remove_entry(This
, name
);
1348 static HRESULT WINAPI
schema_cache_get_length(IXMLDOMSchemaCollection2
* iface
, LONG
* length
)
1350 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1351 TRACE("(%p)->(%p)\n", This
, length
);
1356 *length
= This
->count
;
1360 static HRESULT WINAPI
schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2
* iface
,
1361 LONG index
, BSTR
* uri
)
1363 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1365 TRACE("(%p)->(%i %p)\n", This
, index
, uri
);
1370 if (This
->version
== MSXML6
)
1373 if (index
>= This
->count
)
1376 *uri
= bstr_from_xmlChar(This
->uris
[index
]);
1380 static void cache_copy(void* data
, void* dest
, xmlChar
* name
)
1382 schema_cache
* This
= (schema_cache
*) dest
;
1383 cache_entry
* entry
= (cache_entry
*) data
;
1385 if (xmlHashLookup(This
->cache
, name
) == NULL
)
1387 cache_entry_add_ref(entry
);
1388 cache_add_entry(This
, name
, entry
);
1392 static HRESULT WINAPI
schema_cache_addCollection(IXMLDOMSchemaCollection2
* iface
,
1393 IXMLDOMSchemaCollection
* collection
)
1395 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1398 TRACE("(%p)->(%p)\n", This
, collection
);
1403 That
= unsafe_impl_from_IXMLDOMSchemaCollection(collection
);
1406 ERR("external collection implementation\n");
1410 /* TODO: detect errors while copying & return E_FAIL */
1411 xmlHashScan(That
->cache
, cache_copy
, This
);
1416 static HRESULT WINAPI
schema_cache_get__newEnum(IXMLDOMSchemaCollection2
* iface
, IUnknown
** enumv
)
1418 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1419 TRACE("(%p)->(%p)\n", This
, enumv
);
1420 return create_enumvariant((IUnknown
*)iface
, TRUE
, &schemacache_enumvariant
, (IEnumVARIANT
**)enumv
);
1423 static HRESULT WINAPI
schema_cache_validate(IXMLDOMSchemaCollection2
* iface
)
1425 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1426 FIXME("(%p): stub\n", This
);
1430 static HRESULT WINAPI
schema_cache_put_validateOnLoad(IXMLDOMSchemaCollection2
* iface
,
1433 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1434 FIXME("(%p)->(%d): stub\n", This
, value
);
1436 This
->validateOnLoad
= value
;
1437 /* it's ok to disable it, cause we don't validate on load anyway */
1438 if (value
== VARIANT_FALSE
) return S_OK
;
1443 static HRESULT WINAPI
schema_cache_get_validateOnLoad(IXMLDOMSchemaCollection2
* iface
,
1444 VARIANT_BOOL
* value
)
1446 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1447 TRACE("(%p)->(%p)\n", This
, value
);
1449 if (!value
) return E_POINTER
;
1450 *value
= This
->validateOnLoad
;
1455 static HRESULT WINAPI
schema_cache_getSchema(IXMLDOMSchemaCollection2
* iface
,
1456 BSTR namespaceURI
, ISchema
** schema
)
1458 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1459 FIXME("(%p)->(%s %p): stub\n", This
, debugstr_w(namespaceURI
), schema
);
1465 static HRESULT WINAPI
schema_cache_getDeclaration(IXMLDOMSchemaCollection2
* iface
,
1466 IXMLDOMNode
* node
, ISchemaItem
** item
)
1468 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1469 FIXME("(%p)->(%p %p): stub\n", This
, node
, item
);
1475 static const struct IXMLDOMSchemaCollection2Vtbl XMLDOMSchemaCollection2Vtbl
=
1477 schema_cache_QueryInterface
,
1478 schema_cache_AddRef
,
1479 schema_cache_Release
,
1480 schema_cache_GetTypeInfoCount
,
1481 schema_cache_GetTypeInfo
,
1482 schema_cache_GetIDsOfNames
,
1483 schema_cache_Invoke
,
1486 schema_cache_remove
,
1487 schema_cache_get_length
,
1488 schema_cache_get_namespaceURI
,
1489 schema_cache_addCollection
,
1490 schema_cache_get__newEnum
,
1491 schema_cache_validate
,
1492 schema_cache_put_validateOnLoad
,
1493 schema_cache_get_validateOnLoad
,
1494 schema_cache_getSchema
,
1495 schema_cache_getDeclaration
1498 static xmlSchemaElementPtr
lookup_schema_elemDecl(xmlSchemaPtr schema
, xmlNodePtr node
)
1500 xmlSchemaElementPtr decl
= NULL
;
1501 xmlChar
const* nsURI
= get_node_nsURI(node
);
1503 TRACE("(%p, %p)\n", schema
, node
);
1505 if (xmlStrEqual(nsURI
, schema
->targetNamespace
))
1506 decl
= xmlHashLookup(schema
->elemDecl
, node
->name
);
1508 if (!decl
&& xmlHashSize(schema
->schemasImports
) > 1)
1510 FIXME("declaration not found in main schema - need to check schema imports!\n");
1511 /*xmlSchemaImportPtr import;
1513 import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_NO_NAMESPACE);
1515 import = xmlHashLookup(schema->schemasImports, node->ns->href);
1518 decl = xmlHashLookup(import->schema->elemDecl, node->name);*/
1524 static inline xmlNodePtr
lookup_schema_element(xmlSchemaPtr schema
, xmlNodePtr node
)
1526 xmlSchemaElementPtr decl
= lookup_schema_elemDecl(schema
, node
);
1527 while (decl
!= NULL
&& decl
->refDecl
!= NULL
)
1528 decl
= decl
->refDecl
;
1529 return (decl
!= NULL
)? decl
->node
: NULL
;
1532 HRESULT
SchemaCache_validate_tree(IXMLDOMSchemaCollection2
* iface
, xmlNodePtr tree
)
1534 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1535 xmlSchemaPtr schema
;
1537 TRACE("(%p, %p)\n", This
, tree
);
1542 if (tree
->type
== XML_DOCUMENT_NODE
)
1543 tree
= xmlDocGetRootElement(tree
->doc
);
1545 schema
= get_node_schema(This
, tree
);
1546 /* TODO: if the ns is not in the cache, and it's a URL,
1547 * do we try to load from that? */
1549 return Schema_validate_tree(schema
, tree
);
1551 WARN("no schema found for xmlns=%s\n", get_node_nsURI(tree
));
1556 XDR_DT
SchemaCache_get_node_dt(IXMLDOMSchemaCollection2
* iface
, xmlNodePtr node
)
1558 schema_cache
* This
= impl_from_IXMLDOMSchemaCollection2(iface
);
1559 xmlSchemaPtr schema
= get_node_schema(This
, node
);
1560 XDR_DT dt
= DT_INVALID
;
1562 TRACE("(%p, %p)\n", This
, node
);
1564 if (node
->ns
&& xmlStrEqual(node
->ns
->href
, DT_nsURI
))
1566 dt
= str_to_dt(node
->name
, -1);
1571 xmlNodePtr schema_node
= lookup_schema_element(schema
, node
);
1573 str
= xmlGetNsProp(schema_node
, BAD_CAST
"dt", DT_nsURI
);
1576 dt
= str_to_dt(str
, -1);
1584 static const tid_t schemacache_iface_tids
[] = {
1585 IXMLDOMSchemaCollection2_tid
,
1589 static dispex_static_data_t schemacache_dispex
= {
1591 IXMLDOMSchemaCollection2_tid
,
1593 schemacache_iface_tids
1596 HRESULT
SchemaCache_create(MSXML_VERSION version
, void** obj
)
1598 schema_cache
* This
= heap_alloc(sizeof(schema_cache
));
1600 return E_OUTOFMEMORY
;
1602 TRACE("(%d %p)\n", version
, obj
);
1604 This
->IXMLDOMSchemaCollection2_iface
.lpVtbl
= &XMLDOMSchemaCollection2Vtbl
;
1605 This
->cache
= xmlHashCreate(DEFAULT_HASHTABLE_SIZE
);
1606 This
->allocated
= 10;
1608 This
->uris
= heap_alloc(This
->allocated
*sizeof(xmlChar
*));
1610 This
->version
= version
;
1611 This
->validateOnLoad
= VARIANT_TRUE
;
1612 This
->read_only
= 0;
1613 init_dispex(&This
->dispex
, (IUnknown
*)&This
->IXMLDOMSchemaCollection2_iface
, &schemacache_dispex
);
1615 *obj
= &This
->IXMLDOMSchemaCollection2_iface
;
1621 HRESULT
SchemaCache_create(MSXML_VERSION version
, void** obj
)
1623 MESSAGE("This program tried to use a SchemaCache object, but\n"
1624 "libxml2 support was not present at compile time.\n");