From 72c80375fa2f28f30eeffdba676162cbb293cda1 Mon Sep 17 00:00:00 2001 From: Rok Mandeljc Date: Thu, 13 May 2004 00:00:22 +0000 Subject: [PATCH] dmloader: complete rewrite and full implementation. --- dlls/dmloader/Makefile.in | 2 + dlls/dmloader/classfactory.c | 198 +++++ dlls/dmloader/container.c | 681 +++++++++------ dlls/dmloader/debug.c | 536 ++++++++++++ dlls/dmloader/debug.h | 71 ++ dlls/dmloader/dmloader_main.c | 559 +------------ dlls/dmloader/dmloader_private.h | 428 ++++++---- dlls/dmloader/loader.c | 1326 ++++++++++++++++++------------ dlls/dmloader/loaderstream.c | 796 +++++++++++++++--- 9 files changed, 2954 insertions(+), 1643 deletions(-) create mode 100644 dlls/dmloader/classfactory.c create mode 100644 dlls/dmloader/debug.c create mode 100644 dlls/dmloader/debug.h diff --git a/dlls/dmloader/Makefile.in b/dlls/dmloader/Makefile.in index bd4ebdefffe..2bb731ef3ca 100644 --- a/dlls/dmloader/Makefile.in +++ b/dlls/dmloader/Makefile.in @@ -7,7 +7,9 @@ IMPORTS = ole32 user32 advapi32 kernel32 EXTRALIBS = -ldxguid -luuid C_SRCS = \ + classfactory.c \ container.c \ + debug.c \ dmloader_main.c \ loader.c \ loaderstream.c \ diff --git a/dlls/dmloader/classfactory.c b/dlls/dmloader/classfactory.c new file mode 100644 index 00000000000..0f962cc65fa --- /dev/null +++ b/dlls/dmloader/classfactory.c @@ -0,0 +1,198 @@ + /* IDirectMusicLoaderCF + * IDirectMusicContainerCF + * + * Copyright (C) 2004 Rok Mandeljc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dmloader_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dmloader); + +/***************************************************************************** + * IDirectMusicLoaderCF implementation + */ +HRESULT WINAPI IDirectMusicLoaderCF_QueryInterface (LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj) { + ICOM_THIS(IDirectMusicLoaderCF, iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IClassFactory)) { + IDirectMusicLoaderCF_AddRef (iface); + *ppobj = This; + return S_OK; + } + + WARN(": not found\n"); + return E_NOINTERFACE; +} + +ULONG WINAPI IDirectMusicLoaderCF_AddRef (LPCLASSFACTORY iface) { + ICOM_THIS(IDirectMusicLoaderCF, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); +} + +ULONG WINAPI IDirectMusicLoaderCF_Release (LPCLASSFACTORY iface) { + ICOM_THIS(IDirectMusicLoaderCF, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + HeapFree(GetProcessHeap (), 0, This); + /* decrease number of instances */ + InterlockedDecrement(&dwDirectMusicLoader); + } + + return dwRef; +} + +HRESULT WINAPI IDirectMusicLoaderCF_CreateInstance (LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { + ICOM_THIS(IDirectMusicLoaderCF, iface); + + TRACE ("(%p, %p, %s, %p)\n", This, pOuter, debugstr_dmguid(riid), ppobj); + if (pOuter) { + ERR(": pOuter should be NULL\n"); + return CLASS_E_NOAGGREGATION; + } + + return DMUSIC_CreateDirectMusicLoaderImpl (riid, ppobj, pOuter); +} + +HRESULT WINAPI IDirectMusicLoaderCF_LockServer (LPCLASSFACTORY iface, BOOL dolock) { + ICOM_THIS(IDirectMusicLoaderCF, iface); + TRACE("(%p, %d)\n", This, dolock); + if (dolock == TRUE) + InterlockedIncrement (&dwDirectMusicLoader); + else + InterlockedDecrement (&dwDirectMusicLoader); + return S_OK; +} + +ICOM_VTABLE(IClassFactory) DirectMusicLoaderCF_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicLoaderCF_QueryInterface, + IDirectMusicLoaderCF_AddRef, + IDirectMusicLoaderCF_Release, + IDirectMusicLoaderCF_CreateInstance, + IDirectMusicLoaderCF_LockServer +}; + +HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderCF (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) { + IDirectMusicLoaderCF *obj; + + TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter); + obj = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderCF)); + if (NULL == obj) { + *ppobj = (LPCLASSFACTORY)NULL; + return E_OUTOFMEMORY; + } + obj->lpVtbl = &DirectMusicLoaderCF_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ + + /* increase number of instances */ + InterlockedIncrement (&dwDirectMusicLoader); + + return IDirectMusicLoaderCF_QueryInterface ((LPCLASSFACTORY)obj, lpcGUID, ppobj); +} + + +/***************************************************************************** + * IDirectMusicContainerCF implementation + */ +HRESULT WINAPI IDirectMusicContainerCF_QueryInterface (LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj) { + ICOM_THIS(IDirectMusicContainerCF, iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IClassFactory)) { + IDirectMusicContainerCF_AddRef (iface); + *ppobj = This; + return S_OK; + } + + WARN(": not found\n"); + return E_NOINTERFACE; +} + +ULONG WINAPI IDirectMusicContainerCF_AddRef (LPCLASSFACTORY iface) { + ICOM_THIS(IDirectMusicContainerCF, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); +} + +ULONG WINAPI IDirectMusicContainerCF_Release (LPCLASSFACTORY iface) { + ICOM_THIS(IDirectMusicContainerCF, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + HeapFree(GetProcessHeap (), 0, This); + /* decrease number of instances */ + InterlockedDecrement(&dwDirectMusicContainer); + } + + return dwRef; +} + +HRESULT WINAPI IDirectMusicContainerCF_CreateInstance (LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { + ICOM_THIS(IDirectMusicContainerCF, iface); + + TRACE ("(%p, %p, %s, %p)\n", This, pOuter, debugstr_dmguid(riid), ppobj); + if (pOuter) { + ERR(": pOuter should be NULL\n"); + return CLASS_E_NOAGGREGATION; + } + + return DMUSIC_CreateDirectMusicContainerImpl (riid, ppobj, pOuter); +} + +HRESULT WINAPI IDirectMusicContainerCF_LockServer (LPCLASSFACTORY iface, BOOL dolock) { + ICOM_THIS(IDirectMusicContainerCF, iface); + TRACE("(%p, %d)\n", This, dolock); + if (dolock == TRUE) + InterlockedIncrement (&dwDirectMusicContainer); + else + InterlockedDecrement (&dwDirectMusicContainer); + return S_OK; +} + +ICOM_VTABLE(IClassFactory) DirectMusicContainerCF_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicContainerCF_QueryInterface, + IDirectMusicContainerCF_AddRef, + IDirectMusicContainerCF_Release, + IDirectMusicContainerCF_CreateInstance, + IDirectMusicContainerCF_LockServer +}; + +HRESULT WINAPI DMUSIC_CreateDirectMusicContainerCF (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) { + IDirectMusicContainerCF *obj; + + TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter); + obj = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicContainerCF)); + if (NULL == obj) { + *ppobj = (LPCLASSFACTORY)NULL; + return E_OUTOFMEMORY; + } + obj->lpVtbl = &DirectMusicContainerCF_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ + + /* increase number of instances */ + InterlockedIncrement (&dwDirectMusicContainer); + + return IDirectMusicContainerCF_QueryInterface ((LPCLASSFACTORY)obj, lpcGUID, ppobj); +} diff --git a/dlls/dmloader/container.c b/dlls/dmloader/container.c index b94dafc433c..fd40aac26c0 100644 --- a/dlls/dmloader/container.c +++ b/dlls/dmloader/container.c @@ -1,4 +1,4 @@ -/* IDirectMusicContainer +/* IDirectMusicContainerImpl * * Copyright (C) 2003-2004 Rok Mandeljc * @@ -21,20 +21,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); WINE_DECLARE_DEBUG_CHANNEL(dmfile); +WINE_DECLARE_DEBUG_CHANNEL(dmdump); + +#define DMUS_MAX_CATEGORY_SIZE DMUS_MAX_CATEGORY*sizeof(WCHAR) +#define DMUS_MAX_NAME_SIZE DMUS_MAX_NAME*sizeof(WCHAR) +#define DMUS_MAX_FILENAME_SIZE DMUS_MAX_FILENAME*sizeof(WCHAR) /***************************************************************************** * IDirectMusicContainerImpl implementation */ -/* IDirectMusicContainerImpl IUnknown part: */ -HRESULT WINAPI IDirectMusicContainerImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) { - ICOM_THIS_MULTI(IDirectMusicContainerImpl, UnknownVtbl, iface); +/* IUnknown/IDirectMusicContainer part: */ +HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface (LPDIRECTMUSICCONTAINER iface, REFIID riid, LPVOID *ppobj) { + ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); - if (IsEqualIID (riid, &IID_IUnknown)) { - *ppobj = (LPVOID)&This->UnknownVtbl; - IDirectMusicContainerImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); - return S_OK; - } else if (IsEqualIID (riid, &IID_IDirectMusicContainer)) { + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IDirectMusicContainer)) { *ppobj = (LPVOID)&This->ContainerVtbl; IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl); return S_OK; @@ -48,74 +50,80 @@ HRESULT WINAPI IDirectMusicContainerImpl_IUnknown_QueryInterface (LPUNKNOWN ifac return S_OK; } - WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj); + WARN(": not found\n"); return E_NOINTERFACE; } -ULONG WINAPI IDirectMusicContainerImpl_IUnknown_AddRef (LPUNKNOWN iface) { - ICOM_THIS_MULTI(IDirectMusicContainerImpl, UnknownVtbl, iface); - TRACE("(%p): AddRef from %ld\n", This, This->ref); - return ++(This->ref); -} - -ULONG WINAPI IDirectMusicContainerImpl_IUnknown_Release (LPUNKNOWN iface) { - ICOM_THIS_MULTI(IDirectMusicContainerImpl, UnknownVtbl, iface); - ULONG ref = --This->ref; - TRACE("(%p): ReleaseRef to %ld\n", This, This->ref); - if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -ICOM_VTABLE(IUnknown) DirectMusicContainer_Unknown_Vtbl = { - ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectMusicContainerImpl_IUnknown_QueryInterface, - IDirectMusicContainerImpl_IUnknown_AddRef, - IDirectMusicContainerImpl_IUnknown_Release -}; - -/* IDirectMusicContainer Interface follow: */ -HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface (LPDIRECTMUSICCONTAINER iface, REFIID riid, LPVOID *ppobj) { - ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj); -} - ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_AddRef (LPDIRECTMUSICCONTAINER iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); } ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_Release (LPDIRECTMUSICCONTAINER iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + DMUSIC_DestroyDirectMusicContainerImpl (iface); + HeapFree(GetProcessHeap(), 0, This); + } + + return dwRef; } HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_EnumObject (LPDIRECTMUSICCONTAINER iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc, WCHAR* pwszAlias) { - ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); - DWORD i = -1; /* index ;) ... must be -1 since dwIndex can be 0 */ - struct list *listEntry; - LPDMUS_PRIVATE_CONTAINED_OBJECT_ENTRY objectEntry; + ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); + struct list *pEntry; + LPWINE_CONTAINER_ENTRY pContainedObject; + DWORD dwCount = 0; TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc, pwszAlias); - LIST_FOR_EACH (listEntry, &This->ObjectsList) { - objectEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY, entry); - if (IsEqualGUID(rguidClass, &GUID_DirectMusicAllTypes)) i++; - else if (IsEqualGUID(rguidClass, &objectEntry->pDesc->guidClass)) i++; - if (i == dwIndex) { - if (pDesc) - memcpy (pDesc, objectEntry->pDesc, sizeof(DMUS_OBJECTDESC)); - if (pwszAlias && objectEntry->wszAlias) { - strncpyW (pwszAlias, objectEntry->wszAlias, DMUS_MAX_NAME); - if (strlenW (objectEntry->wszAlias) > DMUS_MAX_NAME) - return DMUS_S_STRING_TRUNCATED; - } - - return S_OK; + /* check if we can write to whole pDesc */ + if (pDesc) { + if (IsBadReadPtr (pDesc, sizeof(DWORD))) { + ERR(": pDesc->dwSize bad read pointer\n"); + return E_POINTER; + } + if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) { + ERR(": invalid pDesc->dwSize\n"); + return E_INVALIDARG; + } + if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) { + ERR(": pDesc bad write pointer\n"); + return E_POINTER; } } + /* check if we wszAlias is big enough */ + if (pwszAlias && IsBadWritePtr (pwszAlias, DMUS_MAX_FILENAME_SIZE)) { + ERR(": wszAlias bad write pointer\n"); + return E_POINTER; + } + DM_STRUCT_INIT(pDesc); + + LIST_FOR_EACH (pEntry, This->pContainedObjects) { + pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry); + + if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pContainedObject->Desc.guidClass)) { + if (dwCount == dwIndex) { + HRESULT result = S_OK; + if (pwszAlias) { + strncpyW (pwszAlias, pContainedObject->wszAlias, DMUS_MAX_FILENAME); + if (strlenW (pContainedObject->wszAlias) > DMUS_MAX_FILENAME) + result = DMUS_S_STRING_TRUNCATED; + } + if (pDesc) + memcpy (pDesc, &pContainedObject->Desc, sizeof(DMUS_OBJECTDESC)); + return result; + } + dwCount++; + } + } + + TRACE(": not found\n"); return S_FALSE; } @@ -127,78 +135,134 @@ ICOM_VTABLE(IDirectMusicContainer) DirectMusicContainer_Container_Vtbl = { IDirectMusicContainerImpl_IDirectMusicContainer_EnumObject }; -/* IDirectMusicContainerImpl IDirectMusicObject part: */ +/* IDirectMusicObject part: */ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj); + return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl, riid, ppobj); } ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); + return IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl); } ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl); + return IDirectMusicContainerImpl_IDirectMusicContainer_Release ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl); } HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - TRACE("(%p, %p)\n", This, pDesc); - /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */ - memcpy (pDesc, This->pDesc, This->pDesc->dwSize); + TRACE("(%p, %p):\n", This, pDesc); + + /* check if whe can write to whole pDesc */ + if (IsBadReadPtr (pDesc, sizeof(DWORD))) { + ERR(": pDesc->dwSize bad read pointer\n"); + return E_POINTER; + } + if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) { + ERR(": invalid pDesc->dwSize\n"); + return E_INVALIDARG; + } + if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) { + ERR(": pDesc bad write pointer\n"); + return E_POINTER; + } + + DM_STRUCT_INIT(pDesc); + memcpy (pDesc, &This->Desc, sizeof(DMUS_OBJECTDESC)); + return S_OK; } HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) { + DWORD dwNewFlags = 0; + DWORD dwFlagDifference; ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - TRACE("(%p, %p): setting descriptor:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC (pDesc)); - - /* According to MSDN, we should copy only given values, not whole struct */ - if (pDesc->dwValidData & DMUS_OBJ_OBJECT) - memcpy (&This->pDesc->guidObject, &pDesc->guidObject, sizeof (pDesc->guidObject)); - if (pDesc->dwValidData & DMUS_OBJ_CLASS) - memcpy (&This->pDesc->guidClass, &pDesc->guidClass, sizeof (pDesc->guidClass)); - if (pDesc->dwValidData & DMUS_OBJ_NAME) - strncpyW (This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME); - if (pDesc->dwValidData & DMUS_OBJ_CATEGORY) - strncpyW (This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY); - if (pDesc->dwValidData & DMUS_OBJ_FILENAME) - strncpyW (This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME); - if (pDesc->dwValidData & DMUS_OBJ_VERSION) - memcpy (&This->pDesc->vVersion, &pDesc->vVersion, sizeof (pDesc->vVersion)); - if (pDesc->dwValidData & DMUS_OBJ_DATE) - memcpy (&This->pDesc->ftDate, &pDesc->ftDate, sizeof (pDesc->ftDate)); - if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { - memcpy (&This->pDesc->llMemLength, &pDesc->llMemLength, sizeof (pDesc->llMemLength)); - memcpy (This->pDesc->pbMemData, pDesc->pbMemData, sizeof (pDesc->pbMemData)); - } - if (pDesc->dwValidData & DMUS_OBJ_STREAM) { - /* according to MSDN, we copy the stream */ - IStream_Clone (pDesc->pStream, &This->pDesc->pStream); - } - - /* add new flags */ - This->pDesc->dwValidData |= pDesc->dwValidData; + TRACE("(%p, %p):\n", This, pDesc); - return S_OK; + /* check if whe can read whole pDesc */ + if (IsBadReadPtr (pDesc, sizeof(DWORD))) { + ERR(": pDesc->dwSize bad read pointer\n"); + return E_POINTER; + } + if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) { + ERR(": invalid pDesc->dwSize\n"); + return E_INVALIDARG; + } + if (IsBadReadPtr (pDesc, sizeof(DMUS_OBJECTDESC))) { + ERR(": pDesc bad read pointer\n"); + return E_POINTER; + } + + if (pDesc->dwValidData & DMUS_OBJ_OBJECT) { + memcpy (&This->Desc.guidObject, &pDesc->guidObject, sizeof(GUID)); + dwNewFlags |= DMUS_OBJ_OBJECT; + } + if (pDesc->dwValidData & DMUS_OBJ_NAME) { + strncpyW (This->Desc.wszName, pDesc->wszName, DMUS_MAX_NAME); + dwNewFlags |= DMUS_OBJ_NAME; + } + if (pDesc->dwValidData & DMUS_OBJ_CATEGORY) { + strncpyW (This->Desc.wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY); + dwNewFlags |= DMUS_OBJ_CATEGORY; + } + if (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) { + strncpyW (This->Desc.wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME); + dwNewFlags |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)); + } + if (pDesc->dwValidData & DMUS_OBJ_VERSION) { + This->Desc.vVersion.dwVersionLS = pDesc->vVersion.dwVersionLS; + This->Desc.vVersion.dwVersionMS = pDesc->vVersion.dwVersionMS; + dwNewFlags |= DMUS_OBJ_VERSION; + } + if (pDesc->dwValidData & DMUS_OBJ_DATE) { + This->Desc.ftDate.dwHighDateTime = pDesc->ftDate.dwHighDateTime; + This->Desc.ftDate.dwLowDateTime = pDesc->ftDate.dwLowDateTime; + dwNewFlags |= DMUS_OBJ_DATE; + } + /* set new flags */ + This->Desc.dwValidData |= dwNewFlags; + + dwFlagDifference = pDesc->dwValidData - dwNewFlags; + if (dwFlagDifference) { + pDesc->dwValidData &= ~dwFlagDifference; /* and with bitwise complement */ + return S_FALSE; + } else return S_OK; } HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, ObjectVtbl, iface); - DMUS_PRIVATE_CHUNK Chunk; + WINE_CHUNK Chunk; DWORD StreamSize, StreamCount, ListSize[1], ListCount[1]; LARGE_INTEGER liMove; /* used when skipping chunks */ TRACE("(%p, %p, %p)\n", This, pStream, pDesc); - /* FIXME: should this be determined from stream? */ - pDesc->dwValidData |= DMUS_OBJ_CLASS; - memcpy (&pDesc->guidClass, &CLSID_DirectMusicContainer, sizeof(CLSID)); + /* check whether arguments are OK */ + if (IsBadReadPtr (pStream, sizeof(LPVOID))) { + ERR(": pStream bad read pointer\n"); + return E_POINTER; + } + /* check whether pDesc is OK */ + if (IsBadReadPtr (pDesc, sizeof(DWORD))) { + ERR(": pDesc->dwSize bad read pointer\n"); + return E_POINTER; + } + if (pDesc->dwSize != sizeof(DMUS_OBJECTDESC)) { + ERR(": invalid pDesc->dwSize\n"); + return E_INVALIDARG; + } + if (IsBadWritePtr (pDesc, sizeof(DMUS_OBJECTDESC))) { + ERR(": pDesc bad write pointer\n"); + return E_POINTER; + } + + DM_STRUCT_INIT(pDesc); + /* here we go... */ IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case FOURCC_RIFF: { IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL); @@ -207,27 +271,48 @@ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPD StreamCount = 0; if (Chunk.fccID == DMUS_FOURCC_CONTAINER_FORM) { TRACE_(dmfile)(": container form\n"); + /* set guidClass */ + pDesc->dwValidData |= DMUS_OBJ_CLASS; + memcpy (&pDesc->guidClass, &CLSID_DirectMusicContainer, sizeof(CLSID)); do { IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_GUID_CHUNK: { TRACE_(dmfile)(": GUID chunk\n"); pDesc->dwValidData |= DMUS_OBJ_OBJECT; IStream_Read (pStream, &pDesc->guidObject, Chunk.dwSize, NULL); + TRACE_(dmdump)(": GUID: %s\n", debugstr_guid(&pDesc->guidObject)); break; } case DMUS_FOURCC_VERSION_CHUNK: { TRACE_(dmfile)(": version chunk\n"); pDesc->dwValidData |= DMUS_OBJ_VERSION; IStream_Read (pStream, &pDesc->vVersion, Chunk.dwSize, NULL); + TRACE_(dmdump)(": version: %s\n", debugstr_dmversion(&pDesc->vVersion)); break; } + case DMUS_FOURCC_DATE_CHUNK: { + TRACE_(dmfile)(": date chunk\n"); + IStream_Read (pStream, &pDesc->ftDate, Chunk.dwSize, NULL); + pDesc->dwValidData |= DMUS_OBJ_DATE; + TRACE_(dmdump)(": date: %s\n", debugstr_filetime(&pDesc->ftDate)); + break; + } case DMUS_FOURCC_CATEGORY_CHUNK: { TRACE_(dmfile)(": category chunk\n"); + /* if it happens that string is too long, + read what we can and skip the rest*/ + if (Chunk.dwSize > DMUS_MAX_CATEGORY_SIZE) { + IStream_Read (pStream, pDesc->wszCategory, DMUS_MAX_CATEGORY_SIZE, NULL); + liMove.QuadPart = Chunk.dwSize - DMUS_MAX_CATEGORY_SIZE; + IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); + } else { + IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL); + } pDesc->dwValidData |= DMUS_OBJ_CATEGORY; - IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL); + TRACE_(dmdump)(": category: %s\n", debugstr_w(pDesc->wszCategory)); break; } case FOURCC_LIST: { @@ -242,43 +327,24 @@ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPD do { IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes (though strings seem to be valid unicode) */ case mmioFOURCC('I','N','A','M'): case DMUS_FOURCC_UNAM_CHUNK: { TRACE_(dmfile)(": name chunk\n"); + /* if it happens that string is too long, + read what we can and skip the rest*/ + if (Chunk.dwSize > DMUS_MAX_NAME_SIZE) { + IStream_Read (pStream, pDesc->wszName, DMUS_MAX_NAME_SIZE, NULL); + liMove.QuadPart = Chunk.dwSize - DMUS_MAX_NAME_SIZE; + IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); + } else { + IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL); + } pDesc->dwValidData |= DMUS_OBJ_NAME; - IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL); - break; - } - case mmioFOURCC('I','A','R','T'): - case DMUS_FOURCC_UART_CHUNK: { - TRACE_(dmfile)(": artist chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','O','P'): - case DMUS_FOURCC_UCOP_CHUNK: { - TRACE_(dmfile)(": copyright chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','S','B','J'): - case DMUS_FOURCC_USBJ_CHUNK: { - TRACE_(dmfile)(": subject chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','M','T'): - case DMUS_FOURCC_UCMT_CHUNK: { - TRACE_(dmfile)(": comment chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); + TRACE_(dmdump)(": name: %s\n", debugstr_w(pDesc->wszName)); break; } default: { @@ -288,7 +354,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPD break; } } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); + TRACE_(dmfile)(": ListCount[0] = 0x%08lX < ListSize[0] = 0x%08lX\n", ListCount[0], ListSize[0]); } while (ListCount[0] < ListSize[0]); break; } @@ -308,7 +374,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPD break; } } - TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize); + TRACE_(dmfile)(": StreamCount[0] = 0x%08lX < StreamSize[0] = 0x%08lX\n", StreamCount, StreamSize); } while (StreamCount < StreamSize); break; } else { @@ -329,8 +395,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPD } } - TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (pDesc)); - + TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC(pDesc)); return S_OK; } @@ -344,50 +409,77 @@ ICOM_VTABLE(IDirectMusicObject) DirectMusicContainer_Object_Vtbl = { IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor }; -/* IDirectMusicContainerImpl IPersistStream part: */ +/* IPersistStream part: */ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj); + return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl, riid, ppobj); } ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); + return IDirectMusicContainerImpl_IDirectMusicContainer_AddRef ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl); } ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_Release (LPPERSISTSTREAM iface) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface); - return IDirectMusicContainerImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl); + return IDirectMusicContainerImpl_IDirectMusicContainer_Release ((LPDIRECTMUSICCONTAINER)&This->ContainerVtbl); } HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) { - *pClassID = CLSID_DirectMusicContainer; + ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface); + + TRACE("(%p, %p)\n", This, pClassID); + if (IsBadWritePtr (pClassID, sizeof(CLSID))) { + ERR(": pClassID bad write pointer\n"); + return E_POINTER; + } + + *pClassID = CLSID_DirectMusicContainer; return S_OK; } HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) { + /* FIXME: is implemented (somehow) */ return E_NOTIMPL; } HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) { ICOM_THIS_MULTI(IDirectMusicContainerImpl, PersistStreamVtbl, iface); - - DMUS_PRIVATE_CHUNK Chunk; + WINE_CHUNK Chunk; DWORD StreamSize, StreamCount, ListSize[3], ListCount[3]; LARGE_INTEGER liMove; /* used when skipping chunks */ ULARGE_INTEGER uliPos; /* needed when dealing with RIFF chunks */ LPDIRECTMUSICGETLOADER pGetLoader; LPDIRECTMUSICLOADER pLoader; + HRESULT result = S_OK; + + TRACE("(%p, %p):\n", This, pStm); + /* check whether pStm is valid read pointer */ + if (IsBadReadPtr (pStm, sizeof(LPVOID))) { + ERR(": pStm bad read pointer\n"); + return E_POINTER; + } + /* if stream is already set, this means we're loaded already */ + if (This->pStream) { + TRACE(": stream is already set, which means container is already loaded\n"); + return DMUS_E_ALREADY_LOADED; + } + /* get loader since it will be needed later */ - IStream_QueryInterface (pStm, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader); + if (FAILED(IStream_QueryInterface (pStm, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader))) { + ERR(": stream not supported\n"); + return DMUS_E_UNSUPPORTED_STREAM; + } IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader); IDirectMusicGetLoader_Release (pGetLoader); + This->pStream = pStm; IStream_AddRef (pStm); /* add count for later references */ - + + /* start with load */ IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case FOURCC_RIFF: { IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); @@ -397,33 +489,53 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if switch (Chunk.fccID) { case DMUS_FOURCC_CONTAINER_FORM: { TRACE_(dmfile)(": container form\n"); + memcpy (&This->Desc.guidClass, &CLSID_DirectMusicContainer, sizeof(CLSID)); + This->Desc.dwValidData |= DMUS_OBJ_CLASS; do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = 0x%04lx)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_CONTAINER_CHUNK: { TRACE_(dmfile)(": container header chunk\n"); - This->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); - IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL); + IStream_Read (pStm, &This->Header, Chunk.dwSize, NULL); + TRACE_(dmdump)(": container header chunk:\n%s", debugstr_DMUS_IO_CONTAINER_HEADER(&This->Header)); break; } case DMUS_FOURCC_GUID_CHUNK: { TRACE_(dmfile)(": GUID chunk\n"); - This->pDesc->dwValidData |= DMUS_OBJ_OBJECT; - IStream_Read (pStm, &This->pDesc->guidObject, Chunk.dwSize, NULL); + IStream_Read (pStm, &This->Desc.guidObject, Chunk.dwSize, NULL); + This->Desc.dwValidData |= DMUS_OBJ_OBJECT; + TRACE_(dmdump)(": GUID: %s\n", debugstr_guid(&This->Desc.guidObject)); break; } case DMUS_FOURCC_VERSION_CHUNK: { TRACE_(dmfile)(": version chunk\n"); - This->pDesc->dwValidData |= DMUS_OBJ_VERSION; - IStream_Read (pStm, &This->pDesc->vVersion, Chunk.dwSize, NULL); + IStream_Read (pStm, &This->Desc.vVersion, Chunk.dwSize, NULL); + This->Desc.dwValidData |= DMUS_OBJ_VERSION; + TRACE_(dmdump)(": version: %s\n", debugstr_dmversion(&This->Desc.vVersion)); break; } + case DMUS_FOURCC_DATE_CHUNK: { + TRACE_(dmfile)(": date chunk\n"); + IStream_Read (pStm, &This->Desc.ftDate, Chunk.dwSize, NULL); + This->Desc.dwValidData |= DMUS_OBJ_DATE; + TRACE_(dmdump)(": date: %s\n", debugstr_filetime(&This->Desc.ftDate)); + break; + } case DMUS_FOURCC_CATEGORY_CHUNK: { TRACE_(dmfile)(": category chunk\n"); - This->pDesc->dwValidData |= DMUS_OBJ_CATEGORY; - IStream_Read (pStm, This->pDesc->wszCategory, Chunk.dwSize, NULL); + /* if it happens that string is too long, + read what we can and skip the rest*/ + if (Chunk.dwSize > DMUS_MAX_CATEGORY_SIZE) { + IStream_Read (pStm, This->Desc.wszCategory, DMUS_MAX_CATEGORY_SIZE, NULL); + liMove.QuadPart = Chunk.dwSize - DMUS_MAX_CATEGORY_SIZE; + IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); + } else { + IStream_Read (pStm, This->Desc.wszCategory, Chunk.dwSize, NULL); + } + This->Desc.dwValidData |= DMUS_OBJ_CATEGORY; + TRACE_(dmdump)(": category: %s\n", debugstr_w(This->Desc.wszCategory)); break; } case FOURCC_LIST: { @@ -437,43 +549,24 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { /* don't ask me why, but M$ puts INFO elements in UNFO list sometimes (though strings seem to be valid unicode) */ case mmioFOURCC('I','N','A','M'): case DMUS_FOURCC_UNAM_CHUNK: { TRACE_(dmfile)(": name chunk\n"); - This->pDesc->dwValidData |= DMUS_OBJ_NAME; - IStream_Read (pStm, This->pDesc->wszName, Chunk.dwSize, NULL); - break; - } - case mmioFOURCC('I','A','R','T'): - case DMUS_FOURCC_UART_CHUNK: { - TRACE_(dmfile)(": artist chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','O','P'): - case DMUS_FOURCC_UCOP_CHUNK: { - TRACE_(dmfile)(": copyright chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','S','B','J'): - case DMUS_FOURCC_USBJ_CHUNK: { - TRACE_(dmfile)(": subject chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','M','T'): - case DMUS_FOURCC_UCMT_CHUNK: { - TRACE_(dmfile)(": comment chunk (ignored)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); + /* if it happens that string is too long, + read what we can and skip the rest*/ + if (Chunk.dwSize > DMUS_MAX_NAME_SIZE) { + IStream_Read (pStm, This->Desc.wszName, DMUS_MAX_NAME_SIZE, NULL); + liMove.QuadPart = Chunk.dwSize - DMUS_MAX_NAME_SIZE; + IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); + } else { + IStream_Read (pStm, This->Desc.wszName, Chunk.dwSize, NULL); + } + This->Desc.dwValidData |= DMUS_OBJ_NAME; + TRACE_(dmdump)(": name: %s\n", debugstr_w(This->Desc.wszName)); break; } default: { @@ -483,7 +576,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if break; } } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); + TRACE_(dmfile)(": ListCount[0] = 0x%08lX < ListSize[0] = 0x%08lX\n", ListCount[0], ListSize[0]); } while (ListCount[0] < ListSize[0]); break; } @@ -492,7 +585,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case FOURCC_LIST: { IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); @@ -501,30 +594,32 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if ListCount[1] = 0; switch (Chunk.fccID) { case DMUS_FOURCC_CONTAINED_OBJECT_LIST: { - DMUS_IO_CONTAINED_OBJECT_HEADER tmpObjectHeader; /* temporary structure */ - LPDMUS_PRIVATE_CONTAINED_OBJECT_ENTRY newEntry; + LPWINE_CONTAINER_ENTRY pNewEntry; TRACE_(dmfile)(": contained object list\n"); - memset (&tmpObjectHeader, 0, sizeof(DMUS_IO_CONTAINED_OBJECT_HEADER)); - newEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY)); - newEntry->pDesc = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC)); - DM_STRUCT_INIT(newEntry->pDesc); + pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_CONTAINER_ENTRY)); + DM_STRUCT_INIT(&pNewEntry->Desc); do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_CONTAINED_ALIAS_CHUNK: { TRACE_(dmfile)(": alias chunk\n"); - newEntry->wszAlias = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); - IStream_Read (pStm, newEntry->wszAlias, Chunk.dwSize, NULL); + pNewEntry->wszAlias = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + IStream_Read (pStm, pNewEntry->wszAlias, Chunk.dwSize, NULL); + TRACE_(dmdump)(": alias: %s\n", debugstr_w(pNewEntry->wszAlias)); break; } case DMUS_FOURCC_CONTAINED_OBJECT_CHUNK: { + DMUS_IO_CONTAINED_OBJECT_HEADER tmpObjectHeader; TRACE_(dmfile)(": contained object header chunk\n"); IStream_Read (pStm, &tmpObjectHeader, Chunk.dwSize, NULL); + TRACE_(dmdump)(": contained object header: \n%s", debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER(&tmpObjectHeader)); /* copy guidClass */ - newEntry->pDesc->dwValidData |= DMUS_OBJ_CLASS; - memcpy (&newEntry->pDesc->guidClass, &tmpObjectHeader.guidClassID, sizeof(GUID)); + pNewEntry->Desc.dwValidData |= DMUS_OBJ_CLASS; + memcpy (&pNewEntry->Desc.guidClass, &tmpObjectHeader.guidClassID, sizeof(GUID)); + /* store flags */ + pNewEntry->dwFlags = tmpObjectHeader.dwFlags; break; } /* now read data... it may be safe to read everything after object header chunk, @@ -536,58 +631,60 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if ListCount[2] = 0; switch (Chunk.fccID) { case DMUS_FOURCC_REF_LIST: { - DMUS_IO_REFERENCE tmpReferenceHeader; /* temporary structure */ TRACE_(dmfile)(": reference list\n"); - memset (&tmpReferenceHeader, 0, sizeof(DMUS_IO_REFERENCE)); + pNewEntry->bIsRIFF = 0; do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); + TRACE_(dmfile)(": %s chunk (size = 0x%08lX)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_REF_CHUNK: { + DMUS_IO_REFERENCE tmpReferenceHeader; /* temporary structure */ TRACE_(dmfile)(": reference header chunk\n"); + memset (&tmpReferenceHeader, 0, sizeof(DMUS_IO_REFERENCE)); IStream_Read (pStm, &tmpReferenceHeader, Chunk.dwSize, NULL); /* copy retrieved data to DMUS_OBJECTDESC */ - if (!IsEqualCLSID (&newEntry->pDesc->guidClass, &tmpReferenceHeader.guidClassID)) ERR(": object header declares different CLSID than reference header\n"); - /* no need since it's already there */ - /*memcpy (&newEntry->pDesc->guidClass, &tempReferenceHeader.guidClassID, sizeof(GUID)); */ - newEntry->pDesc->dwValidData = tmpReferenceHeader.dwValidData; + if (!IsEqualCLSID (&pNewEntry->Desc.guidClass, &tmpReferenceHeader.guidClassID)) ERR(": object header declares different CLSID than reference header?\n"); + /* it shouldn't be necessary to copy guidClass, since it was set in contained object header already... + yet if they happen to be different, I'd rather stick to this one */ + memcpy (&pNewEntry->Desc.guidClass, &tmpReferenceHeader.guidClassID, sizeof(GUID)); + pNewEntry->Desc.dwValidData |= tmpReferenceHeader.dwValidData; break; } case DMUS_FOURCC_GUID_CHUNK: { TRACE_(dmfile)(": guid chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, &newEntry->pDesc->guidObject, Chunk.dwSize, NULL); + IStream_Read (pStm, &pNewEntry->Desc.guidObject, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_DATE_CHUNK: { TRACE_(dmfile)(": file date chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, &newEntry->pDesc->ftDate, Chunk.dwSize, NULL); + IStream_Read (pStm, &pNewEntry->Desc.ftDate, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_NAME_CHUNK: { TRACE_(dmfile)(": name chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, newEntry->pDesc->wszName, Chunk.dwSize, NULL); + IStream_Read (pStm, pNewEntry->Desc.wszName, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_FILE_CHUNK: { TRACE_(dmfile)(": file name chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, newEntry->pDesc->wszFileName, Chunk.dwSize, NULL); + IStream_Read (pStm, pNewEntry->Desc.wszFileName, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_CATEGORY_CHUNK: { TRACE_(dmfile)(": category chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, newEntry->pDesc->wszCategory, Chunk.dwSize, NULL); + IStream_Read (pStm, pNewEntry->Desc.wszCategory, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_VERSION_CHUNK: { TRACE_(dmfile)(": version chunk\n"); /* no need to set flags since they were copied from reference header */ - IStream_Read (pStm, &newEntry->pDesc->vVersion, Chunk.dwSize, NULL); + IStream_Read (pStm, &pNewEntry->Desc.vVersion, Chunk.dwSize, NULL); break; } default: { @@ -597,7 +694,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if break; } } - TRACE_(dmfile)(": ListCount[2] = %ld < ListSize[2] = %ld\n", ListCount[2], ListSize[2]); + TRACE_(dmfile)(": ListCount[2] = 0x%08lX < ListSize[2] = 0x%08lX\n", ListCount[2], ListSize[2]); } while (ListCount[2] < ListSize[2]); break; } @@ -608,13 +705,14 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if } break; } + case FOURCC_RIFF: { IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID)); if (IS_VALID_DMFORM (Chunk.fccID)) { TRACE_(dmfile)(": valid DMUSIC form\n"); - /* we'll have to skip whole RIFF chunk after SetObject call */ - #define RIFF_LOADING /* effective hack ;) */ + pNewEntry->bIsRIFF = 1; + /* we'll have to skip whole RIFF chunk after SetObject is called */ liMove.QuadPart = 0; IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &uliPos); uliPos.QuadPart += (Chunk.dwSize - sizeof(FOURCC)); /* set uliPos at the end of RIFF chunk */ @@ -623,12 +721,8 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if liMove.QuadPart -= (sizeof(FOURCC)+sizeof(DWORD)+sizeof(FOURCC)); IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* put pointer to stream in descriptor */ - newEntry->pDesc->dwValidData |= DMUS_OBJ_STREAM; - /* this is not how M$ does it (according to my tests), but - who says their way is better? */ - /* *newEntry->pDesc->pStream = pStm; */ - /* *IStream_AddRef (pStm); */ /* reference increased */ - IStream_Clone (pStm, &newEntry->pDesc->pStream); + pNewEntry->Desc.dwValidData |= DMUS_OBJ_STREAM; + pNewEntry->Desc.pStream = pStm; /* we don't have to worry about cloning, since SetObject will perform it */ /* wait till we get on the end of object list */ } else { TRACE_(dmfile)(": invalid DMUSIC form (skipping)\n"); @@ -645,35 +739,21 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if break; } } - TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]); + TRACE_(dmfile)(": ListCount[1] = 0x%08lX < ListSize[1] = 0x%08lX\n", ListCount[1], ListSize[1]); } while (ListCount[1] < ListSize[1]); - /* SetObject: this will fill descriptor with additional info - and add alias in loader's cache */ - IDirectMusicLoader_SetObject (pLoader, newEntry->pDesc); - /* my tests show tha we shouldn't return any info on stream when calling EnumObject... sigh... which - means we have to clear these fields to be M$ compliant; but funny thing is, we return filename - when loading from reference... M$ sux */ - /* FIXME: test what happens when we load with DMUS_OBJ_MEMORY */ - /* if we have loaded through RIFF chunk, skip it and clear stream flag */ - #ifdef RIFF_LOADING + /* SetObject: this will fill descriptor with additional info and add alias in loader's cache */ + IDirectMusicLoader_SetObject (pLoader, &pNewEntry->Desc); + /* now that SetObject collected appropriate info into descriptor we can live happily ever after; + or not, since we have to clean evidence of loading through stream... *sigh* + and we have to skip rest of the chunk, if we loaded through RIFF */ + if (pNewEntry->bIsRIFF) { liMove.QuadPart = uliPos.QuadPart; IStream_Seek (pStm, liMove, STREAM_SEEK_SET, NULL); - newEntry->pDesc->dwValidData &= ~DMUS_OBJ_STREAM; /* clear flag */ - newEntry->pDesc->pStream = NULL; - #undef RIFF_LOADING - #endif - /* add entry to list of objects */ - list_add_tail (&This->ObjectsList, &newEntry->entry); - - /* now, if DMUS_CONTAINER_NOLOADS is not set, we are supposed to load contained objects; - so when we call GetObject later, they'll already be in cache */ - if (!(This->pHeader->dwFlags & DMUS_CONTAINER_NOLOADS)) { - IDirectMusicObject* pObject; - TRACE_(dmfile)(": DMUS_CONTAINER_NOLOADS not set\n"); - /* native container and builtin loader show that we use IDirectMusicObject here */ - if (SUCCEEDED(IDirectMusicLoader_GetObject (pLoader, newEntry->pDesc, &IID_IDirectMusicObject, (LPVOID*)&pObject))) - IDirectMusicObject_Release (pObject); + pNewEntry->Desc.dwValidData &= ~DMUS_OBJ_STREAM; /* clear flag (and with bitwise complement) */ + pNewEntry->Desc.pStream = NULL; } + /* add entry to list of objects */ + list_add_tail (This->pContainedObjects, &pNewEntry->entry); break; } default: { @@ -692,7 +772,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if break; } } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); + TRACE_(dmfile)(": ListCount[0] = 0x%08lX < ListSize[0] = 0x%08lX\n", ListCount[0], ListSize[0]); } while (ListCount[0] < ListSize[0]); break; } @@ -712,7 +792,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if break; } } - TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize); + TRACE_(dmfile)(": StreamCount[0] = 0x%08lX < StreamSize[0] = 0x%08lX\n", StreamCount, StreamSize); } while (StreamCount < StreamSize); break; } @@ -724,6 +804,7 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if } } TRACE_(dmfile)(": reading finished\n"); + This->Desc.dwValidData |= DMUS_OBJ_LOADED; break; } default: { @@ -733,42 +814,60 @@ HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Load (LPPERSISTSTREAM if return E_FAIL; } } - - IDirectMusicLoader_Release (pLoader); /* release loader */ -#if 0 + /* now, if DMUS_CONTAINER_NOLOADS is not set, we are supposed to load contained objects; + so when we call GetObject later, they'll already be in cache */ + if (!(This->Header.dwFlags & DMUS_CONTAINER_NOLOADS)) { + struct list *pEntry; + LPWINE_CONTAINER_ENTRY pContainedObject; + + TRACE(": DMUS_CONTAINER_NOLOADS not set... load all objects\n"); + + LIST_FOR_EACH (pEntry, This->pContainedObjects) { + IDirectMusicObject* pObject; + pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry); + /* get object from loader and then release it */ + if (SUCCEEDED(IDirectMusicLoader_GetObject (pLoader, &pContainedObject->Desc, &IID_IDirectMusicObject, (LPVOID*)&pObject))) { + pContainedObject->pObject = pObject; /* for final release */ + IDirectMusicObject_Release (pObject); /* we don't really need this one */ + } else { + WARN(": failed to load contained object\n"); + result = DMUS_S_PARTIALLOAD; + } + } + } + + IDirectMusicLoader_Release (pLoader); /* release loader */ + +#if 0 /* DEBUG: dumps whole container object tree: */ if (TRACE_ON(dmloader)) { int r = 0; - DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY *tmpEntry; + LPWINE_CONTAINER_ENTRY tmpEntry; struct list *listEntry; TRACE("*** IDirectMusicContainer (%p) ***\n", This->ContainerVtbl); - TRACE(" - Object descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (This->pDesc)); - TRACE(" - Header:\n"); - TRACE(" - dwFlags: %s", debugstr_DMUS_CONTAINER_FLAGS (This->pHeader->dwFlags)); - TRACE(" - Objects:\n"); - - LIST_FOR_EACH (listEntry, &This->ObjectsList) { - tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY, entry ); + LIST_FOR_EACH (listEntry, This->pContainedObjects) { + tmpEntry = LIST_ENTRY( listEntry, WINE_CONTAINER_ENTRY, entry ); TRACE(" - Object[%i]:\n", r); TRACE(" - wszAlias: %s\n", debugstr_w(tmpEntry->wszAlias)); - TRACE(" - Object descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC(tmpEntry->pDesc)); + TRACE(" - Object descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC(&tmpEntry->Desc)); r++; } } #endif - - - return S_OK; + + return result; } HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) { + ERR(": should not be needed\n"); return E_NOTIMPL; } HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) { + ERR(": should not be needed\n"); return E_NOTIMPL; } @@ -787,22 +886,60 @@ ICOM_VTABLE(IPersistStream) DirectMusicContainer_PersistStream_Vtbl = { /* for ClassFactory */ HRESULT WINAPI DMUSIC_CreateDirectMusicContainerImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) { IDirectMusicContainerImpl* obj; - + obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicContainerImpl)); if (NULL == obj) { *ppobj = (LPVOID) NULL; return E_OUTOFMEMORY; } - obj->UnknownVtbl = &DirectMusicContainer_Unknown_Vtbl; obj->ContainerVtbl = &DirectMusicContainer_Container_Vtbl; obj->ObjectVtbl = &DirectMusicContainer_Object_Vtbl; obj->PersistStreamVtbl = &DirectMusicContainer_PersistStream_Vtbl; - obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC)); - DM_STRUCT_INIT(obj->pDesc); - obj->pDesc->dwValidData |= DMUS_OBJ_CLASS; - memcpy (&obj->pDesc->guidClass, &CLSID_DirectMusicContainer, sizeof (CLSID)); - obj->ref = 0; /* will be inited by QueryInterface */ - list_init (&obj->ObjectsList); + obj->dwRef = 0; /* will be inited by QueryInterface */ + obj->pContainedObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); + list_init (obj->pContainedObjects); + + /* increase number of instances */ + InterlockedIncrement (&dwDirectMusicContainer); - return IDirectMusicContainerImpl_IUnknown_QueryInterface ((LPUNKNOWN)&obj->UnknownVtbl, lpcGUID, ppobj); + return IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface ((LPDIRECTMUSICCONTAINER)&obj->ContainerVtbl, lpcGUID, ppobj); +} + +HRESULT WINAPI DMUSIC_DestroyDirectMusicContainerImpl (LPDIRECTMUSICCONTAINER iface) { + ICOM_THIS_MULTI(IDirectMusicContainerImpl, ContainerVtbl, iface); + LPDIRECTMUSICLOADER pLoader; + LPDIRECTMUSICGETLOADER pGetLoader; + struct list *pEntry; + LPWINE_CONTAINER_ENTRY pContainedObject; + + /* get loader (from stream we loaded from) */ + TRACE(": getting loader\n"); + IStream_QueryInterface (This->pStream, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader); + IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader); + IDirectMusicGetLoader_Release (pGetLoader); + + /* release objects from loader's cache (if appropriate) */ + TRACE(": releasing objects from loader's cache\n"); + LIST_FOR_EACH (pEntry, This->pContainedObjects) { + pContainedObject = LIST_ENTRY (pEntry, WINE_CONTAINER_ENTRY, entry); + /* my tests indicate that container releases objects *only* + if they were loaded at it's load-time (makes sense, it doesn't + have pointers to objects otherwise); BTW: native container seems + ti ignore the flags (I won't) */ + if (pContainedObject->pObject && !(pContainedObject->dwFlags & DMUS_CONTAINED_OBJF_KEEP)) { + /* flags say it shouldn't be kept in loader's cache */ + IDirectMusicLoader_ReleaseObject (pLoader, pContainedObject->pObject); + } + } + IDirectMusicLoader_Release (pLoader); + + /* release stream we loaded from */ + IStream_Release (This->pStream); + + /* FIXME: release allocated entries */ + + /* decrease number of instances */ + InterlockedDecrement (&dwDirectMusicContainer); + + return S_OK; } diff --git a/dlls/dmloader/debug.c b/dlls/dmloader/debug.c new file mode 100644 index 00000000000..841fa9d6e8c --- /dev/null +++ b/dlls/dmloader/debug.c @@ -0,0 +1,536 @@ +/* Debug and Helper Functions + * + * Copyright (C) 2004 Rok Mandeljc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dmloader_private.h" + +/* check whether the given DWORD is even (return 0) or odd (return 1) */ +int even_or_odd (DWORD number) { + return (number & 0x1); /* basically, check if bit 0 is set ;) */ +} + +/* figures out whether given FOURCC is valid DirectMusic form ID */ +BOOL IS_VALID_DMFORM (FOURCC chunkID) { + if ((chunkID == DMUS_FOURCC_AUDIOPATH_FORM) || (chunkID == DMUS_FOURCC_BAND_FORM) || (chunkID == DMUS_FOURCC_CHORDMAP_FORM) + || (chunkID == DMUS_FOURCC_CONTAINER_FORM) || (chunkID == FOURCC_DLS) || (chunkID == DMUS_FOURCC_SCRIPT_FORM) + || (chunkID == DMUS_FOURCC_SEGMENT_FORM) || (chunkID == DMUS_FOURCC_STYLE_FORM) || (chunkID == DMUS_FOURCC_TOOLGRAPH_FORM) + || (chunkID == DMUS_FOURCC_TRACK_FORM) || (chunkID == mmioFOURCC('W','A','V','E'))) return TRUE; + else return FALSE; +} + +/* translate STREAM_SEEK flag to string */ +const char *resolve_STREAM_SEEK (DWORD flag) { + switch (flag) { + case STREAM_SEEK_SET: + return wine_dbg_sprintf ("STREAM_SEEK_SET"); + case STREAM_SEEK_CUR: + return wine_dbg_sprintf ("STREAM_SEEK_CUR"); + case STREAM_SEEK_END: + return wine_dbg_sprintf ("STREAM_SEEK_END"); + default: + return wine_dbg_sprintf ("()"); + } +} + +/* FOURCC to string conversion for debug messages */ +const char *debugstr_fourcc (DWORD fourcc) { + if (!fourcc) return "'null'"; + return wine_dbg_sprintf ("\'%c%c%c%c\'", + (char)(fourcc), (char)(fourcc >> 8), + (char)(fourcc >> 16), (char)(fourcc >> 24)); +} + +/* DMUS_VERSION struct to string conversion for debug messages */ +const char *debugstr_dmversion (LPDMUS_VERSION version) { + if (!version) return "'null'"; + return wine_dbg_sprintf ("\'%i,%i,%i,%i\'", + HIWORD(version->dwVersionMS),LOWORD(version->dwVersionMS), + HIWORD(version->dwVersionLS), LOWORD(version->dwVersionLS)); +} + +/* month number into month name (for debugstr_filetime) */ +const char *debugstr_month (DWORD dwMonth) { + switch (dwMonth) { + case 1: return "January"; + case 2: return "February"; + case 3: return "March"; + case 4: return "April"; + case 5: return "May"; + case 6: return "June"; + case 7: return "July"; + case 8: return "August"; + case 9: return "September"; + case 10: return "October"; + case 11: return "November"; + case 12: return "December"; + default: return "Invalid"; + } +} + +/* FILETIME struct to string conversion for debug messages */ +const char *debugstr_filetime (LPFILETIME time) { + SYSTEMTIME sysTime; + + if (!time) return "'null'"; + + FileTimeToSystemTime (time, &sysTime); + + return wine_dbg_sprintf ("\'%02i. %s %04i %02i:%02i:%02i\'", \ + sysTime.wDay, debugstr_month(sysTime.wMonth), sysTime.wYear, + sysTime.wHour, sysTime.wMinute, sysTime.wSecond); +} + +/* returns name of given GUID */ +const char *debugstr_dmguid (const GUID *id) { + static const guid_info guids[] = { + /* CLSIDs */ + GE(CLSID_AudioVBScript), + GE(CLSID_DirectMusic), + GE(CLSID_DirectMusicAudioPath), + GE(CLSID_DirectMusicAudioPathConfig), + GE(CLSID_DirectMusicAuditionTrack), + GE(CLSID_DirectMusicBand), + GE(CLSID_DirectMusicBandTrack), + GE(CLSID_DirectMusicChordMapTrack), + GE(CLSID_DirectMusicChordMap), + GE(CLSID_DirectMusicChordTrack), + GE(CLSID_DirectMusicCollection), + GE(CLSID_DirectMusicCommandTrack), + GE(CLSID_DirectMusicComposer), + GE(CLSID_DirectMusicContainer), + GE(CLSID_DirectMusicGraph), + GE(CLSID_DirectMusicLoader), + GE(CLSID_DirectMusicLyricsTrack), + GE(CLSID_DirectMusicMarkerTrack), + GE(CLSID_DirectMusicMelodyFormulationTrack), + GE(CLSID_DirectMusicMotifTrack), + GE(CLSID_DirectMusicMuteTrack), + GE(CLSID_DirectMusicParamControlTrack), + GE(CLSID_DirectMusicPatternTrack), + GE(CLSID_DirectMusicPerformance), + GE(CLSID_DirectMusicScript), + GE(CLSID_DirectMusicScriptAutoImpSegment), + GE(CLSID_DirectMusicScriptAutoImpPerformance), + GE(CLSID_DirectMusicScriptAutoImpSegmentState), + GE(CLSID_DirectMusicScriptAutoImpAudioPathConfig), + GE(CLSID_DirectMusicScriptAutoImpAudioPath), + GE(CLSID_DirectMusicScriptAutoImpSong), + GE(CLSID_DirectMusicScriptSourceCodeLoader), + GE(CLSID_DirectMusicScriptTrack), + GE(CLSID_DirectMusicSection), + GE(CLSID_DirectMusicSegment), + GE(CLSID_DirectMusicSegmentState), + GE(CLSID_DirectMusicSegmentTriggerTrack), + GE(CLSID_DirectMusicSegTriggerTrack), + GE(CLSID_DirectMusicSeqTrack), + GE(CLSID_DirectMusicSignPostTrack), + GE(CLSID_DirectMusicSong), + GE(CLSID_DirectMusicStyle), + GE(CLSID_DirectMusicStyleTrack), + GE(CLSID_DirectMusicSynth), + GE(CLSID_DirectMusicSynthSink), + GE(CLSID_DirectMusicSysExTrack), + GE(CLSID_DirectMusicTemplate), + GE(CLSID_DirectMusicTempoTrack), + GE(CLSID_DirectMusicTimeSigTrack), + GE(CLSID_DirectMusicWaveTrack), + GE(CLSID_DirectSoundWave), + /* IIDs */ + GE(IID_IDirectMusic), + GE(IID_IDirectMusic2), + GE(IID_IDirectMusic8), + GE(IID_IDirectMusicAudioPath), + GE(IID_IDirectMusicBand), + GE(IID_IDirectMusicBuffer), + GE(IID_IDirectMusicChordMap), + GE(IID_IDirectMusicCollection), + GE(IID_IDirectMusicComposer), + GE(IID_IDirectMusicContainer), + GE(IID_IDirectMusicDownload), + GE(IID_IDirectMusicDownloadedInstrument), + GE(IID_IDirectMusicGetLoader), + GE(IID_IDirectMusicGraph), + GE(IID_IDirectMusicInstrument), + GE(IID_IDirectMusicLoader), + GE(IID_IDirectMusicLoader8), + GE(IID_IDirectMusicObject), + GE(IID_IDirectMusicPatternTrack), + GE(IID_IDirectMusicPerformance), + GE(IID_IDirectMusicPerformance2), + GE(IID_IDirectMusicPerformance8), + GE(IID_IDirectMusicPort), + GE(IID_IDirectMusicPortDownload), + GE(IID_IDirectMusicScript), + GE(IID_IDirectMusicSegment), + GE(IID_IDirectMusicSegment2), + GE(IID_IDirectMusicSegment8), + GE(IID_IDirectMusicSegmentState), + GE(IID_IDirectMusicSegmentState8), + GE(IID_IDirectMusicStyle), + GE(IID_IDirectMusicStyle8), + GE(IID_IDirectMusicSynth), + GE(IID_IDirectMusicSynth8), + GE(IID_IDirectMusicSynthSink), + GE(IID_IDirectMusicThru), + GE(IID_IDirectMusicTool), + GE(IID_IDirectMusicTool8), + GE(IID_IDirectMusicTrack), + GE(IID_IDirectMusicTrack8), + GE(IID_IUnknown), + GE(IID_IPersistStream), + GE(IID_IStream), + GE(IID_IClassFactory), + /* GUIDs */ + GE(GUID_DirectMusicAllTypes), + GE(GUID_NOTIFICATION_CHORD), + GE(GUID_NOTIFICATION_COMMAND), + GE(GUID_NOTIFICATION_MEASUREANDBEAT), + GE(GUID_NOTIFICATION_PERFORMANCE), + GE(GUID_NOTIFICATION_RECOMPOSE), + GE(GUID_NOTIFICATION_SEGMENT), + GE(GUID_BandParam), + GE(GUID_ChordParam), + GE(GUID_CommandParam), + GE(GUID_CommandParam2), + GE(GUID_CommandParamNext), + GE(GUID_IDirectMusicBand), + GE(GUID_IDirectMusicChordMap), + GE(GUID_IDirectMusicStyle), + GE(GUID_MuteParam), + GE(GUID_Play_Marker), + GE(GUID_RhythmParam), + GE(GUID_TempoParam), + GE(GUID_TimeSignature), + GE(GUID_Valid_Start_Time), + GE(GUID_Clear_All_Bands), + GE(GUID_ConnectToDLSCollection), + GE(GUID_Disable_Auto_Download), + GE(GUID_DisableTempo), + GE(GUID_DisableTimeSig), + GE(GUID_Download), + GE(GUID_DownloadToAudioPath), + GE(GUID_Enable_Auto_Download), + GE(GUID_EnableTempo), + GE(GUID_EnableTimeSig), + GE(GUID_IgnoreBankSelectForGM), + GE(GUID_SeedVariations), + GE(GUID_StandardMIDIFile), + GE(GUID_Unload), + GE(GUID_UnloadFromAudioPath), + GE(GUID_Variations), + GE(GUID_PerfMasterTempo), + GE(GUID_PerfMasterVolume), + GE(GUID_PerfMasterGrooveLevel), + GE(GUID_PerfAutoDownload), + GE(GUID_DefaultGMCollection), + GE(GUID_Synth_Default), + GE(GUID_Buffer_Reverb), + GE(GUID_Buffer_EnvReverb), + GE(GUID_Buffer_Stereo), + GE(GUID_Buffer_3D_Dry), + GE(GUID_Buffer_Mono), + GE(GUID_DMUS_PROP_GM_Hardware), + GE(GUID_DMUS_PROP_GS_Capable), + GE(GUID_DMUS_PROP_GS_Hardware), + GE(GUID_DMUS_PROP_DLS1), + GE(GUID_DMUS_PROP_DLS2), + GE(GUID_DMUS_PROP_Effects), + GE(GUID_DMUS_PROP_INSTRUMENT2), + GE(GUID_DMUS_PROP_LegacyCaps), + GE(GUID_DMUS_PROP_MemorySize), + GE(GUID_DMUS_PROP_SampleMemorySize), + GE(GUID_DMUS_PROP_SamplePlaybackRate), + GE(GUID_DMUS_PROP_SetSynthSink), + GE(GUID_DMUS_PROP_SinkUsesDSound), + GE(GUID_DMUS_PROP_SynthSink_DSOUND), + GE(GUID_DMUS_PROP_SynthSink_WAVE), + GE(GUID_DMUS_PROP_Volume), + GE(GUID_DMUS_PROP_WavesReverb), + GE(GUID_DMUS_PROP_WriteLatency), + GE(GUID_DMUS_PROP_WritePeriod), + GE(GUID_DMUS_PROP_XG_Capable), + GE(GUID_DMUS_PROP_XG_Hardware) + }; + + unsigned int i; + + if (!id) return "(null)"; + for (i = 0; i < sizeof(guids)/sizeof(guids[0]); i++) { + if (IsEqualGUID(id, guids[i].guid)) + return guids[i].name; + } + + /* if we didn't find it, act like standard debugstr_guid */ + return debugstr_guid(id); +} + +/* returns name of given error code */ +const char *debugstr_dmreturn (DWORD code) { + static const flag_info codes[] = { + FE(S_OK), + FE(S_FALSE), + FE(DMUS_S_PARTIALLOAD), + FE(DMUS_S_PARTIALDOWNLOAD), + FE(DMUS_S_REQUEUE), + FE(DMUS_S_FREE), + FE(DMUS_S_END), + FE(DMUS_S_STRING_TRUNCATED), + FE(DMUS_S_LAST_TOOL), + FE(DMUS_S_OVER_CHORD), + FE(DMUS_S_UP_OCTAVE), + FE(DMUS_S_DOWN_OCTAVE), + FE(DMUS_S_NOBUFFERCONTROL), + FE(DMUS_S_GARBAGE_COLLECTED), + FE(E_NOTIMPL), + FE(E_NOINTERFACE), + FE(E_POINTER), + FE(CLASS_E_NOAGGREGATION), + FE(CLASS_E_CLASSNOTAVAILABLE), + FE(REGDB_E_CLASSNOTREG), + FE(E_OUTOFMEMORY), + FE(E_FAIL), + FE(E_INVALIDARG), + FE(DMUS_E_DRIVER_FAILED), + FE(DMUS_E_PORTS_OPEN), + FE(DMUS_E_DEVICE_IN_USE), + FE(DMUS_E_INSUFFICIENTBUFFER), + FE(DMUS_E_BUFFERNOTSET), + FE(DMUS_E_BUFFERNOTAVAILABLE), + FE(DMUS_E_NOTADLSCOL), + FE(DMUS_E_INVALIDOFFSET), + FE(DMUS_E_ALREADY_LOADED), + FE(DMUS_E_INVALIDPOS), + FE(DMUS_E_INVALIDPATCH), + FE(DMUS_E_CANNOTSEEK), + FE(DMUS_E_CANNOTWRITE), + FE(DMUS_E_CHUNKNOTFOUND), + FE(DMUS_E_INVALID_DOWNLOADID), + FE(DMUS_E_NOT_DOWNLOADED_TO_PORT), + FE(DMUS_E_ALREADY_DOWNLOADED), + FE(DMUS_E_UNKNOWN_PROPERTY), + FE(DMUS_E_SET_UNSUPPORTED), + FE(DMUS_E_GET_UNSUPPORTED), + FE(DMUS_E_NOTMONO), + FE(DMUS_E_BADARTICULATION), + FE(DMUS_E_BADINSTRUMENT), + FE(DMUS_E_BADWAVELINK), + FE(DMUS_E_NOARTICULATION), + FE(DMUS_E_NOTPCM), + FE(DMUS_E_BADWAVE), + FE(DMUS_E_BADOFFSETTABLE), + FE(DMUS_E_UNKNOWNDOWNLOAD), + FE(DMUS_E_NOSYNTHSINK), + FE(DMUS_E_ALREADYOPEN), + FE(DMUS_E_ALREADYCLOSED), + FE(DMUS_E_SYNTHNOTCONFIGURED), + FE(DMUS_E_SYNTHACTIVE), + FE(DMUS_E_CANNOTREAD), + FE(DMUS_E_DMUSIC_RELEASED), + FE(DMUS_E_BUFFER_EMPTY), + FE(DMUS_E_BUFFER_FULL), + FE(DMUS_E_PORT_NOT_CAPTURE), + FE(DMUS_E_PORT_NOT_RENDER), + FE(DMUS_E_DSOUND_NOT_SET), + FE(DMUS_E_ALREADY_ACTIVATED), + FE(DMUS_E_INVALIDBUFFER), + FE(DMUS_E_WAVEFORMATNOTSUPPORTED), + FE(DMUS_E_SYNTHINACTIVE), + FE(DMUS_E_DSOUND_ALREADY_SET), + FE(DMUS_E_INVALID_EVENT), + FE(DMUS_E_UNSUPPORTED_STREAM), + FE(DMUS_E_ALREADY_INITED), + FE(DMUS_E_INVALID_BAND), + FE(DMUS_E_TRACK_HDR_NOT_FIRST_CK), + FE(DMUS_E_TOOL_HDR_NOT_FIRST_CK), + FE(DMUS_E_INVALID_TRACK_HDR), + FE(DMUS_E_INVALID_TOOL_HDR), + FE(DMUS_E_ALL_TOOLS_FAILED), + FE(DMUS_E_ALL_TRACKS_FAILED), + FE(DMUS_E_NOT_FOUND), + FE(DMUS_E_NOT_INIT), + FE(DMUS_E_TYPE_DISABLED), + FE(DMUS_E_TYPE_UNSUPPORTED), + FE(DMUS_E_TIME_PAST), + FE(DMUS_E_TRACK_NOT_FOUND), + FE(DMUS_E_TRACK_NO_CLOCKTIME_SUPPORT), + FE(DMUS_E_NO_MASTER_CLOCK), + FE(DMUS_E_LOADER_NOCLASSID), + FE(DMUS_E_LOADER_BADPATH), + FE(DMUS_E_LOADER_FAILEDOPEN), + FE(DMUS_E_LOADER_FORMATNOTSUPPORTED), + FE(DMUS_E_LOADER_FAILEDCREATE), + FE(DMUS_E_LOADER_OBJECTNOTFOUND), + FE(DMUS_E_LOADER_NOFILENAME), + FE(DMUS_E_INVALIDFILE), + FE(DMUS_E_ALREADY_EXISTS), + FE(DMUS_E_OUT_OF_RANGE), + FE(DMUS_E_SEGMENT_INIT_FAILED), + FE(DMUS_E_ALREADY_SENT), + FE(DMUS_E_CANNOT_FREE), + FE(DMUS_E_CANNOT_OPEN_PORT), + FE(DMUS_E_CANNOT_CONVERT), + FE(DMUS_E_DESCEND_CHUNK_FAIL), + FE(DMUS_E_NOT_LOADED), + FE(DMUS_E_SCRIPT_LANGUAGE_INCOMPATIBLE), + FE(DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE), + FE(DMUS_E_SCRIPT_ERROR_IN_SCRIPT), + FE(DMUS_E_SCRIPT_CANTLOAD_OLEAUT32), + FE(DMUS_E_SCRIPT_LOADSCRIPT_ERROR), + FE(DMUS_E_SCRIPT_INVALID_FILE), + FE(DMUS_E_INVALID_SCRIPTTRACK), + FE(DMUS_E_SCRIPT_VARIABLE_NOT_FOUND), + FE(DMUS_E_SCRIPT_ROUTINE_NOT_FOUND), + FE(DMUS_E_SCRIPT_CONTENT_READONLY), + FE(DMUS_E_SCRIPT_NOT_A_REFERENCE), + FE(DMUS_E_SCRIPT_VALUE_NOT_SUPPORTED), + FE(DMUS_E_INVALID_SEGMENTTRIGGERTRACK), + FE(DMUS_E_INVALID_LYRICSTRACK), + FE(DMUS_E_INVALID_PARAMCONTROLTRACK), + FE(DMUS_E_AUDIOVBSCRIPT_SYNTAXERROR), + FE(DMUS_E_AUDIOVBSCRIPT_RUNTIMEERROR), + FE(DMUS_E_AUDIOVBSCRIPT_OPERATIONFAILURE), + FE(DMUS_E_AUDIOPATHS_NOT_VALID), + FE(DMUS_E_AUDIOPATHS_IN_USE), + FE(DMUS_E_NO_AUDIOPATH_CONFIG), + FE(DMUS_E_AUDIOPATH_INACTIVE), + FE(DMUS_E_AUDIOPATH_NOBUFFER), + FE(DMUS_E_AUDIOPATH_NOPORT), + FE(DMUS_E_NO_AUDIOPATH), + FE(DMUS_E_INVALIDCHUNK), + FE(DMUS_E_AUDIOPATH_NOGLOBALFXBUFFER), + FE(DMUS_E_INVALID_CONTAINER_OBJECT) + }; + + unsigned int i; + for (i = 0; i < sizeof(codes)/sizeof(codes[0]); i++) { + if (code == codes[i].val) + return codes[i].name; + } + + /* if we didn't find it, return value */ + return wine_dbg_sprintf("0x%08lX", code); +} + + +/* generic flag-dumping function */ +const char* debugstr_flags (DWORD flags, const flag_info* names, size_t num_names){ + static char buffer[128] = "", *ptr = &buffer[0]; + unsigned int i, size = sizeof(buffer); + + for (i=0; i < num_names; i++) { + if ((flags & names[i].val)) { + int cnt = snprintf(ptr, size, "%s ", names[i].name); + if (cnt < 0 || cnt >= size) break; + size -= cnt; + ptr += cnt; + } + } + + ptr = &buffer[0]; + return ptr; +} + +/* dump DMUS_OBJ flags */ +const char *debugstr_DMUS_OBJ_FLAGS (DWORD flagmask) { + static const flag_info flags[] = { + FE(DMUS_OBJ_OBJECT), + FE(DMUS_OBJ_CLASS), + FE(DMUS_OBJ_NAME), + FE(DMUS_OBJ_CATEGORY), + FE(DMUS_OBJ_FILENAME), + FE(DMUS_OBJ_FULLPATH), + FE(DMUS_OBJ_URL), + FE(DMUS_OBJ_VERSION), + FE(DMUS_OBJ_DATE), + FE(DMUS_OBJ_LOADED), + FE(DMUS_OBJ_MEMORY), + FE(DMUS_OBJ_STREAM) + }; + return debugstr_flags (flagmask, flags, sizeof(flags)/sizeof(flags[0])); +} + +/* dump DMUS_CONTAINER flags */ +const char *debugstr_DMUS_CONTAINER_FLAGS (DWORD flagmask) { + static const flag_info flags[] = { + FE(DMUS_CONTAINER_NOLOADS) + }; + return debugstr_flags (flagmask, flags, sizeof(flags)/sizeof(flags[0])); +} + +/* dump DMUS_CONTAINED_OBJF flags */ +const char *debugstr_DMUS_CONTAINED_OBJF_FLAGS (DWORD flagmask) { + static const flag_info flags[] = { + FE(DMUS_CONTAINED_OBJF_KEEP) + }; + return debugstr_flags (flagmask, flags, sizeof(flags)/sizeof(flags[0])); +} + +const char *debugstr_DMUS_OBJECTDESC (LPDMUS_OBJECTDESC pDesc) { + if (pDesc) { + char buffer[1024] = "", *ptr = &buffer[0]; + + ptr += sprintf(ptr, "DMUS_OBJECTDESC (%p):\n", pDesc); + ptr += sprintf(ptr, " - dwSize = 0x%08lX\n", pDesc->dwSize); + ptr += sprintf(ptr, " - dwValidData = 0x%08lX ( %s)\n", pDesc->dwValidData, debugstr_DMUS_OBJ_FLAGS (pDesc->dwValidData)); + if (pDesc->dwValidData & DMUS_OBJ_CLASS) ptr += sprintf(ptr, " - guidClass = %s\n", debugstr_dmguid(&pDesc->guidClass)); + if (pDesc->dwValidData & DMUS_OBJ_OBJECT) ptr += sprintf(ptr, " - guidObject = %s\n", debugstr_guid(&pDesc->guidObject)); + if (pDesc->dwValidData & DMUS_OBJ_DATE) ptr += sprintf(ptr, " - ftDate = %s\n", debugstr_filetime (&pDesc->ftDate)); + if (pDesc->dwValidData & DMUS_OBJ_VERSION) ptr += sprintf(ptr, " - vVersion = %s\n", debugstr_dmversion(&pDesc->vVersion)); + if (pDesc->dwValidData & DMUS_OBJ_NAME) ptr += sprintf(ptr, " - wszName = %s\n", debugstr_w(pDesc->wszName)); + if (pDesc->dwValidData & DMUS_OBJ_CATEGORY) ptr += sprintf(ptr, " - wszCategory = %s\n", debugstr_w(pDesc->wszCategory)); + if (pDesc->dwValidData & DMUS_OBJ_FILENAME) ptr += sprintf(ptr, " - wszFileName = %s\n", debugstr_w(pDesc->wszFileName)); + if (pDesc->dwValidData & DMUS_OBJ_MEMORY) ptr += sprintf(ptr, " - llMemLength = %lli\n - pbMemData = %p\n", pDesc->llMemLength, pDesc->pbMemData); + if (pDesc->dwValidData & DMUS_OBJ_STREAM) ptr += sprintf(ptr, " - pStream = %p\n", pDesc->pStream); + + ptr = &buffer[0]; + return ptr; + } else { + return wine_dbg_sprintf("(NULL)"); + } +} + +const char *debugstr_DMUS_IO_CONTAINER_HEADER (LPDMUS_IO_CONTAINER_HEADER pHeader) { + if (pHeader) { + char buffer[1024] = "", *ptr = &buffer[0]; + + ptr += sprintf(ptr, "DMUS_IO_CONTAINER_HEADER (%p):\n", pHeader); + ptr += sprintf(ptr, " - dwFlags = %s\n", debugstr_DMUS_CONTAINER_FLAGS(pHeader->dwFlags)); + + ptr = &buffer[0]; + return ptr; + } else { + return wine_dbg_sprintf("(NULL)"); + } +} + +const char *debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER (LPDMUS_IO_CONTAINED_OBJECT_HEADER pHeader) { + if (pHeader) { + char buffer[1024] = "", *ptr = &buffer[0]; + + ptr += sprintf(ptr, "DMUS_IO_CONTAINED_OBJECT_HEADER (%p):\n", pHeader); + ptr += sprintf(ptr, " - guidClassID = %s\n", debugstr_dmguid(&pHeader->guidClassID)); + ptr += sprintf(ptr, " - dwFlags = %s\n", debugstr_DMUS_CONTAINED_OBJF_FLAGS (pHeader->dwFlags)); + ptr += sprintf(ptr, " - ckid = %s\n", debugstr_fourcc (pHeader->ckid)); + ptr += sprintf(ptr, " - fccType = %s\n", debugstr_fourcc (pHeader->fccType)); + + ptr = &buffer[0]; + return ptr; + } else { + return wine_dbg_sprintf("(NULL)"); + } +} diff --git a/dlls/dmloader/debug.h b/dlls/dmloader/debug.h new file mode 100644 index 00000000000..3535ea11ccd --- /dev/null +++ b/dlls/dmloader/debug.h @@ -0,0 +1,71 @@ +/* Debug and Helper Functions + * + * Copyright (C) 2003-2004 Rok Mandeljc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __WINE_DMLOADER_DEBUG_H +#define __WINE_DMLOADER_DEBUG_H + +/* used for generic dumping (copied from ddraw) */ +typedef struct { + DWORD val; + const char* name; +} flag_info; + +typedef struct { + const GUID *guid; + const char* name; +} guid_info; + +/* used for initialising structs */ +#define DM_STRUCT_INIT(x) \ + do { \ + memset((x), 0, sizeof(*(x))); \ + (x)->dwSize = sizeof(*x); \ + } while (0) + +#define FE(x) { x, #x } +#define GE(x) { &x, #x } + +/* check whether the given DWORD is even (return 0) or odd (return 1) */ +extern int even_or_odd (DWORD number); +/* check whether chunkID is valid dmobject form chunk */ +extern BOOL IS_VALID_DMFORM (FOURCC chunkID); +/* translate STREAM_SEEK flag to string */ +extern const char *resolve_STREAM_SEEK (DWORD flag); +/* FOURCC to string conversion for debug messages */ +extern const char *debugstr_fourcc (DWORD fourcc); +/* DMUS_VERSION struct to string conversion for debug messages */ +extern const char *debugstr_dmversion (LPDMUS_VERSION version); +/* FILETIME struct to string conversion for debug messages */ +extern const char *debugstr_filetime (LPFILETIME time); +/* returns name of given GUID */ +extern const char *debugstr_dmguid (const GUID *id); +/* returns name of given error code */ +extern const char *debugstr_dmreturn (DWORD code); +/* generic flags-dumping function */ +extern const char *debugstr_flags (DWORD flags, const flag_info* names, size_t num_names); + +extern const char *debugstr_DMUS_OBJ_FLAGS (DWORD flagmask); +extern const char *debugstr_DMUS_CONTAINER_FLAGS (DWORD flagmask); +extern const char *debugstr_DMUS_CONTAINED_OBJF_FLAGS (DWORD flagmask); +/* dump whole DMUS_OBJECTDESC struct */ +extern const char *debugstr_DMUS_OBJECTDESC (LPDMUS_OBJECTDESC pDesc); +extern const char *debugstr_DMUS_IO_CONTAINER_HEADER (LPDMUS_IO_CONTAINER_HEADER pHeader); +extern const char *debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER (LPDMUS_IO_CONTAINED_OBJECT_HEADER pHeader); + +#endif /* __WINE_DMLOADER_DEBUG_H */ diff --git a/dlls/dmloader/dmloader_main.c b/dlls/dmloader/dmloader_main.c index a7fe5307137..68aba69b848 100644 --- a/dlls/dmloader/dmloader_main.c +++ b/dlls/dmloader/dmloader_main.c @@ -21,109 +21,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); -typedef struct { - /* IUnknown fields */ - ICOM_VFIELD(IClassFactory); - DWORD ref; -} IClassFactoryImpl; - -/****************************************************************** - * DirectMusicLoader ClassFactory - */ -static HRESULT WINAPI LoaderCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - ICOM_THIS(IClassFactoryImpl,iface); - FIXME("(%p, %s, %p): stub\n", This, debugstr_dmguid(riid), ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI LoaderCF_AddRef(LPCLASSFACTORY iface) { - ICOM_THIS(IClassFactoryImpl,iface); - return ++(This->ref); -} - -static ULONG WINAPI LoaderCF_Release(LPCLASSFACTORY iface) { - ICOM_THIS(IClassFactoryImpl,iface); - /* static class, won't be freed */ - return --(This->ref); -} - -static HRESULT WINAPI LoaderCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { - ICOM_THIS(IClassFactoryImpl,iface); - TRACE ("(%p, %p, %s, %p)\n", This, pOuter, debugstr_dmguid(riid), ppobj); - return DMUSIC_CreateDirectMusicLoaderImpl (riid, (LPVOID*) ppobj, pOuter); -} - -static HRESULT WINAPI LoaderCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - ICOM_THIS(IClassFactoryImpl,iface); - FIXME("(%p, %d): stub\n", This, dolock); - return S_OK; -} - -static ICOM_VTABLE(IClassFactory) LoaderCF_Vtbl = { - ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - LoaderCF_QueryInterface, - LoaderCF_AddRef, - LoaderCF_Release, - LoaderCF_CreateInstance, - LoaderCF_LockServer -}; - -static IClassFactoryImpl Loader_CF = {&LoaderCF_Vtbl, 1 }; - -/****************************************************************** - * DirectMusicContainer ClassFactory - */ -static HRESULT WINAPI ContainerCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - ICOM_THIS(IClassFactoryImpl,iface); - FIXME("(%p, %s, %p): stub\n", This, debugstr_dmguid(riid), ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI ContainerCF_AddRef(LPCLASSFACTORY iface) { - ICOM_THIS(IClassFactoryImpl,iface); - return ++(This->ref); -} - -static ULONG WINAPI ContainerCF_Release(LPCLASSFACTORY iface) { - ICOM_THIS(IClassFactoryImpl,iface); - /* static class, won't be freed */ - return --(This->ref); -} - -static HRESULT WINAPI ContainerCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { - ICOM_THIS(IClassFactoryImpl,iface); - TRACE ("(%p, %p, %s, %p)\n", This, pOuter, debugstr_dmguid(riid), ppobj); - return DMUSIC_CreateDirectMusicContainerImpl (riid, (LPVOID*) ppobj, pOuter); -} - -static HRESULT WINAPI ContainerCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - ICOM_THIS(IClassFactoryImpl,iface); - FIXME("(%p, %d): stub!\n", This, dolock); - return S_OK; -} - -static ICOM_VTABLE(IClassFactory) ContainerCF_Vtbl = { - ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - ContainerCF_QueryInterface, - ContainerCF_AddRef, - ContainerCF_Release, - ContainerCF_CreateInstance, - ContainerCF_LockServer -}; - -static IClassFactoryImpl Container_CF = {&ContainerCF_Vtbl, 1 }; +DWORD dwDirectMusicContainer = 0; +DWORD dwDirectMusicLoader = 0; /****************************************************************** * DllMain - * - * */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) { - DisableThreadLibraryCalls(hinstDLL); + DisableThreadLibraryCalls(hinstDLL); /* FIXME: Initialisation */ - } - else if (fdwReason == DLL_PROCESS_DETACH) { + } else if (fdwReason == DLL_PROCESS_DETACH) { /* FIXME: Cleanup */ } return TRUE; @@ -132,463 +40,28 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { /****************************************************************** * DllCanUnloadNow (DMLOADER.1) - * - * */ -HRESULT WINAPI DMLOADER_DllCanUnloadNow(void) { - FIXME("(void): stub\n"); - return S_FALSE; +HRESULT WINAPI DMLOADER_DllCanUnloadNow (void) { + TRACE("(void)\n"); + /* if there are no instances left, it's safe to release */ + if (!dwDirectMusicContainer && !dwDirectMusicLoader) + return S_OK; + else + return S_FALSE; } /****************************************************************** * DllGetClassObject (DMLOADER.2) - * - * */ -HRESULT WINAPI DMLOADER_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { +HRESULT WINAPI DMLOADER_DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID *ppv) { TRACE("(%s, %s, %p)\n", debugstr_dmguid(rclsid), debugstr_dmguid(riid), ppv); if (IsEqualCLSID (rclsid, &CLSID_DirectMusicLoader) && IsEqualIID (riid, &IID_IClassFactory)) { - *ppv = (LPVOID) &Loader_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; + return DMUSIC_CreateDirectMusicLoaderCF (riid, ppv, NULL); } else if (IsEqualCLSID (rclsid, &CLSID_DirectMusicContainer) && IsEqualIID (riid, &IID_IClassFactory)) { - *ppv = (LPVOID) &Container_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; + return DMUSIC_CreateDirectMusicContainerCF (riid, ppv, NULL); } - WARN("(%s, %s, %p): no interface found.\n", debugstr_dmguid(rclsid), debugstr_dmguid(riid), ppv); + WARN(": no class found\n"); return CLASS_E_CLASSNOTAVAILABLE; } - -/****************************************************************** - * Helper functions - * - * - */ -/* check whether the given DWORD is even (return 0) or odd (return 1) */ -int even_or_odd (DWORD number) { - return (number & 0x1); /* basically, check if bit 0 is set ;) */ -} - -/* translate STREAM_SEEK flag to string */ -const char *resolve_STREAM_SEEK (DWORD flag) { - switch (flag) { - case STREAM_SEEK_SET: - return wine_dbg_sprintf ("STREAM_SEEK_SET"); - case STREAM_SEEK_CUR: - return wine_dbg_sprintf ("STREAM_SEEK_CUR"); - case STREAM_SEEK_END: - return wine_dbg_sprintf ("STREAM_SEEK_END"); - default: - return wine_dbg_sprintf ("()"); - } -} - -/* FOURCC to string conversion for debug messages */ -const char *debugstr_fourcc (DWORD fourcc) { - if (!fourcc) return "'null'"; - return wine_dbg_sprintf ("\'%c%c%c%c\'", - (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} - -/* DMUS_VERSION struct to string conversion for debug messages */ -const char *debugstr_dmversion (LPDMUS_VERSION version) { - if (!version) return "'null'"; - return wine_dbg_sprintf ("\'%i,%i,%i,%i\'", - (int)((version->dwVersionMS && 0xFFFF0000) >> 8), (int)(version->dwVersionMS && 0x0000FFFF), - (int)((version->dwVersionLS && 0xFFFF0000) >> 8), (int)(version->dwVersionLS && 0x0000FFFF)); -} - -/* returns name of given GUID */ -const char *debugstr_dmguid (const GUID *id) { - static const guid_info guids[] = { - /* CLSIDs */ - GE(CLSID_AudioVBScript), - GE(CLSID_DirectMusic), - GE(CLSID_DirectMusicAudioPath), - GE(CLSID_DirectMusicAudioPathConfig), - GE(CLSID_DirectMusicAuditionTrack), - GE(CLSID_DirectMusicBand), - GE(CLSID_DirectMusicBandTrack), - GE(CLSID_DirectMusicChordMapTrack), - GE(CLSID_DirectMusicChordMap), - GE(CLSID_DirectMusicChordTrack), - GE(CLSID_DirectMusicCollection), - GE(CLSID_DirectMusicCommandTrack), - GE(CLSID_DirectMusicComposer), - GE(CLSID_DirectMusicContainer), - GE(CLSID_DirectMusicGraph), - GE(CLSID_DirectMusicLoader), - GE(CLSID_DirectMusicLyricsTrack), - GE(CLSID_DirectMusicMarkerTrack), - GE(CLSID_DirectMusicMelodyFormulationTrack), - GE(CLSID_DirectMusicMotifTrack), - GE(CLSID_DirectMusicMuteTrack), - GE(CLSID_DirectMusicParamControlTrack), - GE(CLSID_DirectMusicPatternTrack), - GE(CLSID_DirectMusicPerformance), - GE(CLSID_DirectMusicScript), - GE(CLSID_DirectMusicScriptAutoImpSegment), - GE(CLSID_DirectMusicScriptAutoImpPerformance), - GE(CLSID_DirectMusicScriptAutoImpSegmentState), - GE(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - GE(CLSID_DirectMusicScriptAutoImpAudioPath), - GE(CLSID_DirectMusicScriptAutoImpSong), - GE(CLSID_DirectMusicScriptSourceCodeLoader), - GE(CLSID_DirectMusicScriptTrack), - GE(CLSID_DirectMusicSection), - GE(CLSID_DirectMusicSegment), - GE(CLSID_DirectMusicSegmentState), - GE(CLSID_DirectMusicSegmentTriggerTrack), - GE(CLSID_DirectMusicSegTriggerTrack), - GE(CLSID_DirectMusicSeqTrack), - GE(CLSID_DirectMusicSignPostTrack), - GE(CLSID_DirectMusicSong), - GE(CLSID_DirectMusicStyle), - GE(CLSID_DirectMusicStyleTrack), - GE(CLSID_DirectMusicSynth), - GE(CLSID_DirectMusicSynthSink), - GE(CLSID_DirectMusicSysExTrack), - GE(CLSID_DirectMusicTemplate), - GE(CLSID_DirectMusicTempoTrack), - GE(CLSID_DirectMusicTimeSigTrack), - GE(CLSID_DirectMusicWaveTrack), - GE(CLSID_DirectSoundWave), - /* IIDs */ - GE(IID_IDirectMusic), - GE(IID_IDirectMusic2), - GE(IID_IDirectMusic8), - GE(IID_IDirectMusicAudioPath), - GE(IID_IDirectMusicBand), - GE(IID_IDirectMusicBuffer), - GE(IID_IDirectMusicChordMap), - GE(IID_IDirectMusicCollection), - GE(IID_IDirectMusicComposer), - GE(IID_IDirectMusicContainer), - GE(IID_IDirectMusicDownload), - GE(IID_IDirectMusicDownloadedInstrument), - GE(IID_IDirectMusicGetLoader), - GE(IID_IDirectMusicGraph), - GE(IID_IDirectMusicInstrument), - GE(IID_IDirectMusicLoader), - GE(IID_IDirectMusicLoader8), - GE(IID_IDirectMusicObject), - GE(IID_IDirectMusicPatternTrack), - GE(IID_IDirectMusicPerformance), - GE(IID_IDirectMusicPerformance2), - GE(IID_IDirectMusicPerformance8), - GE(IID_IDirectMusicPort), - GE(IID_IDirectMusicPortDownload), - GE(IID_IDirectMusicScript), - GE(IID_IDirectMusicSegment), - GE(IID_IDirectMusicSegment2), - GE(IID_IDirectMusicSegment8), - GE(IID_IDirectMusicSegmentState), - GE(IID_IDirectMusicSegmentState8), - GE(IID_IDirectMusicStyle), - GE(IID_IDirectMusicStyle8), - GE(IID_IDirectMusicSynth), - GE(IID_IDirectMusicSynth8), - GE(IID_IDirectMusicSynthSink), - GE(IID_IDirectMusicThru), - GE(IID_IDirectMusicTool), - GE(IID_IDirectMusicTool8), - GE(IID_IDirectMusicTrack), - GE(IID_IDirectMusicTrack8), - GE(IID_IUnknown), - GE(IID_IPersistStream), - GE(IID_IStream), - GE(IID_IClassFactory), - /* GUIDs */ - GE(GUID_DirectMusicAllTypes), - GE(GUID_NOTIFICATION_CHORD), - GE(GUID_NOTIFICATION_COMMAND), - GE(GUID_NOTIFICATION_MEASUREANDBEAT), - GE(GUID_NOTIFICATION_PERFORMANCE), - GE(GUID_NOTIFICATION_RECOMPOSE), - GE(GUID_NOTIFICATION_SEGMENT), - GE(GUID_BandParam), - GE(GUID_ChordParam), - GE(GUID_CommandParam), - GE(GUID_CommandParam2), - GE(GUID_CommandParamNext), - GE(GUID_IDirectMusicBand), - GE(GUID_IDirectMusicChordMap), - GE(GUID_IDirectMusicStyle), - GE(GUID_MuteParam), - GE(GUID_Play_Marker), - GE(GUID_RhythmParam), - GE(GUID_TempoParam), - GE(GUID_TimeSignature), - GE(GUID_Valid_Start_Time), - GE(GUID_Clear_All_Bands), - GE(GUID_ConnectToDLSCollection), - GE(GUID_Disable_Auto_Download), - GE(GUID_DisableTempo), - GE(GUID_DisableTimeSig), - GE(GUID_Download), - GE(GUID_DownloadToAudioPath), - GE(GUID_Enable_Auto_Download), - GE(GUID_EnableTempo), - GE(GUID_EnableTimeSig), - GE(GUID_IgnoreBankSelectForGM), - GE(GUID_SeedVariations), - GE(GUID_StandardMIDIFile), - GE(GUID_Unload), - GE(GUID_UnloadFromAudioPath), - GE(GUID_Variations), - GE(GUID_PerfMasterTempo), - GE(GUID_PerfMasterVolume), - GE(GUID_PerfMasterGrooveLevel), - GE(GUID_PerfAutoDownload), - GE(GUID_DefaultGMCollection), - GE(GUID_Synth_Default), - GE(GUID_Buffer_Reverb), - GE(GUID_Buffer_EnvReverb), - GE(GUID_Buffer_Stereo), - GE(GUID_Buffer_3D_Dry), - GE(GUID_Buffer_Mono), - GE(GUID_DMUS_PROP_GM_Hardware), - GE(GUID_DMUS_PROP_GS_Capable), - GE(GUID_DMUS_PROP_GS_Hardware), - GE(GUID_DMUS_PROP_DLS1), - GE(GUID_DMUS_PROP_DLS2), - GE(GUID_DMUS_PROP_Effects), - GE(GUID_DMUS_PROP_INSTRUMENT2), - GE(GUID_DMUS_PROP_LegacyCaps), - GE(GUID_DMUS_PROP_MemorySize), - GE(GUID_DMUS_PROP_SampleMemorySize), - GE(GUID_DMUS_PROP_SamplePlaybackRate), - GE(GUID_DMUS_PROP_SetSynthSink), - GE(GUID_DMUS_PROP_SinkUsesDSound), - GE(GUID_DMUS_PROP_SynthSink_DSOUND), - GE(GUID_DMUS_PROP_SynthSink_WAVE), - GE(GUID_DMUS_PROP_Volume), - GE(GUID_DMUS_PROP_WavesReverb), - GE(GUID_DMUS_PROP_WriteLatency), - GE(GUID_DMUS_PROP_WritePeriod), - GE(GUID_DMUS_PROP_XG_Capable), - GE(GUID_DMUS_PROP_XG_Hardware) - }; - - unsigned int i; - - if (!id) return "(null)"; - - for (i = 0; i < sizeof(guids)/sizeof(guids[0]); i++) { - if (IsEqualGUID(id, &guids[i].guid)) - return guids[i].name; - } - /* if we didn't find it, act like standard debugstr_guid */ - return debugstr_guid(id); -} - -/* returns name of given error code */ -const char *debugstr_dmreturn (DWORD code) { - static const flag_info codes[] = { - FE(S_OK), - FE(S_FALSE), - FE(DMUS_S_PARTIALLOAD), - FE(DMUS_S_PARTIALDOWNLOAD), - FE(DMUS_S_REQUEUE), - FE(DMUS_S_FREE), - FE(DMUS_S_END), - FE(DMUS_S_STRING_TRUNCATED), - FE(DMUS_S_LAST_TOOL), - FE(DMUS_S_OVER_CHORD), - FE(DMUS_S_UP_OCTAVE), - FE(DMUS_S_DOWN_OCTAVE), - FE(DMUS_S_NOBUFFERCONTROL), - FE(DMUS_S_GARBAGE_COLLECTED), - FE(DMUS_E_DRIVER_FAILED), - FE(DMUS_E_PORTS_OPEN), - FE(DMUS_E_DEVICE_IN_USE), - FE(DMUS_E_INSUFFICIENTBUFFER), - FE(DMUS_E_BUFFERNOTSET), - FE(DMUS_E_BUFFERNOTAVAILABLE), - FE(DMUS_E_NOTADLSCOL), - FE(DMUS_E_INVALIDOFFSET), - FE(DMUS_E_ALREADY_LOADED), - FE(DMUS_E_INVALIDPOS), - FE(DMUS_E_INVALIDPATCH), - FE(DMUS_E_CANNOTSEEK), - FE(DMUS_E_CANNOTWRITE), - FE(DMUS_E_CHUNKNOTFOUND), - FE(DMUS_E_INVALID_DOWNLOADID), - FE(DMUS_E_NOT_DOWNLOADED_TO_PORT), - FE(DMUS_E_ALREADY_DOWNLOADED), - FE(DMUS_E_UNKNOWN_PROPERTY), - FE(DMUS_E_SET_UNSUPPORTED), - FE(DMUS_E_GET_UNSUPPORTED), - FE(DMUS_E_NOTMONO), - FE(DMUS_E_BADARTICULATION), - FE(DMUS_E_BADINSTRUMENT), - FE(DMUS_E_BADWAVELINK), - FE(DMUS_E_NOARTICULATION), - FE(DMUS_E_NOTPCM), - FE(DMUS_E_BADWAVE), - FE(DMUS_E_BADOFFSETTABLE), - FE(DMUS_E_UNKNOWNDOWNLOAD), - FE(DMUS_E_NOSYNTHSINK), - FE(DMUS_E_ALREADYOPEN), - FE(DMUS_E_ALREADYCLOSED), - FE(DMUS_E_SYNTHNOTCONFIGURED), - FE(DMUS_E_SYNTHACTIVE), - FE(DMUS_E_CANNOTREAD), - FE(DMUS_E_DMUSIC_RELEASED), - FE(DMUS_E_BUFFER_EMPTY), - FE(DMUS_E_BUFFER_FULL), - FE(DMUS_E_PORT_NOT_CAPTURE), - FE(DMUS_E_PORT_NOT_RENDER), - FE(DMUS_E_DSOUND_NOT_SET), - FE(DMUS_E_ALREADY_ACTIVATED), - FE(DMUS_E_INVALIDBUFFER), - FE(DMUS_E_WAVEFORMATNOTSUPPORTED), - FE(DMUS_E_SYNTHINACTIVE), - FE(DMUS_E_DSOUND_ALREADY_SET), - FE(DMUS_E_INVALID_EVENT), - FE(DMUS_E_UNSUPPORTED_STREAM), - FE(DMUS_E_ALREADY_INITED), - FE(DMUS_E_INVALID_BAND), - FE(DMUS_E_TRACK_HDR_NOT_FIRST_CK), - FE(DMUS_E_TOOL_HDR_NOT_FIRST_CK), - FE(DMUS_E_INVALID_TRACK_HDR), - FE(DMUS_E_INVALID_TOOL_HDR), - FE(DMUS_E_ALL_TOOLS_FAILED), - FE(DMUS_E_ALL_TRACKS_FAILED), - FE(DMUS_E_NOT_FOUND), - FE(DMUS_E_NOT_INIT), - FE(DMUS_E_TYPE_DISABLED), - FE(DMUS_E_TYPE_UNSUPPORTED), - FE(DMUS_E_TIME_PAST), - FE(DMUS_E_TRACK_NOT_FOUND), - FE(DMUS_E_TRACK_NO_CLOCKTIME_SUPPORT), - FE(DMUS_E_NO_MASTER_CLOCK), - FE(DMUS_E_LOADER_NOCLASSID), - FE(DMUS_E_LOADER_BADPATH), - FE(DMUS_E_LOADER_FAILEDOPEN), - FE(DMUS_E_LOADER_FORMATNOTSUPPORTED), - FE(DMUS_E_LOADER_FAILEDCREATE), - FE(DMUS_E_LOADER_OBJECTNOTFOUND), - FE(DMUS_E_LOADER_NOFILENAME), - FE(DMUS_E_INVALIDFILE), - FE(DMUS_E_ALREADY_EXISTS), - FE(DMUS_E_OUT_OF_RANGE), - FE(DMUS_E_SEGMENT_INIT_FAILED), - FE(DMUS_E_ALREADY_SENT), - FE(DMUS_E_CANNOT_FREE), - FE(DMUS_E_CANNOT_OPEN_PORT), - FE(DMUS_E_CANNOT_CONVERT), - FE(DMUS_E_DESCEND_CHUNK_FAIL), - FE(DMUS_E_NOT_LOADED), - FE(DMUS_E_SCRIPT_LANGUAGE_INCOMPATIBLE), - FE(DMUS_E_SCRIPT_UNSUPPORTED_VARTYPE), - FE(DMUS_E_SCRIPT_ERROR_IN_SCRIPT), - FE(DMUS_E_SCRIPT_CANTLOAD_OLEAUT32), - FE(DMUS_E_SCRIPT_LOADSCRIPT_ERROR), - FE(DMUS_E_SCRIPT_INVALID_FILE), - FE(DMUS_E_INVALID_SCRIPTTRACK), - FE(DMUS_E_SCRIPT_VARIABLE_NOT_FOUND), - FE(DMUS_E_SCRIPT_ROUTINE_NOT_FOUND), - FE(DMUS_E_SCRIPT_CONTENT_READONLY), - FE(DMUS_E_SCRIPT_NOT_A_REFERENCE), - FE(DMUS_E_SCRIPT_VALUE_NOT_SUPPORTED), - FE(DMUS_E_INVALID_SEGMENTTRIGGERTRACK), - FE(DMUS_E_INVALID_LYRICSTRACK), - FE(DMUS_E_INVALID_PARAMCONTROLTRACK), - FE(DMUS_E_AUDIOVBSCRIPT_SYNTAXERROR), - FE(DMUS_E_AUDIOVBSCRIPT_RUNTIMEERROR), - FE(DMUS_E_AUDIOVBSCRIPT_OPERATIONFAILURE), - FE(DMUS_E_AUDIOPATHS_NOT_VALID), - FE(DMUS_E_AUDIOPATHS_IN_USE), - FE(DMUS_E_NO_AUDIOPATH_CONFIG), - FE(DMUS_E_AUDIOPATH_INACTIVE), - FE(DMUS_E_AUDIOPATH_NOBUFFER), - FE(DMUS_E_AUDIOPATH_NOPORT), - FE(DMUS_E_NO_AUDIOPATH), - FE(DMUS_E_INVALIDCHUNK), - FE(DMUS_E_AUDIOPATH_NOGLOBALFXBUFFER), - FE(DMUS_E_INVALID_CONTAINER_OBJECT) - }; - unsigned int i; - for (i = 0; i < sizeof(codes)/sizeof(codes[0]); i++) { - if (code == codes[i].val) - return codes[i].name; - } - /* if we didn't find it, return value */ - return wine_dbg_sprintf("0x%08lx", code); -} - -/* generic flag-dumping function */ -const char* debugstr_flags (DWORD flags, const flag_info* names, size_t num_names){ - char buffer[128] = "", *ptr = &buffer[0]; - unsigned int i, size = sizeof(buffer); - - for (i=0; i < num_names; i++) - { - if ((flags & names[i].val) || /* standard flag*/ - ((!flags) && (!names[i].val))) { /* zero value only */ - int cnt = snprintf(ptr, size, "%s ", names[i].name); - if (cnt < 0 || cnt >= size) break; - size -= cnt; - ptr += cnt; - } - } - - return wine_dbg_sprintf("%s", buffer); -} - -/* dump DMUS_OBJ flags */ -const char *debugstr_DMUS_OBJ_FLAGS (DWORD flagmask) { - static const flag_info flags[] = { - FE(DMUS_OBJ_OBJECT), - FE(DMUS_OBJ_CLASS), - FE(DMUS_OBJ_NAME), - FE(DMUS_OBJ_CATEGORY), - FE(DMUS_OBJ_FILENAME), - FE(DMUS_OBJ_FULLPATH), - FE(DMUS_OBJ_URL), - FE(DMUS_OBJ_VERSION), - FE(DMUS_OBJ_DATE), - FE(DMUS_OBJ_LOADED), - FE(DMUS_OBJ_MEMORY), - FE(DMUS_OBJ_STREAM) - }; - return debugstr_flags (flagmask, flags, sizeof(flags)/sizeof(flags[0])); -} - -/* dump whole DMUS_OBJECTDESC struct */ -const char *debugstr_DMUS_OBJECTDESC (LPDMUS_OBJECTDESC pDesc) { - if (pDesc) { - char buffer[1024] = "", *ptr = &buffer[0]; - - ptr += sprintf(ptr, "DMUS_OBJECTDESC (%p):\n", pDesc); - ptr += sprintf(ptr, " - dwSize = %ld\n", pDesc->dwSize); - ptr += sprintf(ptr, " - dwValidData = %s\n", debugstr_DMUS_OBJ_FLAGS (pDesc->dwValidData)); - if (pDesc->dwValidData & DMUS_OBJ_CLASS) ptr += sprintf(ptr, " - guidClass = %s\n", debugstr_dmguid(&pDesc->guidClass)); - if (pDesc->dwValidData & DMUS_OBJ_OBJECT) ptr += sprintf(ptr, " - guidObject = %s\n", debugstr_guid(&pDesc->guidObject)); - if (pDesc->dwValidData & DMUS_OBJ_DATE) ptr += sprintf(ptr, " - ftDate = FIXME\n"); - if (pDesc->dwValidData & DMUS_OBJ_VERSION) ptr += sprintf(ptr, " - vVersion = %s\n", debugstr_dmversion(&pDesc->vVersion)); - if (pDesc->dwValidData & DMUS_OBJ_NAME) ptr += sprintf(ptr, " - wszName = %s\n", debugstr_w(pDesc->wszName)); - if (pDesc->dwValidData & DMUS_OBJ_CATEGORY) ptr += sprintf(ptr, " - wszCategory = %s\n", debugstr_w(pDesc->wszCategory)); - if (pDesc->dwValidData & DMUS_OBJ_FILENAME) ptr += sprintf(ptr, " - wszFileName = %s\n", debugstr_w(pDesc->wszFileName)); - if (pDesc->dwValidData & DMUS_OBJ_MEMORY) ptr += sprintf(ptr, " - llMemLength = %lli\n - pbMemData = %p\n", pDesc->llMemLength, pDesc->pbMemData); - if (pDesc->dwValidData & DMUS_OBJ_STREAM) ptr += sprintf(ptr, " - pStream = %p", pDesc->pStream); - - return wine_dbg_sprintf("%s", buffer); - } else { - return wine_dbg_sprintf("(NULL)"); - } -} - -/* figures out whether given FOURCC is valid DirectMusic form ID */ -BOOL IS_VALID_DMFORM (FOURCC chunkID) { - if ((chunkID == DMUS_FOURCC_AUDIOPATH_FORM) || (chunkID == DMUS_FOURCC_BAND_FORM) || (chunkID == DMUS_FOURCC_CHORDMAP_FORM) - || (chunkID == DMUS_FOURCC_CONTAINER_FORM) || (chunkID == FOURCC_DLS) || (chunkID == DMUS_FOURCC_SCRIPT_FORM) - || (chunkID == DMUS_FOURCC_SEGMENT_FORM) || (chunkID == DMUS_FOURCC_STYLE_FORM) || (chunkID == DMUS_FOURCC_TOOLGRAPH_FORM) - || (chunkID == DMUS_FOURCC_TRACK_FORM) || (chunkID == mmioFOURCC('W','A','V','E'))) return TRUE; - else return FALSE; -} diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index bf7dfd0fdac..4e284c3f9cc 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -39,118 +39,179 @@ #include "dmusicf.h" #include "dmusics.h" -/***************************************************************************** - * Auxiliary definitions - */ -/* cache entry */ -typedef struct _DMUS_PRIVATE_CACHE_ENTRY { - struct list entry; /* for listing elements */ - BOOL bIsFaultyDLS; /* my workaround for enabling caching of "faulty" dls collections */ - LPDIRECTMUSICOBJECT pObject; /* pointer to object */ -} DMUS_PRIVATE_CACHE_ENTRY, *LPDMUS_PRIVATE_CACHE_ENTRY; - -/* alias entry */ -typedef struct _DMUS_PRIVATE_ALIAS_ENTRY { - struct list entry; /* for listing elements */ - LPDMUS_OBJECTDESC pDesc; /* descriptor, containing info */ -} DMUS_PRIVATE_ALIAS_ENTRY, *LPDMUS_PRIVATE_ALIAS_ENTRY; - -/* contained object entry */ -typedef struct _DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY { - struct list entry; /* for listing elements */ - WCHAR* wszAlias; - LPDMUS_OBJECTDESC pDesc; -} DMUS_PRIVATE_CONTAINED_OBJECT_ENTRY, *LPDMUS_PRIVATE_CONTAINED_OBJECT_ENTRY; +/* dmloader.dll global (for DllCanUnloadNow) */ +extern DWORD dwDirectMusicLoader; /* number of DirectMusicLoader(CF) instances */ +extern DWORD dwDirectMusicContainer; /* number of DirectMusicContainer(CF) instances */ /***************************************************************************** * Interfaces */ -typedef struct IDirectMusicLoader8Impl IDirectMusicLoader8Impl; -typedef struct IDirectMusicContainerImpl IDirectMusicContainerImpl; +typedef struct IDirectMusicLoaderCF IDirectMusicLoaderCF; +typedef struct IDirectMusicContainerCF IDirectMusicContainerCF; -typedef struct ILoaderStream ILoaderStream; +typedef struct IDirectMusicLoaderImpl IDirectMusicLoaderImpl; +typedef struct IDirectMusicContainerImpl IDirectMusicContainerImpl; + +typedef struct IDirectMusicLoaderFileStream IDirectMusicLoaderFileStream; +typedef struct IDirectMusicLoaderResourceStream IDirectMusicLoaderResourceStream; +typedef struct IDirectMusicLoaderGenericStream IDirectMusicLoaderGenericStream; + /***************************************************************************** * Predeclare the interface implementation structures */ -extern ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader8_Vtbl; +extern ICOM_VTABLE(IClassFactory) DirectMusicLoaderCF_Vtbl; +extern ICOM_VTABLE(IClassFactory) DirectMusicContainerCF_Vtbl; + +extern ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader_Loader_Vtbl; -extern ICOM_VTABLE(IUnknown) DirectMusicContainer_Unknown_Vtbl; extern ICOM_VTABLE(IDirectMusicContainer) DirectMusicContainer_Container_Vtbl; -extern ICOM_VTABLE(IDirectMusicObject) DirectMusicContainer_Object_Vtbl; -extern ICOM_VTABLE(IPersistStream) DirectMusicContainer_PersistStream_Vtbl; +extern ICOM_VTABLE(IDirectMusicObject) DirectMusicContainer_Object_Vtbl; +extern ICOM_VTABLE(IPersistStream) DirectMusicContainer_PersistStream_Vtbl; -extern ICOM_VTABLE(IUnknown) LoaderStream_Unknown_Vtbl; -extern ICOM_VTABLE(IStream) LoaderStream_Stream_Vtbl; -extern ICOM_VTABLE(IDirectMusicGetLoader) LoaderStream_GetLoader_Vtbl; +extern ICOM_VTABLE(IStream) DirectMusicLoaderFileStream_Stream_Vtbl; +extern ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderFileStream_GetLoader_Vtbl; + +extern ICOM_VTABLE(IStream) DirectMusicLoaderResourceStream_Stream_Vtbl; +extern ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderResourceStream_GetLoader_Vtbl; + +extern ICOM_VTABLE(IStream) DirectMusicLoaderGenericStream_Stream_Vtbl; +extern ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderGenericStream_GetLoader_Vtbl; /***************************************************************************** - * ClassFactory + * Creation helpers */ +extern HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderCF (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DMUSIC_CreateDirectMusicContainerCF (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter); + extern HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderImpl (LPDIRECTMUSICLOADER8 iface); extern HRESULT WINAPI DMUSIC_CreateDirectMusicContainerImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DMUSIC_DestroyDirectMusicContainerImpl(LPDIRECTMUSICCONTAINER iface); -extern HRESULT WINAPI DMUSIC_CreateLoaderStream (LPVOID *ppobj); +extern HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderFileStream (LPVOID *ppobj); +extern HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderFileStream (LPSTREAM iface); + +extern HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderResourceStream (LPVOID *ppobj); +extern HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderResourceStream (LPSTREAM iface); + +extern HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderGenericStream (LPVOID *ppobj); +extern HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderGenericStream (LPSTREAM iface); /***************************************************************************** - * IDirectMusicLoader8Impl implementation structure + * IDirectMusicLoaderCF implementation structure */ -struct IDirectMusicLoader8Impl { - /* IUnknown fields */ - ICOM_VFIELD(IDirectMusicLoader8); - DWORD ref; - - /* IDirectMusicLoaderImpl fields */ - WCHAR wzSearchPath[MAX_PATH]; - - /* simple cache (linked list) */ - struct list CacheList; - struct list AliasList; +struct IDirectMusicLoaderCF { + /* IUnknown fields */ + ICOM_VFIELD(IClassFactory); + DWORD dwRef; }; -/* IUnknown: */ -extern HRESULT WINAPI IDirectMusicLoader8Impl_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj); -extern ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface); -extern ULONG WINAPI IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface); -/* IDirectMusicLoader: */ -extern HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID*ppv); -extern HRESULT WINAPI IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc); -extern HRESULT WINAPI IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear); -extern HRESULT WINAPI IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName); -extern HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject); -extern HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject); -extern HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass); -extern HRESULT WINAPI IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable); -extern HRESULT WINAPI IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc); -/* IDirectMusicLoader8: */ -extern void WINAPI IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface); -extern HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject); -extern HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject); +/* IUnknown / IClassFactory: */ +extern HRESULT WINAPI IDirectMusicLoaderCF_QueryInterface (LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj); +extern ULONG WINAPI IDirectMusicLoaderCF_AddRef (LPCLASSFACTORY iface); +extern ULONG WINAPI IDirectMusicLoaderCF_Release (LPCLASSFACTORY iface); +extern HRESULT WINAPI IDirectMusicLoaderCF_CreateInstance (LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj); +extern HRESULT WINAPI IDirectMusicLoaderCF_LockServer (LPCLASSFACTORY iface,BOOL dolock); + + +/***************************************************************************** + * IDirectMusicContainerCF implementation structure + */ +struct IDirectMusicContainerCF { + /* IUnknown fields */ + ICOM_VFIELD(IClassFactory); + DWORD dwRef; +}; + +/* IUnknown / IClassFactory: */ +extern HRESULT WINAPI IDirectMusicContainerCF_QueryInterface (LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj); +extern ULONG WINAPI IDirectMusicContainerCF_AddRef (LPCLASSFACTORY iface); +extern ULONG WINAPI IDirectMusicContainerCF_Release (LPCLASSFACTORY iface); +extern HRESULT WINAPI IDirectMusicContainerCF_CreateInstance (LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj); +extern HRESULT WINAPI IDirectMusicContainerCF_LockServer (LPCLASSFACTORY iface,BOOL dolock); + + +/* cache/alias entry */ +typedef struct _WINE_LOADER_ENTRY { + struct list entry; /* for listing elements */ + DMUS_OBJECTDESC Desc; + LPDIRECTMUSICOBJECT pObject; /* pointer to object */ + BOOL bInvalidDefaultDLS; /* my workaround for enabling caching of "faulty" default dls collection */ +} WINE_LOADER_ENTRY, *LPWINE_LOADER_ENTRY; + +/* cache options, search paths for specific types of objects */ +typedef struct _WINE_LOADER_OPTION { + struct list entry; /* for listing elements */ + GUID guidClass; /* ID of object type */ + WCHAR wszSearchPath[MAX_PATH]; /* look for objects of certain type in here */ + BOOL bCache; /* cache objects of certain type */ +} WINE_LOADER_OPTION, *LPWINE_LOADER_OPTION; + +/***************************************************************************** + * IDirectMusicLoaderImpl implementation structure + */ +struct IDirectMusicLoaderImpl { + /* VTABLEs */ + ICOM_VTABLE(IDirectMusicLoader8) *LoaderVtbl; + /* reference counter */ + DWORD dwRef; + /* simple cache (linked list) */ + struct list *pObjects; + /* settings for certain object classes */ + struct list *pClassSettings; + /* critical section */ + CRITICAL_SECTION CritSect; +}; + +/* IUnknown / IDirectMusicLoader(8): */ +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj); +extern ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface); +extern ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID*ppv); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc); +extern void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject); +extern HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject); + +/* contained object entry */ +typedef struct _WINE_CONTAINER_ENTRY { + struct list entry; /* for listing elements */ + DMUS_OBJECTDESC Desc; + BOOL bIsRIFF; + DWORD dwFlags; /* DMUS_CONTAINED_OBJF_KEEP: keep object in loader's cache, even when container is released */ + WCHAR* wszAlias; + LPDIRECTMUSICOBJECT pObject; /* needed when releasing from loader's cache on container release */ +} WINE_CONTAINER_ENTRY, *LPWINE_CONTAINER_ENTRY; /***************************************************************************** * IDirectMusicContainerImpl implementation structure */ struct IDirectMusicContainerImpl { - /* IUnknown fields */ - ICOM_VTABLE(IUnknown) *UnknownVtbl; - ICOM_VTABLE(IDirectMusicContainer) *ContainerVtbl; - ICOM_VTABLE(IDirectMusicObject) *ObjectVtbl; - ICOM_VTABLE(IPersistStream) *PersistStreamVtbl; - DWORD ref; - - /* IDirectMusicContainerImpl fields */ - LPDMUS_OBJECTDESC pDesc; - DMUS_IO_CONTAINER_HEADER* pHeader; - - /* list of objects */ - struct list ObjectsList; + /* VTABLEs */ + ICOM_VTABLE(IDirectMusicContainer) *ContainerVtbl; + ICOM_VTABLE(IDirectMusicObject) *ObjectVtbl; + ICOM_VTABLE(IPersistStream) *PersistStreamVtbl; + /* reference counter */ + DWORD dwRef; + /* stream */ + LPSTREAM pStream; + /* header */ + DMUS_IO_CONTAINER_HEADER Header; + /* data */ + struct list *pContainedObjects; + /* descriptor */ + DMUS_OBJECTDESC Desc; }; -/* IUnknown: */ -extern HRESULT WINAPI IDirectMusicContainerImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj); -extern ULONG WINAPI IDirectMusicContainerImpl_IUnknown_AddRef (LPUNKNOWN iface); -extern ULONG WINAPI IDirectMusicContainerImpl_IUnknown_Release (LPUNKNOWN iface); -/* IDirectMusicContainer: */ +/* IUnknown / IDirectMusicContainer: */ extern HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_QueryInterface (LPDIRECTMUSICCONTAINER iface, REFIID riid, LPVOID *ppobj); extern ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_AddRef (LPDIRECTMUSICCONTAINER iface); extern ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicContainer_Release (LPDIRECTMUSICCONTAINER iface); @@ -162,7 +223,6 @@ extern ULONG WINAPI IDirectMusicContainerImpl_IDirectMusicObject_Release (LPDI extern HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc); extern HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc); extern HRESULT WINAPI IDirectMusicContainerImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc); - /* IPersistStream: */ extern HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, void** ppvObject); extern ULONG WINAPI IDirectMusicContainerImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface); @@ -175,97 +235,145 @@ extern HRESULT WINAPI IDirectMusicContainerImpl_IPersistStream_GetSizeMax (LPPER /***************************************************************************** - * ILoaderStream implementation structure + * IDirectMusicLoaderFileStream implementation structure */ -struct ILoaderStream { - /* IUnknown fields */ - ICOM_VTABLE(IUnknown) *UnknownVtbl; - ICOM_VTABLE(IStream) *StreamVtbl; - ICOM_VTABLE(IDirectMusicGetLoader) *GetLoaderVtbl; - DWORD ref; - - /* ILoaderStream fields */ - IDirectMusicLoader8Impl* pLoader; - HANDLE hFile; - WCHAR wzFileName[MAX_PATH]; /* for clone */ +struct IDirectMusicLoaderFileStream { + /* VTABLEs */ + ICOM_VTABLE(IStream) *StreamVtbl; + ICOM_VTABLE(IDirectMusicGetLoader) *GetLoaderVtbl; + /* reference counter */ + DWORD dwRef; + /* file */ + WCHAR wzFileName[MAX_PATH]; /* for clone */ + HANDLE hFile; + /* loader */ + LPDIRECTMUSICLOADER8 pLoader; }; /* Custom: */ -extern HRESULT WINAPI ILoaderStream_Attach (LPSTREAM iface, LPCWSTR wzFile, IDirectMusicLoader *pLoader); -extern void WINAPI ILoaderStream_Detach (LPSTREAM iface); -/* IUnknown: */ -extern HRESULT WINAPI ILoaderStream_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, void** ppobj); -extern ULONG WINAPI ILoaderStream_IUnknown_AddRef (LPUNKNOWN iface); -extern ULONG WINAPI ILoaderStream_IUnknown_Release (LPUNKNOWN iface); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER pLoader); +extern void WINAPI IDirectMusicLoaderFileStream_Detach (LPSTREAM iface); +/* IUnknown/IStream: */ +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface); +extern ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Read (IStream* iface, void* pv, ULONG cb, ULONG* pcbRead); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Revert (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface, IStream** ppstm); /* IDirectMusicGetLoader: */ -extern HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj); -extern ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); -extern ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface); -extern HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader); -/* IStream: */ -extern HRESULT WINAPI ILoaderStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj); -extern ULONG WINAPI ILoaderStream_IStream_AddRef (LPSTREAM iface); -extern ULONG WINAPI ILoaderStream_IStream_Release (LPSTREAM iface);extern HRESULT WINAPI ILoaderStream_IStream_Read (IStream* iface, void* pv, ULONG cb, ULONG* pcbRead); -extern HRESULT WINAPI ILoaderStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten); -extern HRESULT WINAPI ILoaderStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition); -extern HRESULT WINAPI ILoaderStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize); -extern HRESULT WINAPI ILoaderStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten); -extern HRESULT WINAPI ILoaderStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags); -extern HRESULT WINAPI ILoaderStream_IStream_Revert (LPSTREAM iface); -extern HRESULT WINAPI ILoaderStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); -extern HRESULT WINAPI ILoaderStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); -extern HRESULT WINAPI ILoaderStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag); -extern HRESULT WINAPI ILoaderStream_IStream_Clone (LPSTREAM iface, IStream** ppstm); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); +extern ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader); + + +/***************************************************************************** + * IDirectMusicLoaderResourceStream implementation structure + */ +struct IDirectMusicLoaderResourceStream { + /* IUnknown fields */ + ICOM_VTABLE(IStream) *StreamVtbl; + ICOM_VTABLE(IDirectMusicGetLoader) *GetLoaderVtbl; + /* reference counter */ + DWORD dwRef; + /* data */ + LPBYTE pbMemData; + LONGLONG llMemLength; + /* current position */ + LONGLONG llPos; + /* loader */ + LPDIRECTMUSICLOADER8 pLoader; +}; + +/* Custom: */ +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER pLoader); +extern void WINAPI IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface); +/* IUnknown/IStream: */ +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface); +extern ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_Release (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Read (IStream* iface, void* pv, ULONG cb, ULONG* pcbRead); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Revert (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Clone (LPSTREAM iface, IStream** ppstm); +/* IDirectMusicGetLoader: */ +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); +extern ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader); + + +/***************************************************************************** + * IDirectMusicLoaderGenericStream implementation structure + */ +struct IDirectMusicLoaderGenericStream { + /* IUnknown fields */ + ICOM_VTABLE(IStream) *StreamVtbl; + ICOM_VTABLE(IDirectMusicGetLoader) *GetLoaderVtbl; + /* reference counter */ + DWORD dwRef; + /* stream */ + LPSTREAM pStream; + /* loader */ + LPDIRECTMUSICLOADER8 pLoader; +}; + +/* Custom: */ +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER pLoader); +extern void WINAPI IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface); +/* IUnknown/IStream: */ +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface); +extern ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (IStream* iface, void* pv, ULONG cb, ULONG* pcbRead); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm); +/* IDirectMusicGetLoader: */ +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj); +extern ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); +extern ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader); /***************************************************************************** * Misc. */ /* for simpler reading */ -typedef struct _DMUS_PRIVATE_CHUNK { +typedef struct _WINE_CHUNK { FOURCC fccID; /* FOURCC ID of the chunk */ DWORD dwSize; /* size of the chunk */ -} DMUS_PRIVATE_CHUNK, *LPDMUS_PRIVATE_CHUNK; +} WINE_CHUNK, *LPWINE_CHUNK; -/* used for generic dumping (copied from ddraw) */ -typedef struct { - DWORD val; - const char* name; -} flag_info; +extern HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]); +extern HRESULT WINAPI DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache); +extern HRESULT WINAPI DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache); +extern HRESULT WINAPI DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface); +extern HRESULT WINAPI DMUSIC_CopyDescriptor (LPDMUS_OBJECTDESC pDst, LPDMUS_OBJECTDESC pSrc); +extern BOOL WINAPI DMUSIC_IsValidLoadableClass (REFCLSID pClassID); -typedef struct { - const GUID *guid; - const char* name; -} guid_info; - -/* used for initialising structs (primarily for DMUS_OBJECTDESC) */ -#define DM_STRUCT_INIT(x) \ - do { \ - memset((x), 0, sizeof(*(x))); \ - (x)->dwSize = sizeof(*x); \ - } while (0) - -#define FE(x) { x, #x } -#define GE(x) { &x, #x } - -/* check whether the given DWORD is even (return 0) or odd (return 1) */ -extern int even_or_odd (DWORD number); -/* translate STREAM_SEEK flag to string */ -extern const char *resolve_STREAM_SEEK (DWORD flag); -/* FOURCC to string conversion for debug messages */ -extern const char *debugstr_fourcc (DWORD fourcc); -/* DMUS_VERSION struct to string conversion for debug messages */ -extern const char *debugstr_dmversion (LPDMUS_VERSION version); -/* returns name of given GUID */ -extern const char *debugstr_dmguid (const GUID *id); -/* returns name of given error code */ -extern const char *debugstr_dmreturn (DWORD code); -/* generic flags-dumping function */ -extern const char *debugstr_flags (DWORD flags, const flag_info* names, size_t num_names); -extern const char *debugstr_DMUS_OBJ_FLAGS (DWORD flagmask); -/* dump whole DMUS_OBJECTDESC struct */ -extern const char *debugstr_DMUS_OBJECTDESC (LPDMUS_OBJECTDESC pDesc); -/* check whether chunkID is valid dmobject form chunk */ -extern BOOL IS_VALID_DMFORM (FOURCC chunkID); +#include "debug.h" #endif /* __WINE_DMLOADER_PRIVATE_H */ diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index a3f3a0e7649..ebe9b42397b 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -1,4 +1,4 @@ -/* IDirectMusicLoader8 Implementation +/* IDirectMusicLoaderImpl * * Copyright (C) 2003-2004 Rok Mandeljc * @@ -21,685 +21,807 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); -HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]); - -/* IDirectMusicLoader8 IUnknown part: */ -HRESULT WINAPI IDirectMusicLoader8Impl_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); +/***************************************************************************** + * IDirectMusicLoaderImpl implementation + */ +/* IUnknown/IDirectMusicLoader(8) part: */ +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface (LPDIRECTMUSICLOADER8 iface, REFIID riid, LPVOID *ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj); if (IsEqualIID (riid, &IID_IUnknown) || IsEqualIID (riid, &IID_IDirectMusicLoader) || IsEqualIID (riid, &IID_IDirectMusicLoader8)) { - IDirectMusicLoader8Impl_AddRef(iface); + IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (iface); *ppobj = This; return S_OK; } - WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj); + WARN(": not found\n"); return E_NOINTERFACE; } -ULONG WINAPI IDirectMusicLoader8Impl_AddRef (LPDIRECTMUSICLOADER8 iface) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - TRACE("(%p): AddRef from %ld\n", This, This->ref); - return ++(This->ref); +ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef (LPDIRECTMUSICLOADER8 iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); } -ULONG WINAPI IDirectMusicLoader8Impl_Release (LPDIRECTMUSICLOADER8 iface) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - ULONG ref = --This->ref; - TRACE("(%p): ReleaseRef to %ld\n", This, This->ref); - if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This); +ULONG WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_Release (LPDIRECTMUSICLOADER8 iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, This->dwRef); + if (dwRef == 0) { + DMUSIC_DestroyDirectMusicLoaderImpl (iface); + HeapFree (GetProcessHeap(), 0, This); } - return ref; + + return dwRef; } -/* IDirectMusicLoader8 IDirectMusicLoader part: */ -HRESULT WINAPI IDirectMusicLoader8Impl_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - HRESULT result = 0; - struct list *listEntry; - LPDMUS_PRIVATE_ALIAS_ENTRY aliasEntry; - DMUS_PRIVATE_CACHE_ENTRY *cacheEntry; - DMUS_OBJECTDESC CacheDesc; - IDirectMusicObject* pObject; - LPDMUS_PRIVATE_CACHE_ENTRY newEntry; +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc, REFIID riid, LPVOID* ppv) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + HRESULT result = S_OK; + HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */ + + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry = NULL; + LPSTREAM pStream; + IPersistStream* pPersistStream = NULL; - TRACE("(%p, %p, %s, %p): pDesc:\n%s\n", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc)); + LPDIRECTMUSICOBJECT pObject; + DMUS_OBJECTDESC GotDesc; + BOOL bCache; + + TRACE("(%p, %p, %s, %p): pDesc:\n%s", This, pDesc, debugstr_dmguid(riid), ppv, debugstr_DMUS_OBJECTDESC(pDesc)); - /* if I understand correctly, SetObject makes sort of aliases for entries in cache; - therefore I created alias list, which is similiar to cache list, and is used as resolver - (it maps let's say GUID to filename) */ - TRACE(": looking for alias\n"); - LIST_FOR_EACH (listEntry, &This->AliasList) { - aliasEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_ALIAS_ENTRY, entry); - /* for the time being, we support only GUID/name mapping */ - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_OBJECT) && (pDesc->dwValidData & DMUS_OBJ_OBJECT) - && IsEqualGUID (&aliasEntry->pDesc->guidObject, &pDesc->guidObject)) { - TRACE(": found alias by GUID (%s)... mapping:\n", debugstr_dmguid(&aliasEntry->pDesc->guidObject)); - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_FILENAME) && !(pDesc->dwValidData & DMUS_OBJ_FILENAME)) { - TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry->pDesc->wszFileName)); - pDesc->dwValidData |= DMUS_OBJ_FILENAME; - pDesc->dwValidData |= (aliasEntry->pDesc->dwValidData & DMUS_OBJ_FULLPATH); - strncpyW (pDesc->wszFileName, aliasEntry->pDesc->wszFileName, DMUS_MAX_FILENAME); - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_NAME) && !(pDesc->dwValidData & DMUS_OBJ_NAME)) { - TRACE(": - to name (%s)\n", debugstr_w(aliasEntry->pDesc->wszName)); - pDesc->dwValidData |= DMUS_OBJ_NAME; - strncpyW (pDesc->wszName, aliasEntry->pDesc->wszName, DMUS_MAX_NAME); - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_MEMORY) && !(pDesc->dwValidData & DMUS_OBJ_MEMORY)) { - TRACE(": - to memory location\n"); - pDesc->dwValidData |= DMUS_OBJ_MEMORY; - /* FIXME: is this correct? */ - pDesc->pbMemData = aliasEntry->pDesc->pbMemData; - pDesc->llMemLength = aliasEntry->pDesc->llMemLength; - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_STREAM) && !(pDesc->dwValidData & DMUS_OBJ_STREAM)) { - TRACE(": - to stream\n"); - pDesc->dwValidData |= DMUS_OBJ_STREAM; - IStream_Clone (aliasEntry->pDesc->pStream, &pDesc->pStream); - } - } - else if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_NAME) && (pDesc->dwValidData & DMUS_OBJ_NAME) - && !strncmpW (aliasEntry->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME)) { - TRACE(": found alias by name (%s)... mapping:\n", debugstr_w(aliasEntry->pDesc->wszName)); - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_FILENAME) && !(pDesc->dwValidData & DMUS_OBJ_FILENAME)) { - TRACE(": - to filename (%s)\n", debugstr_w(aliasEntry->pDesc->wszFileName)); - pDesc->dwValidData |= DMUS_OBJ_FILENAME; - pDesc->dwValidData |= (aliasEntry->pDesc->dwValidData & DMUS_OBJ_FULLPATH); - strncpyW (pDesc->wszFileName, aliasEntry->pDesc->wszFileName, DMUS_MAX_FILENAME); - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_OBJECT) && !(pDesc->dwValidData & DMUS_OBJ_OBJECT)) { - TRACE(": - to object GUID (%s)\n", debugstr_dmguid(&aliasEntry->pDesc->guidObject)); - pDesc->dwValidData |= DMUS_OBJ_OBJECT; - memcpy (&pDesc->guidObject, &aliasEntry->pDesc->guidObject, sizeof(GUID)); - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_MEMORY) && !(pDesc->dwValidData & DMUS_OBJ_MEMORY)) { - TRACE(": - to memory location\n"); - pDesc->dwValidData |= DMUS_OBJ_MEMORY; - /* FIXME: is this correct? */ - pDesc->pbMemData = aliasEntry->pDesc->pbMemData; - pDesc->llMemLength = aliasEntry->pDesc->llMemLength; - } - if ((aliasEntry->pDesc->dwValidData & DMUS_OBJ_STREAM) && !(pDesc->dwValidData & DMUS_OBJ_STREAM)) { - TRACE(": - to stream\n"); - pDesc->dwValidData |= DMUS_OBJ_STREAM; - IStream_Clone (aliasEntry->pDesc->pStream, &pDesc->pStream); - } - } - /*else FIXME(": implement other types of mapping\n"); */ - } - - /* iterate through cache and check whether object has already been loaded */ - TRACE(": looking up cache...\n"); - DM_STRUCT_INIT(&CacheDesc); - LIST_FOR_EACH (listEntry, &This->CacheList) { - cacheEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry); - /* first check whether cached object is "faulty" default dls collection; - * I don't think it's recongised by object descriptor, since it contains no - * data; it's not very elegant way, but it works :) - */ - if (cacheEntry->bIsFaultyDLS == TRUE) { - if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && IsEqualGUID (&GUID_DefaultGMCollection, &pDesc->guidObject)) { - TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n"); - return DMUS_E_LOADER_NOFILENAME; - } - } - /* I think it shouldn't happen that pObject is NULL, but better be safe */ - if (cacheEntry->pObject) { - DM_STRUCT_INIT(&CacheDesc); /* prepare desc for reuse */ - IDirectMusicObject_GetDescriptor (cacheEntry->pObject, &CacheDesc); - /* according to MSDN, search order is: - 1. DMUS_OBJ_OBJECT - 2. DMUS_OBJ_MEMORY (FIXME) - 3. DMUS_OBJ_FILENAME & DMUS_OBJ_FULLPATH - 4. DMUS_OBJ_NAME & DMUS_OBJ_CATEGORY - 5. DMUS_OBJ_NAME - 6. DMUS_OBJ_FILENAME */ - if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && (CacheDesc.dwValidData & DMUS_OBJ_OBJECT) - && IsEqualGUID (&pDesc->guidObject, &CacheDesc.guidObject)) { - TRACE(": found it by object GUID\n"); - return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv); - } - if ((pDesc->dwValidData & DMUS_OBJ_MEMORY) && (CacheDesc.dwValidData & DMUS_OBJ_MEMORY)) { - FIXME(": DMUS_OBJ_MEMORY not supported yet\n"); - } - if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && (pDesc->dwValidData & DMUS_OBJ_FULLPATH) - && (CacheDesc.dwValidData & DMUS_OBJ_FILENAME) && (CacheDesc.dwValidData & DMUS_OBJ_FULLPATH) - && !strncmpW (pDesc->wszFileName, CacheDesc.wszFileName, DMUS_MAX_FILENAME)) { - TRACE(": found it by fullpath filename\n"); - return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv); - } - if ((pDesc->dwValidData & DMUS_OBJ_NAME) && (pDesc->dwValidData & DMUS_OBJ_CATEGORY) - && (CacheDesc.dwValidData & DMUS_OBJ_NAME) && (CacheDesc.dwValidData & DMUS_OBJ_CATEGORY) - && !strncmpW (pDesc->wszName, CacheDesc.wszName, DMUS_MAX_NAME) - && !strncmpW (pDesc->wszCategory, CacheDesc.wszCategory, DMUS_MAX_CATEGORY)) { - TRACE(": found it by name and category\n"); - return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv); - } - if ((pDesc->dwValidData & DMUS_OBJ_NAME) && (CacheDesc.dwValidData & DMUS_OBJ_NAME) - && !strncmpW (pDesc->wszName, CacheDesc.wszName, DMUS_MAX_NAME)) { - TRACE(": found it by name\n"); - return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv); - } - if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && (CacheDesc.dwValidData & DMUS_OBJ_FILENAME) - && !strncmpW (pDesc->wszFileName, CacheDesc.wszFileName, DMUS_MAX_FILENAME)) { - TRACE(": found it by filename\n"); - return IDirectMusicObject_QueryInterface (cacheEntry->pObject, riid, ppv); - } - } - } - - /* object doesn't exist in cache... guess we'll have to load it */ - TRACE(": object does not exist in cache\n"); - - /* sometimes it happens that guidClass is missing */ + /* sometimes it happens that guidClass is missing... which is a BadThingTM */ if (!(pDesc->dwValidData & DMUS_OBJ_CLASS)) { ERR(": guidClass not valid but needed\n"); *ppv = NULL; return DMUS_E_LOADER_NOCLASSID; } - - if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { + + /* OK, first we iterate thru the list of objects we know about; these are either loaded (GetObject, LoadObjectFromFile) + or set via SetObject; */ + TRACE(": looking if we have object in the cache or if it can be found via alias\n"); + LIST_FOR_EACH(pEntry, This->pObjects) { + LPWINE_LOADER_ENTRY pExistingEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); + if ((pDesc->dwValidData & DMUS_OBJ_OBJECT) && + (pExistingEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) && + IsEqualGUID (&pDesc->guidObject, &pExistingEntry->Desc.guidObject)) { + TRACE(": found it by object GUID\n"); + /* I suppose such stuff can happen only when GUID for object is given (GUID_DefaultGMCollection) */ + if (pExistingEntry->bInvalidDefaultDLS == TRUE) { + TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n"); + return DMUS_E_LOADER_NOFILENAME; + } + if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { + TRACE(": already loaded\n"); + return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); + } else { + TRACE(": not loaded yet\n"); + pObjectEntry = pExistingEntry; + } + } + else if ((pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && + (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && + !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by fullpath filename\n"); + if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { + TRACE(": already loaded\n"); + return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); + } else { + TRACE(": not loaded yet\n"); + pObjectEntry = pExistingEntry; + } + } + else if ((pDesc->dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && + (pExistingEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && + !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME) && + !strncmpW (pDesc->wszCategory, pExistingEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { + TRACE(": found it by name and category\n"); + if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { + TRACE(": already loaded\n"); + return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); + } else { + TRACE(": not loaded yet\n"); + pObjectEntry = pExistingEntry; + } + } + else if ((pDesc->dwValidData & DMUS_OBJ_NAME) && + (pExistingEntry->Desc.dwValidData & DMUS_OBJ_NAME) && + !strncmpW (pDesc->wszName, pExistingEntry->Desc.wszName, DMUS_MAX_NAME)) { + TRACE(": found it by name\n"); + if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { + TRACE(": already loaded\n"); + return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); + } else { + TRACE(": not loaded yet\n"); + pObjectEntry = pExistingEntry; + } + } + else if ((pDesc->dwValidData & DMUS_OBJ_FILENAME) && + (pExistingEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) && + !strncmpW (pDesc->wszFileName, pExistingEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by filename\n"); + if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { + TRACE(": already loaded\n"); + return IDirectMusicObject_QueryInterface (pExistingEntry->pObject, riid, ppv); + } else { + TRACE(": not loaded yet\n"); + pObjectEntry = pExistingEntry; + } + } + } + + /* basically, if we found alias, we use its descriptor to load... + else we use info we were given */ + if (pObjectEntry) { + TRACE(": found alias entry for requested object... using stored info\n"); + /* I think in certain cases it can happen that entry's descriptor lacks info + where to load from (e.g.: if we loaded from stream and then released object + from cache; then only it's CLSID, GUID and perhaps name are left); so just + overwrite info entry has (since it ought to be 100% correct) */ + DMUSIC_CopyDescriptor (pDesc, &pObjectEntry->Desc); + /*pDesc = &pObjectEntry->Desc; */ /* FIXME: is this OK? */ + } else { + TRACE(": no cache/alias entry found for requested object\n"); + } + + if (pDesc->dwValidData & DMUS_OBJ_URL) { + TRACE(": loading from URLs not supported yet\n"); + return DMUS_E_LOADER_FORMATNOTSUPPORTED; + } + else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { /* load object from file */ /* generate filename; if it's full path, don't add search directory path, otherwise do */ - WCHAR wzFileName[MAX_PATH]; - DMUS_OBJECTDESC GotDesc; - LPSTREAM pStream; - IPersistStream* pPersistStream = NULL; + WCHAR wszFileName[MAX_PATH]; if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { - lstrcpyW(wzFileName, pDesc->wszFileName); + lstrcpyW(wszFileName, pDesc->wszFileName); } else { - WCHAR *p; - lstrcpyW(wzFileName, This->wzSearchPath); - p = wzFileName + lstrlenW(wzFileName); - if (p > wzFileName && p[-1] != '\\') *p++ = '\\'; + WCHAR *p, wszSearchPath[MAX_PATH]; + DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL); + lstrcpyW(wszFileName, wszSearchPath); + p = wszFileName + lstrlenW(wszFileName); + if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; strcpyW(p, pDesc->wszFileName); } - TRACE(": loading from file (%s)\n", debugstr_w(wzFileName)); - /* create stream and associate it with dls collection file */ - result = DMUSIC_CreateLoaderStream ((LPVOID*)&pStream); + TRACE(": loading from file (%s)\n", debugstr_w(wszFileName)); + /* create stream and associate it with file */ + result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); if (FAILED(result)) { - ERR(": could not create loader stream\n"); + ERR(": could not create loader stream\n"); return result; } - result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface); + result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, (LPDIRECTMUSICLOADER)iface); if (FAILED(result)) { ERR(": could not attach stream to file\n"); return result; } - /* create object */ - result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); + + } + else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { + /* load object from resource */ + TRACE(": loading from resource\n"); + /* create stream and associate it with given resource */ + result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream); if (FAILED(result)) { - ERR(": could not create object\n"); + ERR(": could not create resource stream\n"); return result; } - /* acquire PersistStream interface */ - result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream); + result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, (LPDIRECTMUSICLOADER)iface); if (FAILED(result)) { - ERR("failed to Query\n"); + ERR(": could not attach stream to resource\n"); return result; } - /* load */ - result = IPersistStream_Load (pPersistStream, pStream); - if (FAILED(result)) { - ERR(": failed to load object\n"); - return result; - } - /* get descriptor */ - DM_STRUCT_INIT(&GotDesc); - result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc); - if (FAILED(result)) { - ERR(": failed to get descriptor\n"); - return result; - } - /* now set the "missing" info (check comment at "Loading default DLS collection") */ - GotDesc.dwValidData |= (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED); /* this time only these are missing */ - strncpyW (GotDesc.wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME); /* set wszFileName, even if futile */ - /* set descriptor */ - IDirectMusicObject_SetDescriptor (pObject, &GotDesc); - /* release all loading related stuff */ - IStream_Release (pStream); - IPersistStream_Release (pPersistStream); } else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { - LPSTREAM pClonedStream = NULL; - IPersistStream* pPersistStream = NULL; - DMUS_OBJECTDESC GotDesc; /* load object from stream */ TRACE(": loading from stream\n"); - /* clone stream, given in pDesc */ - result = IStream_Clone (pDesc->pStream, &pClonedStream); + /* create universal stream and associate it with given one */ + result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); if (FAILED(result)) { - ERR(": failed to clone stream\n"); + ERR(": could not create generic stream\n"); return result; } - /* create object */ - result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); + result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, (LPDIRECTMUSICLOADER)iface); if (FAILED(result)) { - ERR(": could not create object\n"); + ERR(": failed to attach stream\n"); return result; } - /* acquire PersistStream interface */ - result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream); - if (FAILED(result)) { - ERR(": could not acquire IPersistStream\n"); - return result; - } - /* load */ - result = IPersistStream_Load (pPersistStream, pClonedStream); - if (FAILED(result)) { - ERR(": failed to load object\n"); - return result; - } - /* get descriptor */ - DM_STRUCT_INIT(&GotDesc); - result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc); - if (FAILED(result)) { - ERR(": failed to get descriptor\n"); - return result; - } - /* now set the "missing" info */ - GotDesc.dwValidData |= DMUS_OBJ_LOADED; /* only missing data with streams */ - /* set descriptor */ - IDirectMusicObject_SetDescriptor (pObject, &GotDesc); - /* release all loading-related stuff */ - IPersistStream_Release (pPersistStream); - IStream_Release (pClonedStream); - } - else if (pDesc->dwValidData & DMUS_OBJ_OBJECT) { - /* load object by GUID */ - TRACE(": loading by GUID (only default DLS supported)\n"); - if (IsEqualGUID (&pDesc->guidObject, &GUID_DefaultGMCollection)) { - /* Loading default DLS collection: *dirty* secret (TM) - * By mixing native and builtin loader and collection and - * various .dls files, I found out following undocumented - * behaviour: - * - loader creates two instances of collection object - * - it calls ParseDescriptor on first, then releases it - * - then it checks returned descriptor; I'm not sure, but - * it seems that DMUS_OBJ_OBJECT is not present if DLS - * collection is indeed *real* one (gm.dls) - * - if above mentioned flag is not set, it creates another - * instance and loads it; it also gets descriptor and adds - * guidObject and wszFileName (even though this one cannot be - * set on native collection, or so it seems) - * => it seems to be sort of check whether given 'default - * DLS collection' is really one shipped with DX before - * actually loading it - * -cheers, Rok - */ - WCHAR wzFileName[DMUS_MAX_FILENAME]; - LPSTREAM pStream; - LPSTREAM pProbeStream; - IDirectMusicObject *pProbeObject; - DMUS_OBJECTDESC ProbeDesc; - DMUS_OBJECTDESC GotDesc; - IPersistStream *pPersistStream = NULL; - - /* get the path for default collection */ - TRACE(": getting default DLS collection path...\n"); - if (FAILED(DMUSIC_GetDefaultGMPath (wzFileName))) { - ERR(": could not get default collection path\n"); - return E_FAIL; - } - /* create stream and associate it with dls collection file */ - TRACE(": creating stream...\n"); - result = DMUSIC_CreateLoaderStream ((LPVOID*) &pStream); - if (FAILED(result)) { - ERR(": could not create loader stream\n"); - return result; - } - TRACE(": attaching stream...\n"); - result = ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface); - if (FAILED(result)) { - ERR(": could not attach stream to file\n"); - return result; - } - /* now create a clone of stream for "probe" */ - TRACE(": cloning stream (for probing)...\n"); - result = IStream_Clone (pStream, &pProbeStream); - if (FAILED(result)) { - ERR(": could not clone stream\n"); - return result; - } - /* create object for "probing" */ - TRACE(": creating IDirectMusicObject (for probing)...\n"); - result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pProbeObject); - if (FAILED(result)) { - ERR(": could not create object (for probing)\n"); - return result; - } - /* get descriptor from stream */ - TRACE(": parsing descriptor on probe stream...\n"); - DM_STRUCT_INIT(&ProbeDesc); - result = IDirectMusicObject_ParseDescriptor (pProbeObject, pProbeStream, &ProbeDesc); - if (FAILED(result)) { - ERR(": could not parse descriptor\n"); - return result; - } - /* release all probing-related stuff */ - TRACE(": releasing probing-related stuff...\n"); - IStream_Release (pProbeStream); - IDirectMusicObject_Release (pProbeObject); - /* now, if it happens by any chance that dls collection isn't *the one* - * TODO: - check if the way below is the appropriate one - */ - if (ProbeDesc.dwValidData & DMUS_OBJ_OBJECT) { - LPDMUS_PRIVATE_CACHE_ENTRY newEntry; - WARN(": the default DLS collection is not the one shipped with DX\n"); - /* my tests show that we return pointer to something or NULL, depending on + how - * input object was defined (therefore we probably don't return anything for object) - * and DMUS_E_LOADER_NOFILENAME as error code - * (I'd personally rather return DMUS_S_PARTIALLOAD, but I don't set rules) - */ - newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY)); - newEntry->pObject = NULL; - newEntry->bIsFaultyDLS = TRUE; /* so that cache won't try to get descriptor */ - list_add_tail (&This->CacheList, &newEntry->entry); - TRACE(": filled in cache entry\n"); - return DMUS_E_LOADER_NOFILENAME; - } - /* now the real loading... create object */ - TRACE(": creating IDirectMusicObject (for loading)\n"); - result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*) &pObject); - if (FAILED(result)) { - ERR(": could not create object (for loading)\n"); - return result; - } - /* acquire PersistStream interface */ - TRACE(": getting IPersistStream on object...\n"); - result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*) &pPersistStream); - if (FAILED(result)) { - ERR(": could not acquire IPersistStream\n"); - return result; - } - /* load */ - TRACE(": loading object..\n"); - result = IPersistStream_Load (pPersistStream, pStream); - if (FAILED(result)) { - ERR(": failed to load object\n"); - return result; - } - /* get descriptor */ - TRACE(": getting descriptor of loaded object...\n"); - DM_STRUCT_INIT(&GotDesc); - result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc); - if (FAILED(result)) { - ERR(": failed to get descriptor\n"); - return result; - } - /* now set the "missing" info */ - TRACE(": adding \"missing\" info...\n"); - GotDesc.dwValidData |= (DMUS_OBJ_OBJECT | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED); - memcpy (&GotDesc.guidObject, &pDesc->guidObject, sizeof(GUID)); /* set guidObject */ - strncpyW (GotDesc.wszFileName, wzFileName, DMUS_MAX_FILENAME); /* set wszFileName, even if futile */ - /* set descriptor */ - TRACE(": setting descriptor\n"); - IDirectMusicObject_SetDescriptor (pObject, &GotDesc); - /* release all loading related stuff */ - TRACE(": releasing all loading-related stuff\n"); - IStream_Release (pStream); - IPersistStream_Release (pPersistStream); - } else { - return E_FAIL; - } } else { /* nowhere to load from */ FIXME(": unknown/unsupported way of loading\n"); - return E_FAIL; + return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ } - - /* add object to cache */ - newEntry = (LPDMUS_PRIVATE_CACHE_ENTRY) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_CACHE_ENTRY)); - if (pObject) { - newEntry->pObject = pObject; - newEntry->bIsFaultyDLS = FALSE; + + /* create object */ + result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); + if (FAILED(result)) { + ERR(": could not create object\n"); + return result; } - list_add_tail (&This->CacheList, &newEntry->entry); - TRACE(": filled in cache entry\n"); + /* acquire PersistStream interface */ + result = IDirectMusicObject_QueryInterface (pObject, &IID_IPersistStream, (LPVOID*)&pPersistStream); + if (FAILED(result)) { + ERR("failed to Query\n"); + return result; + } + /* load */ + result = IPersistStream_Load (pPersistStream, pStream); + if (result != S_OK) { + WARN(": failed to (completely) load object (%s)\n", debugstr_dmreturn(result)); + ret = DMUS_S_PARTIALLOAD /*result*/; + } + /* get descriptor */ + DM_STRUCT_INIT(&GotDesc); + result = IDirectMusicObject_GetDescriptor (pObject, &GotDesc); + /* set filename (if we loaded via filename) */ + if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { + GotDesc.dwValidData |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)); + strcpyW (GotDesc.wszFileName, pDesc->wszFileName); + } + if (FAILED(result)) { + ERR(": failed to get descriptor\n"); + return result; + } + /* release all loading related stuff */ + IStream_Release (pStream); + IPersistStream_Release (pPersistStream); + + /* add object to cache/overwrite existing info (if cache is enabled) */ + DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, NULL, &bCache); + if (bCache) { + if (!pObjectEntry) { + pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY)); + DM_STRUCT_INIT(&pObjectEntry->Desc); + if (pObject) { + DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->pObject = pObject; + pObjectEntry->bInvalidDefaultDLS = FALSE; + } + list_add_head (This->pObjects, &pObjectEntry->entry); + } else { + if (pObject) { + DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->pObject = pObject; + pObjectEntry->bInvalidDefaultDLS = FALSE; + } + } + TRACE(": filled in cache entry\n"); + } else TRACE(": caching disabled\n"); #if 0 /* for debug purposes (e.g. to check if all files are cached) */ TRACE("*** Loader's cache ***\n"); int i = 0; - LIST_FOR_EACH (listEntry, &This->CacheList) { + LIST_FOR_EACH (pEntry, This->pObjects) { i++; - TRACE("Entry nr. %i:\n", i); - cacheEntry = LIST_ENTRY(listEntry, DMUS_PRIVATE_CACHE_ENTRY, entry); - if (cacheEntry->bIsFaultyDLS == FALSE) { - DM_STRUCT_INIT(&CacheDesc); /* prepare desc for reuse */ - IDirectMusicObject_GetDescriptor (cacheEntry->pObject, &CacheDesc); - TRACE(": %s\n", debugstr_DMUS_OBJECTDESC(&CacheDesc)); - } else { - TRACE(": faulty DLS collection\n"); - } + pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); + TRACE(": entry nr. %i:\n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", i, debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); } #endif - return IDirectMusicObject_QueryInterface (pObject, riid, ppv); + result = IDirectMusicObject_QueryInterface (pObject, riid, ppv); + if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */ + /* if there was trouble with loading, and if no other error occured, + we should return DMUS_S_PARTIALLOAD; else, error is returned */ + if (result == S_OK) + return ret; + else + return result; } -HRESULT WINAPI IDirectMusicLoader8Impl_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - DMUS_PRIVATE_ALIAS_ENTRY *newEntry; +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject (LPDIRECTMUSICLOADER8 iface, LPDMUS_OBJECTDESC pDesc) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + LPSTREAM pStream; + LPDIRECTMUSICOBJECT pObject; DMUS_OBJECTDESC Desc; - + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry, pNewEntry; + TRACE("(%p, %p): pDesc:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC(pDesc)); - + /* create stream and load additional info from it */ if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { /* generate filename; if it's full path, don't add search directory path, otherwise do */ - WCHAR wzFileName[MAX_PATH]; - LPSTREAM pStream; - IDirectMusicObject* pObject; + WCHAR wszFileName[MAX_PATH]; if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { - lstrcpyW(wzFileName, pDesc->wszFileName); + lstrcpyW(wszFileName, pDesc->wszFileName); } else { WCHAR *p; - lstrcpyW(wzFileName, This->wzSearchPath); - p = wzFileName + lstrlenW(wzFileName); - if (p > wzFileName && p[-1] != '\\') *p++ = '\\'; + WCHAR wszSearchPath[MAX_PATH]; + DMUSIC_GetLoaderSettings (iface, &pDesc->guidClass, wszSearchPath, NULL); + lstrcpyW(wszFileName, wszSearchPath); + p = wszFileName + lstrlenW(wszFileName); + if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; strcpyW(p, pDesc->wszFileName); } /* create stream */ - DMUSIC_CreateLoaderStream ((LPVOID*) &pStream); + DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); /* attach stream */ - ILoaderStream_Attach (pStream, wzFileName, (LPDIRECTMUSICLOADER)iface); - /* create object */ - CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); - /* parse descriptor */ - DM_STRUCT_INIT(&Desc); - IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc); - /* release everything */ - IDirectMusicObject_Release (pObject); - IStream_Release (pStream); + IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, (LPDIRECTMUSICLOADER)iface); } - else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { - /* clone stream */ - LPSTREAM pStream = NULL; - IDirectMusicObject* pObject; - - IStream_Clone (pDesc->pStream, &pStream); - /* create object */ - CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); - /* parse descriptor */ - DM_STRUCT_INIT(&Desc); - IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc); - /* release everything */ - IDirectMusicObject_Release (pObject); - IStream_Release (pStream); + else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { + /* create stream */ + DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); + /* attach stream */ + IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, (LPDIRECTMUSICLOADER)iface); + } + else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { + /* create stream */ + DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream); + /* attach stream */ + IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, (LPDIRECTMUSICLOADER)iface); } else { - WARN(": no way to get additional info\n"); + ERR(": no way to get additional info\n"); + return DMUS_E_LOADER_FAILEDOPEN; } + + /* create object */ + CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); + + /* *sigh*... some ms objects have lousy implementation of ParseDescriptor that clears input descriptor :( */ +#ifdef NOW_WE_ARE_FREE + /* parse descriptor: we actually use input descriptor; fields that aren't available from stream remain, + otherwise real info is set */ + IDirectMusicObject_ParseDescriptor (pObject, pStream, pDesc); +#endif + /* hmph... due to some trouble I had with certain tests, we store current position and then set it back */ + DM_STRUCT_INIT(&Desc); + if (FAILED(IDirectMusicObject_ParseDescriptor (pObject, pStream, &Desc))) { + ERR(": couldn't parse descriptor\n"); + return DMUS_E_LOADER_FORMATNOTSUPPORTED; + } + + /* copy elements from parsed descriptor into input descriptor; this sets new info, overwriting if necessary, + but leaves info that's provided by input and not available from stream */ + DMUSIC_CopyDescriptor (pDesc, &Desc); - /* now set additional info... my tests show that existing fields should be overwritten */ - if (Desc.dwValidData & DMUS_OBJ_OBJECT) - memcpy (&pDesc->guidObject, &Desc.guidObject, sizeof(Desc.guidObject)); - if (Desc.dwValidData & DMUS_OBJ_CLASS) - memcpy (&pDesc->guidClass, &Desc.guidClass, sizeof(Desc.guidClass)); - if (Desc.dwValidData & DMUS_OBJ_NAME) - strncpyW (pDesc->wszName, Desc.wszName, DMUS_MAX_NAME); - if (Desc.dwValidData & DMUS_OBJ_CATEGORY) - strncpyW (pDesc->wszCategory, Desc.wszCategory, DMUS_MAX_CATEGORY); - if (Desc.dwValidData & DMUS_OBJ_FILENAME) - strncpyW (pDesc->wszFileName, Desc.wszFileName, DMUS_MAX_FILENAME); - if (Desc.dwValidData & DMUS_OBJ_VERSION) - memcpy (&pDesc->vVersion, &Desc.vVersion, sizeof(Desc.vVersion)); - if (Desc.dwValidData & DMUS_OBJ_DATE) - memcpy (&pDesc->ftDate, &Desc.ftDate, sizeof(Desc.ftDate)); - pDesc->dwValidData |= Desc.dwValidData; /* add new flags */ + /* release everything */ + IDirectMusicObject_Release (pObject); + IStream_Release (pStream); + + /* sometimes it happens that twisted programs call SetObject for same object twice... + in such cases, native loader returns S_OK and does nothing... a sound plan */ + LIST_FOR_EACH (pEntry, This->pObjects) { + pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); + if (!memcmp (&pObjectEntry->Desc, pDesc, sizeof(DMUS_OBJECTDESC))) { + TRACE(": exacly same entry already exists\n"); + return S_OK; + } + } /* add new entry */ TRACE(": adding alias entry with following info: \n%s\n", debugstr_DMUS_OBJECTDESC(pDesc)); - newEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_ALIAS_ENTRY)); - newEntry->pDesc = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC)); - memcpy (newEntry->pDesc, pDesc, sizeof(DMUS_OBJECTDESC)); - list_add_tail (&This->AliasList, &newEntry->entry); + pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_ENTRY)); + /* use this function instead of pure memcpy due to streams (memcpy just copies pointer), + which is basically used further by app that called SetDescriptor... better safety than exception */ + DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc); + list_add_head (This->pObjects, &pNewEntry->entry); + + return S_OK; +} + +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) { + WCHAR wszCurrentPath[MAX_PATH]; + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzPath), fClear); + FIXME(": fClear ignored\n"); + DMUSIC_GetLoaderSettings (iface, rguidClass, wszCurrentPath, NULL); + if (!strncmpW(wszCurrentPath, pwzPath, MAX_PATH)) { + return S_FALSE; + } + /* FIXME: check if path is valid; else return DMUS_E_LOADER_BADPATH */ + return DMUSIC_SetLoaderSettings (iface, rguidClass, pwzPath, NULL); +} + +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) { + static const WCHAR wszAny[] = {'*',0}; + WIN32_FIND_DATAW FileData; + HANDLE hSearch; + WCHAR wszSearchString[MAX_PATH]; + WCHAR *p; + HRESULT result; + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %s, %p, %p)\n", This, debugstr_dmguid(rguidClass), pwzFileExtension, pwzScanFileName); + if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || !DMUSIC_IsValidLoadableClass(rguidClass)) { + ERR(": rguidClass invalid CLSID\n"); + return REGDB_E_CLASSNOTREG; + } + + /* get search path for given class */ + DMUSIC_GetLoaderSettings (iface, rguidClass, wszSearchString, NULL); + + p = wszSearchString + lstrlenW(wszSearchString); + if (p > wszSearchString && p[-1] != '\\') *p++ = '\\'; + *p++ = '*'; /* any file */ + if (strcmpW (pwzFileExtension, wszAny)) *p++ = '.'; /* if we have actual extension, put a dot */ + strcpyW (p, pwzFileExtension); + + TRACE(": search string: %s\n", debugstr_w(wszSearchString)); + + hSearch = FindFirstFileW (wszSearchString, &FileData); + if (hSearch == INVALID_HANDLE_VALUE) { + TRACE(": no files found\n"); + return S_FALSE; + } + + do { + DMUS_OBJECTDESC Desc; + DM_STRUCT_INIT(&Desc); + Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_DATE; + memcpy (&Desc.guidClass, rguidClass, sizeof(GUID)); + strcpyW (Desc.wszFileName, FileData.cFileName); + FileTimeToLocalFileTime (&FileData.ftCreationTime, &Desc.ftDate); + IDirectMusicLoader8_SetObject (iface, &Desc); + + if (!FindNextFileW (hSearch, &FileData)) { + if (GetLastError () == ERROR_NO_MORE_FILES) { + TRACE(": search completed\n"); + result = S_OK; + } else { + ERR(": could not get next file\n"); + result = E_FAIL; + } + FindClose (hSearch); + return result; + } + } while (1); +} + +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { + DMUS_OBJECTDESC Desc; + HRESULT result = DMUS_E_LOADER_OBJECTNOTFOUND; + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry = NULL; + + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %p)\n", This, pObject); + + /* get descriptor */ + DM_STRUCT_INIT(&Desc); + IDirectMusicObject_GetDescriptor (pObject, &Desc); + + /* now iterate thru list and check if we have alias (without object), corresponding + to descriptor of input object */ + LIST_FOR_EACH(pEntry, This->pObjects) { + pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); + if ((Desc.dwValidData & DMUS_OBJ_OBJECT) && + (pObjectEntry->Desc.dwValidData & DMUS_OBJ_OBJECT) && + IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) { + TRACE(": found it by object GUID\n"); + if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) + result = S_FALSE; + else + result = S_OK; + break; + } + else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && + !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by fullpath filename\n"); + if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) + result = S_FALSE; + else + result = S_OK; + break; + } + else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && + !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) && + !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { + TRACE(": found it by name and category\n"); + if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) + result = S_FALSE; + else + result = S_OK; + break; + } + else if ((Desc.dwValidData & DMUS_OBJ_NAME) && + (pObjectEntry->Desc.dwValidData & DMUS_OBJ_NAME) && + !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) { + TRACE(": found it by name\n"); + if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) + result = S_FALSE; + else + result = S_OK; + break; + } + else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) && + (pObjectEntry->Desc.dwValidData & DMUS_OBJ_FILENAME) && + !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by filename\n"); + if ((pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED) && pObjectEntry->pObject) + result = S_FALSE; + else + result = S_OK; + break; + } + } + + /* if we found such alias, then set everything */ + if (result == S_OK) { + pObjectEntry->Desc.dwValidData &= DMUS_OBJ_LOADED; + pObjectEntry->pObject = pObject; + IDirectMusicObject_AddRef (pObjectEntry->pObject); + } + + return result; +} + +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { + DMUS_OBJECTDESC Desc; + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry = NULL; + HRESULT result = S_FALSE; + + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %p)\n", This, pObject); + + /* get descriptor */ + DM_STRUCT_INIT(&Desc); + IDirectMusicObject_GetDescriptor (pObject, &Desc); + + /* iterate thru the list of objects we know about; check only those with DMUS_OBJ_LOADED */ + TRACE(": looking for the object in cache\n"); + LIST_FOR_EACH(pEntry, This->pObjects) { + pObjectEntry = LIST_ENTRY(pEntry, WINE_LOADER_ENTRY, entry); + if ((Desc.dwValidData & DMUS_OBJ_OBJECT) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_OBJECT | DMUS_OBJ_LOADED)) && + IsEqualGUID (&Desc.guidObject, &pObjectEntry->Desc.guidObject)) { + TRACE(": found it by object GUID\n%s", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc)); + result = S_OK; + break; + } + else if ((Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH)) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_LOADED)) && + !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by fullpath filename\n"); + result = S_OK; + break; + } + else if ((Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY | DMUS_OBJ_LOADED)) && + !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME) && + !strncmpW (Desc.wszCategory, pObjectEntry->Desc.wszCategory, DMUS_MAX_CATEGORY)) { + TRACE(": found it by name and category\n"); + result = S_OK; + break; + } + else if ((Desc.dwValidData & DMUS_OBJ_NAME) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_NAME | DMUS_OBJ_LOADED)) && + !strncmpW (Desc.wszName, pObjectEntry->Desc.wszName, DMUS_MAX_NAME)) { + TRACE(": found it by name\n"); + result = S_OK; + break; + } + else if ((Desc.dwValidData & DMUS_OBJ_FILENAME) && + (pObjectEntry->Desc.dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_LOADED)) && + !strncmpW (Desc.wszFileName, pObjectEntry->Desc.wszFileName, DMUS_MAX_FILENAME)) { + TRACE(": found it by filename\n"); + result = S_OK; + break; + } + } + if (result == S_OK) { + /*TRACE(": releasing: \n%s - bInvalidDefaultDLS = %i\n - pObject = %p\n", debugstr_DMUS_OBJECTDESC(&pObjectEntry->Desc), pObjectEntry->bInvalidDefaultDLS, pObjectEntry->pObject); */ + IDirectMusicObject_Release (pObjectEntry->pObject); + pObjectEntry->pObject = NULL; + pObjectEntry->Desc.dwValidData &= ~DMUS_OBJ_LOADED; + } + return result; +} + +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) { + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry; + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidClass)); + + LIST_FOR_EACH (pEntry, This->pObjects) { + pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); + + if ((IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) && + (pObjectEntry->Desc.dwValidData & DMUS_OBJ_LOADED)) { + /* basically, wrap to ReleaseObject for each object found */ + IDirectMusicLoader8_ReleaseObject (iface, pObjectEntry->pObject); + } + } return S_OK; } -HRESULT WINAPI IDirectMusicLoader8Impl_SetSearchDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzPath, BOOL fClear) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - TRACE("(%p, %s, %s, %d)\n", This, debugstr_dmguid(rguidClass), debugstr_w(pwzPath), fClear); - if (0 == strncmpW(This->wzSearchPath, pwzPath, MAX_PATH)) { - return S_FALSE; - } - strncpyW(This->wzSearchPath, pwzPath, MAX_PATH); - return S_OK; +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + BOOL bCurrent; + TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(rguidClass), fEnable); + DMUSIC_GetLoaderSettings (iface, rguidClass, NULL, &bCurrent); + if (bCurrent == fEnable) + return S_FALSE; + else + return DMUSIC_SetLoaderSettings (iface, rguidClass, NULL, &fEnable); } -HRESULT WINAPI IDirectMusicLoader8Impl_ScanDirectory (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, WCHAR* pwzFileExtension, WCHAR* pwzScanFileName) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_dmguid(rguidClass), pwzFileExtension, pwzScanFileName); - return S_OK; -} - -HRESULT WINAPI IDirectMusicLoader8Impl_CacheObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %p): stub\n", This, pObject); - return S_OK; -} - -HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObject (LPDIRECTMUSICLOADER8 iface, IDirectMusicObject* pObject) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %p): stub\n", This, pObject); - return S_OK; -} - -HRESULT WINAPI IDirectMusicLoader8Impl_ClearCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidClass)); - return S_OK; -} - -HRESULT WINAPI IDirectMusicLoader8Impl_EnableCache (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, BOOL fEnable) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %s, %d): stub\n", This, debugstr_dmguid(rguidClass), fEnable); - return S_OK; -} - -HRESULT WINAPI IDirectMusicLoader8Impl_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %s, %ld, %p): stub\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc); +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClass, DWORD dwIndex, LPDMUS_OBJECTDESC pDesc) { + DWORD dwCount = 0; + struct list *pEntry; + LPWINE_LOADER_ENTRY pObjectEntry; + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc); + + DM_STRUCT_INIT(pDesc); + + LIST_FOR_EACH (pEntry, This->pObjects) { + pObjectEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); + + if (IsEqualGUID (rguidClass, &GUID_DirectMusicAllTypes) || IsEqualGUID (rguidClass, &pObjectEntry->Desc.guidClass)) { + if (dwCount == dwIndex) { + memcpy (pDesc, &pObjectEntry->Desc, sizeof(DMUS_OBJECTDESC)); + /* we aren't supposed to reveal this info */ + pDesc->dwValidData &= ~(DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM); + pDesc->pbMemData = NULL; + pDesc->llMemLength = 0; + pDesc->pStream = NULL; + return S_OK; + } + dwCount++; + } + } + + TRACE(": not found\n"); return S_FALSE; } -/* IDirectMusicLoader8 Interface part follow: */ -void WINAPI IDirectMusicLoader8Impl_CollectGarbage (LPDIRECTMUSICLOADER8 iface) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); +void WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage (LPDIRECTMUSICLOADER8 iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); FIXME("(%p): stub\n", This); } -HRESULT WINAPI IDirectMusicLoader8Impl_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); - FIXME("(%p, %p): stub\n", This, pObject); - return S_OK; +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown (LPDIRECTMUSICLOADER8 iface, IUnknown* pObject) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + HRESULT result; + LPDIRECTMUSICOBJECT pObjectInterface; + + TRACE("(%p, %p)\n", This, pObject); + + if (IsBadReadPtr (pObject, sizeof(LPUNKNOWN))) { + ERR(": pObject bad write pointer\n"); + return E_POINTER; + } + /* we simply get IDirectMusicObject interface */ + result = IUnknown_QueryInterface (pObject, &IID_IDirectMusicObject, (LPVOID*)&pObjectInterface); + if (FAILED(result)) return result; + /* and release it in old-fashioned way */ + result = IDirectMusicLoader8_ReleaseObject (iface, pObjectInterface); + IDirectMusicObject_Release (pObjectInterface); + + return result; } -HRESULT WINAPI IDirectMusicLoader8Impl_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, - REFGUID rguidClassID, - REFIID iidInterfaceID, - WCHAR* pwzFilePath, - void** ppObject) { - ICOM_THIS(IDirectMusicLoader8Impl,iface); +HRESULT WINAPI IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile (LPDIRECTMUSICLOADER8 iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR* pwzFilePath, void** ppObject) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); DMUS_OBJECTDESC ObjDesc; + WCHAR wszLoaderSearchPath[MAX_PATH]; - TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoader8Impl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject); + TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject); - ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC); + DM_STRUCT_INIT(&ObjDesc); ObjDesc.dwValidData = DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS; /* I believe I've read somewhere in MSDN that this function requires either full path or relative path */ - ObjDesc.guidClass = *rguidClassID; + memcpy (&ObjDesc.guidClass, rguidClassID, sizeof(CLSID)); /* OK, MSDN says that search order is the following: - current directory (DONE) - windows search path (FIXME: how do I get that?) - loader's search path (DONE) */ - /* search in current directory */ - if (!SearchPathW (NULL, pwzFilePath, NULL, - sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) && - /* search in loader's search path */ - !SearchPathW (This->wzSearchPath, pwzFilePath, NULL, - sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) - { + DMUSIC_GetLoaderSettings (iface, rguidClassID, wszLoaderSearchPath, NULL); + /* search in current directory */ + if (!SearchPathW (NULL, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL) && + /* search in loader's search path */ + !SearchPathW (wszLoaderSearchPath, pwzFilePath, NULL, sizeof(ObjDesc.wszFileName)/sizeof(WCHAR), ObjDesc.wszFileName, NULL)) { /* cannot find file */ - TRACE("cannot find file\n"); + TRACE(": cannot find file\n"); return DMUS_E_LOADER_FAILEDOPEN; } - TRACE("full file path = %s\n", debugstr_w (ObjDesc.wszFileName)); + TRACE(": full file path = %s\n", debugstr_w (ObjDesc.wszFileName)); - return IDirectMusicLoader8Impl_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject); + return IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject (iface, &ObjDesc, iidInterfaceID, ppObject); } -ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader8_Vtbl = { +ICOM_VTABLE(IDirectMusicLoader8) DirectMusicLoader_Loader_Vtbl = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - IDirectMusicLoader8Impl_QueryInterface, - IDirectMusicLoader8Impl_AddRef, - IDirectMusicLoader8Impl_Release, - IDirectMusicLoader8Impl_GetObject, - IDirectMusicLoader8Impl_SetObject, - IDirectMusicLoader8Impl_SetSearchDirectory, - IDirectMusicLoader8Impl_ScanDirectory, - IDirectMusicLoader8Impl_CacheObject, - IDirectMusicLoader8Impl_ReleaseObject, - IDirectMusicLoader8Impl_ClearCache, - IDirectMusicLoader8Impl_EnableCache, - IDirectMusicLoader8Impl_EnumObject, - IDirectMusicLoader8Impl_CollectGarbage, - IDirectMusicLoader8Impl_ReleaseObjectByUnknown, - IDirectMusicLoader8Impl_LoadObjectFromFile + IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface, + IDirectMusicLoaderImpl_IDirectMusicLoader_AddRef, + IDirectMusicLoaderImpl_IDirectMusicLoader_Release, + IDirectMusicLoaderImpl_IDirectMusicLoader_GetObject, + IDirectMusicLoaderImpl_IDirectMusicLoader_SetObject, + IDirectMusicLoaderImpl_IDirectMusicLoader_SetSearchDirectory, + IDirectMusicLoaderImpl_IDirectMusicLoader_ScanDirectory, + IDirectMusicLoaderImpl_IDirectMusicLoader_CacheObject, + IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObject, + IDirectMusicLoaderImpl_IDirectMusicLoader_ClearCache, + IDirectMusicLoaderImpl_IDirectMusicLoader_EnableCache, + IDirectMusicLoaderImpl_IDirectMusicLoader_EnumObject, + IDirectMusicLoaderImpl_IDirectMusicLoader_CollectGarbage, + IDirectMusicLoaderImpl_IDirectMusicLoader_ReleaseObjectByUnknown, + IDirectMusicLoaderImpl_IDirectMusicLoader_LoadObjectFromFile }; /* for ClassFactory */ HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderImpl (LPCGUID lpcGUID, LPVOID *ppobj, LPUNKNOWN pUnkOuter) { - IDirectMusicLoader8Impl *obj; + IDirectMusicLoaderImpl *obj; + DMUS_OBJECTDESC Desc; + LPWINE_LOADER_ENTRY pDefaultDLSEntry; + struct list *pEntry; - TRACE("(%p,%p,%p)\n",lpcGUID, ppobj, pUnkOuter); - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoader8Impl)); + TRACE("(%s, %p, %p)\n", debugstr_dmguid(lpcGUID), ppobj, pUnkOuter); + obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl)); if (NULL == obj) { *ppobj = (LPDIRECTMUSICLOADER8)NULL; return E_OUTOFMEMORY; } - obj->lpVtbl = &DirectMusicLoader8_Vtbl; - obj->ref = 0; /* will be inited with QueryInterface */ - MultiByteToWideChar (CP_ACP, 0, ".\\", -1, obj->wzSearchPath, MAX_PATH); - list_init (&obj->CacheList); - list_init (&obj->AliasList); + obj->LoaderVtbl = &DirectMusicLoader_Loader_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ + /* init critical section */ + /* init cache/alias list */ + /*InitializeCriticalSection (&obj->CritSect); */ + obj->pObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); + list_init (obj->pObjects); + /* init settings */ + obj->pClassSettings = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); + list_init (obj->pClassSettings); + DMUSIC_InitLoaderSettings ((LPDIRECTMUSICLOADER8)obj); - return IDirectMusicLoader8Impl_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj); + /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */ + DM_STRUCT_INIT(&Desc); + Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT; + memcpy (&Desc.guidClass, &CLSID_DirectMusicCollection, sizeof(CLSID)); + memcpy (&Desc.guidObject, &GUID_DefaultGMCollection, sizeof(GUID)); + DMUSIC_GetDefaultGMPath (Desc.wszFileName); + IDirectMusicLoader_SetObject ((LPDIRECTMUSICLOADER8)obj, &Desc); + /* and now the workaroundTM for "invalid" default DLS; basically, + my tests showed that if GUID chunk is present in default DLS + collection, loader treats it as "invalid" and returns + DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check + if out input guidObject was overwritten */ + pEntry = list_head (obj->pObjects); + pDefaultDLSEntry = LIST_ENTRY (pEntry, WINE_LOADER_ENTRY, entry); + if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) { + pDefaultDLSEntry->bInvalidDefaultDLS = TRUE; + } + + /* increase number of instances */ + InterlockedIncrement (&dwDirectMusicLoader); + + return IDirectMusicLoaderImpl_IDirectMusicLoader_QueryInterface ((LPDIRECTMUSICLOADER8)obj, lpcGUID, ppobj); } -/* help function for IDirectMusicLoader8Impl_GetObject */ +HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderImpl (LPDIRECTMUSICLOADER8 iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + + TRACE("(%p)\n", This); + + /* firstly, release the cache */ + IDirectMusicLoader8_ClearCache (iface, &GUID_DirectMusicAllTypes); + /* FIXME: release all allocated entries */ + /* destroy critical section */ + /*DeleteCriticalSection (&This->CritSect); */ + + /* decrease number of instances */ + InterlockedDecrement (&dwDirectMusicLoader); + + return S_OK; +} + +/* help function for DMUSIC_SetDefaultDLS */ HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { HKEY hkDM; DWORD returnType, sizeOfReturnBuffer = MAX_PATH; @@ -715,3 +837,119 @@ HRESULT WINAPI DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { return S_OK; } + +/* help function for retrieval of search path and caching option for certain class */ +HRESULT WINAPI DMUSIC_GetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + struct list *pEntry; + TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache); + + LIST_FOR_EACH(pEntry, This->pClassSettings) { + LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry); + if (IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) { + if (wszSearchPath) + strcpyW(wszSearchPath, pOptionEntry->wszSearchPath); + if (pbCache) + *pbCache = pOptionEntry->bCache; + return S_OK; + } + } + return S_FALSE; +} + +/* help function for setting search path and caching option for certain class */ +HRESULT WINAPI DMUSIC_SetLoaderSettings (LPDIRECTMUSICLOADER8 iface, REFGUID pClassID, WCHAR* wszSearchPath, LPBOOL pbCache) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + struct list *pEntry; + HRESULT result = S_FALSE; /* in case pClassID != GUID_DirectMusicAllTypes and not a valid CLSID */ + TRACE(": (%p, %s, %p, %p)\n", This, debugstr_dmguid(pClassID), wszSearchPath, pbCache); + + LIST_FOR_EACH(pEntry, This->pClassSettings) { + LPWINE_LOADER_OPTION pOptionEntry = LIST_ENTRY(pEntry, WINE_LOADER_OPTION, entry); + /* well, either we have GUID_DirectMusicAllTypes and need to set it to all, + or specific CLSID is given and we set it only to it */ + if (IsEqualGUID (pClassID, &GUID_DirectMusicAllTypes) || + IsEqualCLSID (pClassID, &pOptionEntry->guidClass)) { + if (wszSearchPath) + strcpyW(pOptionEntry->wszSearchPath, wszSearchPath); + if (pbCache) + pOptionEntry->bCache = *pbCache; + result = S_OK; + } + } + + return result; +} + +HRESULT WINAPI DMUSIC_InitLoaderSettings (LPDIRECTMUSICLOADER8 iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderImpl, LoaderVtbl, iface); + + /* hard-coded list of classes */ + static REFCLSID classes[] = { + &CLSID_DirectMusicAudioPathConfig, + &CLSID_DirectMusicBand, + &CLSID_DirectMusicContainer, + &CLSID_DirectMusicCollection, + &CLSID_DirectMusicChordMap, + &CLSID_DirectMusicSegment, + &CLSID_DirectMusicScript, + &CLSID_DirectMusicSong, + &CLSID_DirectMusicStyle, + &CLSID_DirectMusicGraph, + &CLSID_DirectSoundWave + }; + + int i; + WCHAR wszCurrent[MAX_PATH]; + + TRACE(": (%p)\n", This); + GetCurrentDirectoryW (MAX_PATH, wszCurrent); + + for (i = 0; i < sizeof(classes)/sizeof(REFCLSID); i++) { + LPWINE_LOADER_OPTION pNewSetting = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_LOADER_OPTION)); + memcpy (&pNewSetting->guidClass, classes[i], sizeof(CLSID)); + strcpyW (pNewSetting->wszSearchPath, wszCurrent); + pNewSetting->bCache = TRUE; + list_add_tail (This->pClassSettings, &pNewSetting->entry); + } + + return S_OK; +} + +HRESULT WINAPI DMUSIC_CopyDescriptor (LPDMUS_OBJECTDESC pDst, LPDMUS_OBJECTDESC pSrc) { + TRACE(": copy \n%s", debugstr_DMUS_OBJECTDESC(pSrc)); + /* copy field by field */ + if (pSrc->dwValidData & DMUS_OBJ_CLASS) memcpy (&pDst->guidClass, &pSrc->guidClass, sizeof(CLSID)); + if (pSrc->dwValidData & DMUS_OBJ_OBJECT) memcpy (&pDst->guidObject, &pSrc->guidObject, sizeof(GUID)); + if (pSrc->dwValidData & DMUS_OBJ_DATE) memcpy (&pDst->ftDate, &pSrc->ftDate, sizeof(FILETIME)); + if (pSrc->dwValidData & DMUS_OBJ_VERSION) memcpy (&pDst->vVersion, &pSrc->vVersion, sizeof(DMUS_VERSION)); + if (pSrc->dwValidData & DMUS_OBJ_NAME) strcpyW (pDst->wszName, pSrc->wszName); + if (pSrc->dwValidData & DMUS_OBJ_CATEGORY) strcpyW (pDst->wszCategory, pSrc->wszCategory); + if (pSrc->dwValidData & DMUS_OBJ_FILENAME) strcpyW (pDst->wszFileName, pSrc->wszFileName); + if (pSrc->dwValidData & DMUS_OBJ_STREAM) IStream_Clone (pSrc->pStream, &pDst->pStream); + if (pSrc->dwValidData & DMUS_OBJ_MEMORY) { + pDst->pbMemData = pSrc->pbMemData; + pDst->llMemLength = pSrc->llMemLength; + } + /* set flags */ + pDst->dwValidData |= pSrc->dwValidData; + return S_OK; +} + +BOOL WINAPI DMUSIC_IsValidLoadableClass (REFCLSID pClassID) { + if (IsEqualCLSID(pClassID, &CLSID_DirectMusicAudioPathConfig) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicBand) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicContainer) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicCollection) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicChordMap) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicSegment) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicScript) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicSong) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicStyle) || + IsEqualCLSID(pClassID, &CLSID_DirectMusicGraph) || + IsEqualCLSID(pClassID, &CLSID_DirectSoundWave) || + IsEqualCLSID(pClassID, &GUID_DirectMusicAllTypes)) + return TRUE; + else + return FALSE; +} diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index 5c79770e01f..8a4f70bf61c 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -1,4 +1,6 @@ -/* ILoaderStream Implementation +/* IDirectMusicLoaderFileStream + * IDirectMusicLoaderResourceStream + * IDirectMusicLoaderGenericStream * * Copyright (C) 2003-2004 Rok Mandeljc * @@ -17,6 +19,31 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* SIDE NOTES: + * After extensive testing and structure dumping I came to a conclusion that + * DirectMusic as in present state implements three types of streams: + * 1. IDirectMusicLoaderFileStream: stream that was most obvious, since + * it's used for loading from files; it is sort of wrapper around + * CreateFile, ReadFile, WriteFile and SetFilePointer and it supports + * both read and write + * 2. IDirectMusicLoaderResourceStream: a stream that had to exist, since + * according to MSDN, IDirectMusicLoader supports loading from resource + * as well; in this case, data is represented as a big chunk of bytes, + * from which we "read" (copy) data and keep the trace of our position; + * it supports read only + * 3. IDirectMusicLoaderGenericStream: this one was the most problematic, + * since I thought it was URL-related; besides, there's no obvious need + * for it, since input streams can simply be cloned, lest loading from + * stream is requested; but if one really thinks about it, input stream + * could be none of 1. or 2.; in this case, a wrapper that offers + * IDirectMusicGetLoader interface would be nice, and this is what this + * stream is; as such, all functions are supported, as long as underlying + * ("low-level") stream supports them + * + * - Rok Mandeljc; 24. april, 2004 +*/ + #define NONAMELESSUNION #define NONAMELESSSTRUCT @@ -26,15 +53,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); WINE_DECLARE_DEBUG_CHANNEL(dmfileraw); /***************************************************************************** - * Custom functions: + * IDirectMusicLoaderFileStream implementation */ -HRESULT WINAPI ILoaderStream_Attach (LPSTREAM iface, LPCWSTR wzFile, IDirectMusicLoader *pLoader) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); +/* Custom : */ +HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER pLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader); - ILoaderStream_Detach (iface); - This->hFile = CreateFileW (wzFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + IDirectMusicLoaderFileStream_Detach (iface); + This->hFile = CreateFileW (wzFile, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (This->hFile == INVALID_HANDLE_VALUE) { - TRACE(": failed\n"); + WARN(": failed\n"); return DMUS_E_LOADER_FAILEDOPEN; } /* create IDirectMusicGetLoader */ @@ -44,95 +72,72 @@ HRESULT WINAPI ILoaderStream_Attach (LPSTREAM iface, LPCWSTR wzFile, IDirectMusi return S_OK; } -void WINAPI ILoaderStream_Detach (LPSTREAM iface) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); +void WINAPI IDirectMusicLoaderFileStream_Detach (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + TRACE("(%p)\n", This); if (This->hFile != INVALID_HANDLE_VALUE) { CloseHandle(This->hFile); } This->wzFileName[0] = (L'\0'); } -/***************************************************************************** - * ILoaderStream implementation - */ -/* ILoaderStream IUnknown part: */ -HRESULT WINAPI ILoaderStream_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface); + +/* IUnknown/IStream part: */ +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); - if (IsEqualIID (riid, &IID_IUnknown)) { - *ppobj = (LPVOID)&This->UnknownVtbl; - ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); - return S_OK; - } else if (IsEqualIID (riid, &IID_IStream)) { + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IStream)) { *ppobj = (LPVOID)&This->StreamVtbl; - ILoaderStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); + IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); return S_OK; } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { *ppobj = (LPVOID)&This->GetLoaderVtbl; - ILoaderStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); + IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); return S_OK; } - WARN("(%p, %s,%p): not found\n", This, debugstr_dmguid(riid), ppobj); + WARN(": not found\n"); return E_NOINTERFACE; } -ULONG WINAPI ILoaderStream_IUnknown_AddRef (LPUNKNOWN iface) { - ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface); - TRACE("(%p): AddRef from %ld\n", This, This->ref); - return ++(This->ref); +ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); } -ULONG WINAPI ILoaderStream_IUnknown_Release (LPUNKNOWN iface) { - ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface); - ULONG ref = --This->ref; - TRACE("(%p): ReleaseRef to %ld\n", This, This->ref); - if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This); +ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + DMUSIC_DestroyDirectMusicLoaderFileStream (iface); } - return ref; + + return dwRef; } -ICOM_VTABLE(IUnknown) LoaderStream_Unknown_Vtbl = { - ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - ILoaderStream_IUnknown_QueryInterface, - ILoaderStream_IUnknown_AddRef, - ILoaderStream_IUnknown_Release -}; - -/* ILoaderStream IStream part: */ -HRESULT WINAPI ILoaderStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); - return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj); -} - -ULONG WINAPI ILoaderStream_IStream_AddRef (LPSTREAM iface) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); - return ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); -} - -ULONG WINAPI ILoaderStream_IStream_Release (LPSTREAM iface) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); - return ILoaderStream_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl); -} - -HRESULT WINAPI ILoaderStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); ULONG cbRead; - TRACE_(dmfileraw)("(%p, %p, 0x%04lx, %p)\n", This, pv, cb, pcbRead); + + TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p)\n", This, pv, cb, pcbRead); if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; if (pcbRead == NULL) pcbRead = &cbRead; if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL; - TRACE_(dmfileraw)(": data (size = 0x%04lx): '%s'\n", *pcbRead, debugstr_an(pv, *pcbRead)); + + TRACE_(dmfileraw)(": data (size = 0x%08lX): '%s'\n", *pcbRead, debugstr_an(pv, *pcbRead)); return S_OK; } -HRESULT WINAPI ILoaderStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); LARGE_INTEGER liNewPos; - TRACE_(dmfileraw)("(%p, 0x%04llx, %s, %p)\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition); + TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p)\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition); if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; @@ -145,30 +150,30 @@ HRESULT WINAPI ILoaderStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMov return S_OK; } -HRESULT WINAPI ILoaderStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { - ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface); +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); LPSTREAM pOther = NULL; HRESULT result; TRACE("(%p, %p)\n", iface, ppstm); - result = DMUSIC_CreateLoaderStream ((LPVOID*)&pOther); + result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pOther); if (FAILED(result)) return result; if (This->hFile != INVALID_HANDLE_VALUE) { ULARGE_INTEGER ullCurrentPosition; - result = ILoaderStream_Attach (pOther, This->wzFileName, (LPDIRECTMUSICLOADER)This->pLoader); + result = IDirectMusicLoaderFileStream_Attach (pOther, This->wzFileName, (LPDIRECTMUSICLOADER)This->pLoader); if (SUCCEEDED(result)) { LARGE_INTEGER liZero; liZero.QuadPart = 0; - result = ILoaderStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */ + result = IDirectMusicLoaderFileStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */ } if (SUCCEEDED(result)) { LARGE_INTEGER liNewPosition; liNewPosition.QuadPart = ullCurrentPosition.QuadPart; - result = ILoaderStream_IStream_Seek ((LPSTREAM)pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition); + result = IDirectMusicLoaderFileStream_IStream_Seek ((LPSTREAM)pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition); } if (FAILED(result)) { TRACE(": failed\n"); - ILoaderStream_IStream_Release ((LPSTREAM)pOther); + IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)pOther); return result; } } @@ -177,84 +182,90 @@ HRESULT WINAPI ILoaderStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { return S_OK; } -HRESULT WINAPI ILoaderStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { - ERR(": should not be needed\n"); - return E_NOTIMPL; +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + ULONG cbWrite; + + TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p)\n", This, pv, cb, pcbWritten); + if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; + if (pcbWritten == NULL) pcbWritten = &cbWrite; + if (!WriteFile (This->hFile, pv, cb, pcbWritten, NULL) || *pcbWritten != cb) return E_FAIL; + + TRACE_(dmfileraw)(": data (size = 0x%08lX): '%s'\n", *pcbWritten, debugstr_an(pv, *pcbWritten)); + return S_OK; } -HRESULT WINAPI ILoaderStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_Revert (LPSTREAM iface) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Revert (LPSTREAM iface) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { ERR(": should not be needed\n"); return E_NOTIMPL; } -HRESULT WINAPI ILoaderStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { +HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { ERR(": should not be needed\n"); return E_NOTIMPL; } -ICOM_VTABLE(IStream) LoaderStream_Stream_Vtbl = { +ICOM_VTABLE(IStream) DirectMusicLoaderFileStream_Stream_Vtbl = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - ILoaderStream_IStream_QueryInterface, - ILoaderStream_IStream_AddRef, - ILoaderStream_IStream_Release, - ILoaderStream_IStream_Read, - ILoaderStream_IStream_Write, - ILoaderStream_IStream_Seek, - ILoaderStream_IStream_SetSize, - ILoaderStream_IStream_CopyTo, - ILoaderStream_IStream_Commit, - ILoaderStream_IStream_Revert, - ILoaderStream_IStream_LockRegion, - ILoaderStream_IStream_UnlockRegion, - ILoaderStream_IStream_Stat, - ILoaderStream_IStream_Clone + IDirectMusicLoaderFileStream_IStream_QueryInterface, + IDirectMusicLoaderFileStream_IStream_AddRef, + IDirectMusicLoaderFileStream_IStream_Release, + IDirectMusicLoaderFileStream_IStream_Read, + IDirectMusicLoaderFileStream_IStream_Write, + IDirectMusicLoaderFileStream_IStream_Seek, + IDirectMusicLoaderFileStream_IStream_SetSize, + IDirectMusicLoaderFileStream_IStream_CopyTo, + IDirectMusicLoaderFileStream_IStream_Commit, + IDirectMusicLoaderFileStream_IStream_Revert, + IDirectMusicLoaderFileStream_IStream_LockRegion, + IDirectMusicLoaderFileStream_IStream_UnlockRegion, + IDirectMusicLoaderFileStream_IStream_Stat, + IDirectMusicLoaderFileStream_IStream_Clone }; -/***************************************************************************** - * ILoaderStream IDirectMusicGetLoader part: - */ -HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface); - return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj); +/* IDirectMusicGetLoader part: */ +HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); } -ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface); - return ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl); +ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); } -ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface); - return ILoaderStream_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl); +ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); } -HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { - ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface); +HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); TRACE("(%p, %p)\n", This, ppLoader); *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; @@ -263,27 +274,564 @@ HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLO return S_OK; } -ICOM_VTABLE(IDirectMusicGetLoader) LoaderStream_GetLoader_Vtbl = { +ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderFileStream_GetLoader_Vtbl = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE - ILoaderStream_IDirectMusicGetLoader_QueryInterface, - ILoaderStream_IDirectMusicGetLoader_AddRef, - ILoaderStream_IDirectMusicGetLoader_Release, - ILoaderStream_IDirectMusicGetLoader_GetLoader + IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface, + IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef, + IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release, + IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader }; -HRESULT WINAPI DMUSIC_CreateLoaderStream (LPVOID* ppobj) { - ILoaderStream *pStream; +HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderFileStream (LPVOID* ppobj) { + IDirectMusicLoaderFileStream *obj; TRACE("(%p)\n", ppobj); - pStream = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(ILoaderStream)); - if (NULL == pStream) { + obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderFileStream)); + if (NULL == obj) { *ppobj = (LPVOID) NULL; return E_OUTOFMEMORY; } - pStream->UnknownVtbl = &LoaderStream_Unknown_Vtbl; - pStream->StreamVtbl = &LoaderStream_Stream_Vtbl; - pStream->GetLoaderVtbl = &LoaderStream_GetLoader_Vtbl; - pStream->ref = 0; /* will be inited with QueryInterface */ + obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl; + obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ - return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&pStream->UnknownVtbl, &IID_IStream, ppobj); + return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); +} + +HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderFileStream (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + + TRACE("(%p)\n", iface); + if (This->hFile) + IDirectMusicLoaderFileStream_Detach (iface); + HeapFree (GetProcessHeap(), 0, This); + + return S_OK; +} + + +/***************************************************************************** + * IDirectMusicLoaderResourceStream implementation + */ +/* Custom : */ +HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER pLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + + TRACE("(%p, %p, 0x%08llX, 0x%08llx, %p)\n", This, pbMemData, llMemLength, llPos, pLoader); + if (!pbMemData || !llMemLength) { + WARN(": invalid pbMemData or llMemLength\n"); + return E_FAIL; + } + IDirectMusicLoaderResourceStream_Detach (iface); + This->pbMemData = pbMemData; + This->llMemLength = llMemLength; + This->llPos = llPos; + This->pLoader = pLoader; + + return S_OK; +} + +void WINAPI IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + TRACE("(%p)\n", This); + + This->pbMemData = NULL; + This->llMemLength = 0; +} + + +/* IUnknown/IStream part: */ +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IStream)) { + *ppobj = (LPVOID)&This->StreamVtbl; + IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); + return S_OK; + } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { + *ppobj = (LPVOID)&This->GetLoaderVtbl; + IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); + return S_OK; + } + + WARN(": not found\n"); + return E_NOINTERFACE; +} + +ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); +} + +ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_Release (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + DMUSIC_DestroyDirectMusicLoaderResourceStream (iface); + } + + return dwRef; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { + LPBYTE pByte; + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + + TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p)\n", This, pv, cb, pcbRead); + if ((This->llPos + cb) > This->llMemLength) { + WARN_(dmfileraw)(": requested size out of range\n"); + return E_FAIL; + } + + pByte = &This->pbMemData[This->llPos]; + memcpy (pv, pByte, cb); + This->llPos += cb; /* move pointer */ + /* FIXME: error checking would be nice */ + *pcbRead = cb; + + TRACE_(dmfileraw)(": data (size = 0x%08lX): '%s'\n", *pcbRead, debugstr_an(pv, *pcbRead)); + return S_OK; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p)\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition); + + switch (dwOrigin) { + case STREAM_SEEK_CUR: { + if ((This->llPos + dlibMove.QuadPart) > This->llMemLength) { + WARN_(dmfileraw)(": requested offset out of range\n"); + return E_FAIL; + } + break; + } + case STREAM_SEEK_SET: { + if (dlibMove.QuadPart > This->llMemLength) { + WARN_(dmfileraw)(": requested offset out of range\n"); + return E_FAIL; + } + /* set to the beginning of the stream */ + This->llPos = 0; + break; + } + case STREAM_SEEK_END: { + /* TODO: check if this is true... I do think offset should be negative in this case */ + if (dlibMove.QuadPart > 0) { + WARN_(dmfileraw)(": requested offset out of range\n"); + return E_FAIL; + } + /* set to the end of the stream */ + This->llPos = This->llMemLength; + break; + } + default: { + ERR_(dmfileraw)(": invalid dwOrigin\n"); + return E_FAIL; + } + } + /* now simply add */ + This->llPos += dlibMove.QuadPart; + + if (plibNewPosition) plibNewPosition->QuadPart = This->llPos; + + return S_OK; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + LPSTREAM pOther = NULL; + HRESULT result; + + TRACE("(%p, %p)\n", iface, ppstm); + result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pOther); + if (FAILED(result)) return result; + + IDirectMusicLoaderResourceStream_Attach (pOther, This->pbMemData, This->llMemLength, This->llPos, This->pLoader); + + TRACE(": succeeded\n"); + *ppstm = (IStream*)pOther; + return S_OK; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Revert (LPSTREAM iface) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { + ERR(": should not be needed\n"); + return E_NOTIMPL; +} + +ICOM_VTABLE(IStream) DirectMusicLoaderResourceStream_Stream_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicLoaderResourceStream_IStream_QueryInterface, + IDirectMusicLoaderResourceStream_IStream_AddRef, + IDirectMusicLoaderResourceStream_IStream_Release, + IDirectMusicLoaderResourceStream_IStream_Read, + IDirectMusicLoaderResourceStream_IStream_Write, + IDirectMusicLoaderResourceStream_IStream_Seek, + IDirectMusicLoaderResourceStream_IStream_SetSize, + IDirectMusicLoaderResourceStream_IStream_CopyTo, + IDirectMusicLoaderResourceStream_IStream_Commit, + IDirectMusicLoaderResourceStream_IStream_Revert, + IDirectMusicLoaderResourceStream_IStream_LockRegion, + IDirectMusicLoaderResourceStream_IStream_UnlockRegion, + IDirectMusicLoaderResourceStream_IStream_Stat, + IDirectMusicLoaderResourceStream_IStream_Clone +}; + +/* IDirectMusicGetLoader part: */ +HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); +} + +ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); +} + +ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderResourceStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); +} + +HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); + + TRACE("(%p, %p)\n", This, ppLoader); + *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; + IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader); + + return S_OK; +} + +ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderResourceStream_GetLoader_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface, + IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef, + IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release, + IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader +}; + +HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderResourceStream (LPVOID* ppobj) { + IDirectMusicLoaderResourceStream *obj; + + TRACE("(%p)\n", ppobj); + obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderResourceStream)); + if (NULL == obj) { + *ppobj = (LPVOID) NULL; + return E_OUTOFMEMORY; + } + obj->StreamVtbl = &DirectMusicLoaderResourceStream_Stream_Vtbl; + obj->GetLoaderVtbl = &DirectMusicLoaderResourceStream_GetLoader_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ + + return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); +} + +HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderResourceStream (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); + + TRACE("(%p)\n", iface); + IDirectMusicLoaderResourceStream_Detach (iface); + HeapFree (GetProcessHeap(), 0, This); + + return S_OK; +} + +/***************************************************************************** + * IDirectMusicLoaderGenericStream implementation + */ +/* Custom : */ +HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER pLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + TRACE("(%p, %p, %p)\n", This, pStream, pLoader); + if (!pStream) { + WARN(": invalid pStream\n"); + return E_FAIL; + } + if (!pLoader) { + WARN(": invalid pLoader\n"); + return E_FAIL; + } + + IDirectMusicLoaderGenericStream_Detach (iface); + IStream_Clone (pStream, &This->pStream); + This->pLoader = pLoader; + + return S_OK; +} + +void WINAPI IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + if (This->pStream) + IStream_Release (This->pStream); + This->pStream = NULL; +} + + +/* IUnknown/IStream part: */ +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); + if (IsEqualIID (riid, &IID_IUnknown) || + IsEqualIID (riid, &IID_IStream)) { + *ppobj = (LPVOID)&This->StreamVtbl; + IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); + return S_OK; + } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { + *ppobj = (LPVOID)&This->GetLoaderVtbl; + IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); + return S_OK; + } + + WARN(": not found\n"); + return E_NOINTERFACE; +} + +ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p): AddRef from %ld\n", This, This->dwRef); + return InterlockedIncrement (&This->dwRef); +} + +ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + DWORD dwRef = InterlockedDecrement (&This->dwRef); + TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); + if (dwRef == 0) { + DMUSIC_DestroyDirectMusicLoaderGenericStream (iface); + } + + return dwRef; +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p): redirecting to low-level stream\n", This, pv, cb, pcbRead); + if (!This->pStream) + return E_FAIL; + + return IStream_Read (This->pStream, pv, cb, pcbRead); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE_(dmfileraw)("(%p, 0x%08llX, %s, %p): redirecting to low-level stream\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition); + if (!This->pStream) + return E_FAIL; + + return IStream_Seek (This->pStream, dlibMove, dwOrigin, plibNewPosition); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + LPSTREAM pOther = NULL; + LPSTREAM pLowLevel = NULL; + HRESULT result; + + TRACE("(%p, %p)\n", iface, ppstm); + result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pOther); + if (FAILED(result)) return result; + + if (FAILED(IStream_Clone (This->pStream, &pLowLevel))) + return E_FAIL; + + IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel, This->pLoader); + + TRACE(": succeeded\n"); + *ppstm = (IStream*)pOther; + return S_OK; +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE_(dmfileraw)("(%p, %p, 0x%08lX, %p): redirecting to low-level stream\n", This, pv, cb, pcbWritten); + if (!This->pStream) + return E_FAIL; + + return IStream_Write (This->pStream, pv, cb, pcbWritten); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, 0x%08llX): redirecting to low-level stream\n", This, libNewSize.QuadPart); + if (!This->pStream) + return E_FAIL; + + return IStream_SetSize (This->pStream, libNewSize); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, %p, 0x%08llX, %p, %p): redirecting to low-level stream\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); + if (!This->pStream) + return E_FAIL; + + return IStream_CopyTo (This->pStream, pstm, cb, pcbRead, pcbWritten); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, 0x%08lX): redirecting to low-level stream\n", This, grfCommitFlags); + if (!This->pStream) + return E_FAIL; + + return IStream_Commit (This->pStream, grfCommitFlags); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p): redirecting to low-level stream\n", This); + if (!This->pStream) + return E_FAIL; + + return IStream_Revert (This->pStream); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08lX): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + if (!This->pStream) + return E_FAIL; + + return IStream_LockRegion (This->pStream, libOffset, cb, dwLockType); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, 0x%08llX, 0x%08llX, 0x%08lX): redirecting to low-level stream\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + if (!This->pStream) + return E_FAIL; + + return IStream_UnlockRegion (This->pStream, libOffset, cb, dwLockType); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + TRACE("(%p, %p, 0x%08lX): redirecting to low-level stream\n", This, pstatstg, grfStatFlag); + if (!This->pStream) + return E_FAIL; + + return IStream_Stat (This->pStream, pstatstg, grfStatFlag); +} + +ICOM_VTABLE(IStream) DirectMusicLoaderGenericStream_Stream_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicLoaderGenericStream_IStream_QueryInterface, + IDirectMusicLoaderGenericStream_IStream_AddRef, + IDirectMusicLoaderGenericStream_IStream_Release, + IDirectMusicLoaderGenericStream_IStream_Read, + IDirectMusicLoaderGenericStream_IStream_Write, + IDirectMusicLoaderGenericStream_IStream_Seek, + IDirectMusicLoaderGenericStream_IStream_SetSize, + IDirectMusicLoaderGenericStream_IStream_CopyTo, + IDirectMusicLoaderGenericStream_IStream_Commit, + IDirectMusicLoaderGenericStream_IStream_Revert, + IDirectMusicLoaderGenericStream_IStream_LockRegion, + IDirectMusicLoaderGenericStream_IStream_UnlockRegion, + IDirectMusicLoaderGenericStream_IStream_Stat, + IDirectMusicLoaderGenericStream_IStream_Clone +}; + +/* IDirectMusicGetLoader part: */ +HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); +} + +ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); +} + +ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); + return IDirectMusicLoaderGenericStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); +} + +HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); + + TRACE("(%p, %p)\n", This, ppLoader); + *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; + IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader); + + return S_OK; +} + +ICOM_VTABLE(IDirectMusicGetLoader) DirectMusicLoaderGenericStream_GetLoader_Vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface, + IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef, + IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release, + IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader +}; + +HRESULT WINAPI DMUSIC_CreateDirectMusicLoaderGenericStream (LPVOID* ppobj) { + IDirectMusicLoaderGenericStream *obj; + + TRACE("(%p)\n", ppobj); + obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderGenericStream)); + if (NULL == obj) { + *ppobj = (LPVOID) NULL; + return E_OUTOFMEMORY; + } + obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl; + obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl; + obj->dwRef = 0; /* will be inited with QueryInterface */ + + return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); +} + +HRESULT WINAPI DMUSIC_DestroyDirectMusicLoaderGenericStream (LPSTREAM iface) { + ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); + + TRACE("(%p)\n", iface); + IDirectMusicLoaderGenericStream_Detach (iface); + HeapFree (GetProcessHeap(), 0, This); + + return S_OK; }