Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmband/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmband/dmobject.h | 8 ++-
dlls/dmcompos/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmcompos/dmobject.h | 8 ++-
dlls/dmloader/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmloader/dmobject.h | 8 ++-
dlls/dmscript/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmscript/dmobject.h | 8 ++-
dlls/dmstyle/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmstyle/dmobject.h | 8 ++-
dlls/dmusic/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dmusic/dmobject.h | 8 ++-
dlls/dswave/dmobject.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/dswave/dmobject.h | 8 ++-
14 files changed, 791 insertions(+), 42 deletions(-)
diff --git a/dlls/dmband/dmobject.c b/dlls/dmband/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmband/dmobject.c
+++ b/dlls/dmband/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmband/dmobject.h b/dlls/dmband/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmband/dmobject.h
+++ b/dlls/dmband/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmcompos/dmobject.c b/dlls/dmcompos/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmcompos/dmobject.c
+++ b/dlls/dmcompos/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmcompos/dmobject.h b/dlls/dmcompos/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmcompos/dmobject.h
+++ b/dlls/dmcompos/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmloader/dmobject.c b/dlls/dmloader/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmloader/dmobject.c
+++ b/dlls/dmloader/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmloader/dmobject.h b/dlls/dmloader/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmloader/dmobject.h
+++ b/dlls/dmloader/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmscript/dmobject.c b/dlls/dmscript/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmscript/dmobject.c
+++ b/dlls/dmscript/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmscript/dmobject.h b/dlls/dmscript/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmscript/dmobject.h
+++ b/dlls/dmscript/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmstyle/dmobject.c b/dlls/dmstyle/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmstyle/dmobject.c
+++ b/dlls/dmstyle/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmstyle/dmobject.h b/dlls/dmstyle/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmstyle/dmobject.h
+++ b/dlls/dmstyle/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dmusic/dmobject.c
+++ b/dlls/dmusic/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dmusic/dmobject.h
+++ b/dlls/dmusic/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
diff --git a/dlls/dswave/dmobject.c b/dlls/dswave/dmobject.c
index 9ea31ab32a6..e6a1ce906a7 100644
--- a/dlls/dswave/dmobject.c
+++ b/dlls/dswave/dmobject.c
@@ -28,6 +28,7 @@
#include "dmusics.h"
#include "dmobject.h"
#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmobj);
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
@@ -349,7 +350,7 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk)
return S_OK;
}
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk)
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk)
{
LARGE_INTEGER end;
@@ -371,6 +372,50 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk)
return stream_get_chunk(stream, chunk);
}
+/* Reads chunk data of the form:
+ DWORD - size of array element
+ element[] - Array of elements
+ The caller needs to heap_free() the array.
+*/
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size)
+{
+ DWORD size;
+ HRESULT hr;
+
+ *array = NULL;
+ *count = 0;
+
+ if (chunk->size < sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk));
+ return E_FAIL;
+ }
+ if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD))))
+ return hr;
+ if (size != elem_size) {
+ WARN_(dmfile)("%s: Array element size mismatch: got %u, expected %u\n",
+ debugstr_chunk(chunk), size, elem_size);
+ return DMUS_E_UNSUPPORTED_STREAM;
+ }
+
+ *count = (chunk->size - sizeof(DWORD)) / elem_size;
+ size = *count * elem_size;
+ if (!(*array = heap_alloc(size)))
+ return E_OUTOFMEMORY;
+ if (FAILED(hr = stream_read(stream, *array, size))) {
+ heap_free(*array);
+ *array = NULL;
+ return hr;
+ }
+
+ if (chunk->size > size + sizeof(DWORD)) {
+ WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk));
+ stream_skip_chunk(stream, chunk);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size)
{
@@ -529,15 +574,30 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
switch (chunk.id) {
+ case DMUS_FOURCC_CATEGORY_CHUNK:
+ if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ break;
+ case DMUS_FOURCC_DATE_CHUNK:
+ if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk,
+ &desc->ftDate, sizeof(desc->ftDate)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_DATE;
+ break;
+ case DMUS_FOURCC_FILE_CHUNK:
+ if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszFileName, sizeof(desc->wszFileName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_FILENAME;
+ break;
case DMUS_FOURCC_GUID_CHUNK:
if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk,
&desc->guidObject, sizeof(desc->guidObject)) == S_OK)
desc->dwValidData |= DMUS_OBJ_OBJECT;
break;
- case DMUS_FOURCC_CATEGORY_CHUNK:
- if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk,
- desc->wszCategory, sizeof(desc->wszCategory)) == S_OK)
- desc->dwValidData |= DMUS_OBJ_CATEGORY;
+ case DMUS_FOURCC_NAME_CHUNK:
+ if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk,
+ desc->wszName, sizeof(desc->wszName)) == S_OK)
+ desc->dwValidData |= DMUS_OBJ_NAME;
break;
case DMUS_FOURCC_VERSION_CHUNK:
if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk,
@@ -557,6 +617,47 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
return hr;
}
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj)
+{
+ struct chunk_entry chunk = {.parent = list};
+ IDirectMusicGetLoader *getloader;
+ IDirectMusicLoader *loader;
+ DMUS_OBJECTDESC desc;
+ DMUS_IO_REFERENCE reference;
+ HRESULT hr;
+
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_REF_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ return hr;
+ }
+ TRACE("REFERENCE guidClassID %s, dwValidData %#x\n", debugstr_dmguid(&reference.guidClassID),
+ reference.dwValidData);
+
+ if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData)))
+ return hr;
+ desc.guidClass = reference.guidClassID;
+ desc.dwValidData |= DMUS_OBJ_CLASS;
+ dump_DMUS_OBJECTDESC(&desc);
+
+ if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader)))
+ return hr;
+ hr = IDirectMusicGetLoader_GetLoader(getloader, &loader);
+ IDirectMusicGetLoader_Release(getloader);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj);
+ IDirectMusicLoader_Release(loader);
+
+ return hr;
+}
+
/* Generic IPersistStream methods */
static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface)
{
diff --git a/dlls/dswave/dmobject.h b/dlls/dswave/dmobject.h
index d347020691c..afe721dc824 100644
--- a/dlls/dswave/dmobject.h
+++ b/dlls/dswave/dmobject.h
@@ -33,8 +33,10 @@ struct chunk_entry {
HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
-HRESULT stream_skip_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN;
+HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array,
+ unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data,
ULONG size) DECLSPEC_HIDDEN;
HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str,
@@ -89,6 +91,10 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff,
#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */
#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */
+/* 'DMRF' (reference list) helper */
+HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list,
+ IDirectMusicObject **dmobj) DECLSPEC_HIDDEN;
+
/* Generic IPersistStream methods */
HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid,
void **ret_iface) DECLSPEC_HIDDEN;
--
2.26.2