diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 8468e5551dc..503a58023ec 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -404,6 +404,21 @@ static inline xmlChar *xmlchar_from_wchar( const WCHAR *str ) return xmlchar_from_wcharn(str, -1); } +static inline xmlChar *heap_strdupxmlChar(const xmlChar *str) +{ + xmlChar *ret = NULL; + + if(str) { + DWORD size; + + size = (xmlStrlen(str)+1)*sizeof(xmlChar); + ret = heap_alloc(size); + memcpy(ret, str, size); + } + + return ret; +} + #endif static inline HRESULT return_bstr(const WCHAR *value, BSTR *p) diff --git a/dlls/msxml3/schema.c b/dlls/msxml3/schema.c index 5d971f93f89..5626464d218 100644 --- a/dlls/msxml3/schema.c +++ b/dlls/msxml3/schema.c @@ -100,6 +100,9 @@ typedef struct MSXML_VERSION version; xmlHashTablePtr cache; + xmlChar **uris; + int allocated; + int count; VARIANT_BOOL validateOnLoad; int read_only; @@ -113,12 +116,6 @@ typedef struct LONG ref; } cache_entry; -typedef struct -{ - LONG index; - BSTR* out; -} cache_index_data; - /* datatypes lookup stuff * generated with help from gperf */ #define DT_MIN_STR_LEN 2 @@ -982,6 +979,55 @@ static void cache_free(void* data, xmlChar* name /* ignored */) cache_entry_release((cache_entry*)data); } +/* returns index or -1 if not found */ +static int cache_free_uri(schema_cache *cache, const xmlChar *uri) +{ + int i; + + for (i = 0; i < cache->count; i++) + if (xmlStrEqual(cache->uris[i], uri)) + { + heap_free(cache->uris[i]); + return i; + } + + return -1; +} + +static void cache_add_entry(schema_cache *cache, const xmlChar *uri, cache_entry *entry) +{ + int i; + + /* meaning no entry found with this name */ + if (xmlHashRemoveEntry(cache->cache, uri, cache_free)) + { + if (cache->count == cache->allocated) + { + cache->allocated *= 2; + cache->uris = heap_realloc(cache->uris, cache->allocated*sizeof(xmlChar*)); + } + i = cache->count++; + } + else + i = cache_free_uri(cache, uri); + + cache->uris[i] = heap_strdupxmlChar(uri); + xmlHashAddEntry(cache->cache, uri, entry); +} + +static void cache_remove_entry(schema_cache *cache, const xmlChar *uri) +{ + /* adjust index if entry was really removed */ + if (xmlHashRemoveEntry(cache->cache, uri, cache_free) == 0) + { + int i = cache_free_uri(cache, uri); + if (i == -1) return; + /* shift array */ + if (i != --cache->count) + memmove(&cache->uris[i], &cache->uris[i+1], (cache->count-i)*sizeof(xmlChar*)); + } +} + /* This one adds all namespaces defined in document to a cache, without anything associated with uri obviously. Unfortunately namespace:: axis implementation in libxml2 differs from what we need, @@ -1030,8 +1076,7 @@ HRESULT cache_from_doc_ns(IXMLDOMSchemaCollection2 *iface, xmlnode *node) entry->schema = NULL; entry->doc = NULL; - xmlHashRemoveEntry(This->cache, ns->href, cache_free); - xmlHashAddEntry(This->cache, ns->href, entry); + cache_add_entry(This, ns->href, entry); } pos++; } @@ -1088,6 +1133,11 @@ static ULONG WINAPI schema_cache_Release(IXMLDOMSchemaCollection2* iface) if (ref == 0) { + int i; + + for (i = 0; i < This->count; i++) + heap_free(This->uris[i]); + heap_free(This->uris); xmlHashFree(This->cache, cache_free); release_dispex(&This->dispex); heap_free(This); @@ -1143,7 +1193,7 @@ static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri { case VT_NULL: { - xmlHashRemoveEntry(This->cache, name, cache_free); + cache_remove_entry(This, name); } break; @@ -1161,8 +1211,7 @@ static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri return E_FAIL; } - xmlHashRemoveEntry(This->cache, name, cache_free); - xmlHashAddEntry(This->cache, name, entry); + cache_add_entry(This, name, entry); } break; @@ -1211,8 +1260,7 @@ static HRESULT WINAPI schema_cache_add(IXMLDOMSchemaCollection2* iface, BSTR uri return E_FAIL; } - xmlHashRemoveEntry(This->cache, name, cache_free); - xmlHashAddEntry(This->cache, name, entry); + cache_add_entry(This, name, entry); } break; @@ -1260,7 +1308,7 @@ static HRESULT WINAPI schema_cache_remove(IXMLDOMSchemaCollection2* iface, BSTR if (This->version == MSXML6) return E_NOTIMPL; - xmlHashRemoveEntry(This->cache, name, cache_free); + cache_remove_entry(This, name); heap_free(name); return S_OK; } @@ -1272,33 +1320,25 @@ static HRESULT WINAPI schema_cache_get_length(IXMLDOMSchemaCollection2* iface, L if (!length) return E_POINTER; - *length = xmlHashSize(This->cache); + + *length = This->count; return S_OK; } -static void cache_index(void* data /* ignored */, void* index, xmlChar* name) -{ - cache_index_data* index_data = (cache_index_data*)index; - - if (index_data->index-- == 0) - *index_data->out = bstr_from_xmlChar(name); -} - static HRESULT WINAPI schema_cache_get_namespaceURI(IXMLDOMSchemaCollection2* iface, - LONG index, BSTR* len) + LONG index, BSTR* uri) { schema_cache* This = impl_from_IXMLDOMSchemaCollection2(iface); - cache_index_data data = {index, len}; - TRACE("(%p)->(%i %p)\n", This, index, len); - if (!len) + TRACE("(%p)->(%i %p)\n", This, index, uri); + + if (!uri) return E_POINTER; - if (index >= xmlHashSize(This->cache)) + if (index >= This->count) return E_FAIL; - *len = NULL; - xmlHashScan(This->cache, cache_index, &data); + *uri = bstr_from_xmlChar(This->uris[index]); return S_OK; } @@ -1310,7 +1350,7 @@ static void cache_copy(void* data, void* dest, xmlChar* name) if (xmlHashLookup(This->cache, name) == NULL) { cache_entry_add_ref(entry); - xmlHashAddEntry(This->cache, name, entry); + cache_add_entry(This, name, entry); } } @@ -1528,6 +1568,9 @@ HRESULT SchemaCache_create(MSXML_VERSION version, IUnknown* outer, void** obj) This->IXMLDOMSchemaCollection2_iface.lpVtbl = &XMLDOMSchemaCollection2Vtbl; This->cache = xmlHashCreate(DEFAULT_HASHTABLE_SIZE); + This->allocated = 10; + This->count = 0; + This->uris = heap_alloc(This->allocated*sizeof(xmlChar*)); This->ref = 1; This->version = version; This->validateOnLoad = VARIANT_TRUE;