[PATCH] dmime: Parse Wave track stream

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Tue May 5 07:36:25 CDT 2020


Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/dmime/dmime_private.h |   7 +
 dlls/dmime/wavetrack.c     | 264 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 269 insertions(+), 2 deletions(-)

diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h
index 9759039a03e9..fddb66e89f60 100644
--- a/dlls/dmime/dmime_private.h
+++ b/dlls/dmime/dmime_private.h
@@ -86,6 +86,13 @@ typedef struct _DMUS_PRIVATE_TEMPO_ITEM {
   DMUS_IO_TEMPO_ITEM item;
 } DMUS_PRIVATE_TEMPO_ITEM, *LPDMUS_PRIVATE_TEMPO_ITEM;
 
+struct DMUS_PRIVATE_WAVE_ITEM {
+    struct list entry; /* for listing elements */
+    DMUS_IO_WAVE_TRACK_HEADER header;
+
+    IDirectMusicObject *object;
+};
+
 typedef struct _DMUS_PRIVATE_SEGMENT_ITEM {
   struct list entry; /* for listing elements */
   DMUS_IO_SEGMENT_ITEM_HEADER header;
diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c
index 1c6b08b52355..84d0bfa10dd5 100644
--- a/dlls/dmime/wavetrack.c
+++ b/dlls/dmime/wavetrack.c
@@ -20,6 +20,8 @@
 #include "dmime_private.h"
 #include "dmobject.h"
 
+#include "wine/heap.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(dmime);
 
 /*****************************************************************************
@@ -32,6 +34,8 @@ typedef struct IDirectMusicWaveTrack {
     IDirectMusicTrack8 IDirectMusicTrack8_iface;
     struct dmobject dmobj;  /* IPersistStream only */
     LONG ref;
+
+    struct list items;
 } IDirectMusicWaveTrack;
 
 /* IDirectMusicWaveTrack IDirectMusicTrack8 part: */
@@ -40,6 +44,11 @@ static inline IDirectMusicWaveTrack *impl_from_IDirectMusicTrack8(IDirectMusicTr
     return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, IDirectMusicTrack8_iface);
 }
 
+static inline IDirectMusicWaveTrack *impl_from_IPersistStream(IPersistStream *iface)
+{
+    return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, dmobj.IPersistStream_iface);
+}
+
 static HRESULT WINAPI wave_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
         void **ret_iface)
 {
@@ -81,6 +90,19 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface)
     TRACE("(%p) ref=%d\n", This, ref);
 
     if (!ref) {
+        struct list *cursor, *cursor2;
+        struct DMUS_PRIVATE_WAVE_ITEM *item;
+
+        LIST_FOR_EACH_SAFE(cursor, cursor2, &This->items) {
+            item = LIST_ENTRY(cursor, struct DMUS_PRIVATE_WAVE_ITEM, entry);
+            list_remove(cursor);
+
+            if (item->object)
+                IDirectMusicObject_Release(item->object);
+
+            heap_free(item);
+        }
+
         HeapFree(GetProcessHeap(), 0, This);
         DMIME_UnlockModule();
     }
@@ -280,10 +302,247 @@ static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
     wave_track_Join
 };
 
+static HRESULT stream_parse_reference(IStream *stream, const struct chunk_entry *parent,
+        IDirectMusicObject **object)
+{
+    HRESULT hr;
+    struct chunk_entry chunk = {.parent = parent};
+    DMUS_IO_REFERENCE reference;
+    DMUS_OBJECTDESC description;
+    IDirectMusicGetLoader *getloader;
+    IDirectMusicLoader *loader;
+
+    memset(&description, 0, sizeof(description));
+
+    *object = NULL;
+
+    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, chunk.size))) {
+        WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+        return hr;
+    }
+
+    TRACE("REFERENCE guidClassID %s, dwValidData 0x%08x\n", debugstr_dmguid(&reference.guidClassID),
+                reference.dwValidData);
+
+    description.dwValidData = DMUS_OBJ_CLASS;
+    description.guidClass = reference.guidClassID;
+
+    while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) {
+        switch (chunk.id) {
+            case DMUS_FOURCC_GUID_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.guidObject,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_OBJECT;
+                break;
+            }
+            case DMUS_FOURCC_DATE_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.ftDate,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_DATE;
+                break;
+            }
+            case DMUS_FOURCC_NAME_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.wszName,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_NAME;
+                break;
+            }
+            case DMUS_FOURCC_FILE_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.wszFileName,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_FILENAME;
+                break;
+            }
+            case DMUS_FOURCC_VERSION_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.vVersion,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_VERSION;
+                break;
+            }
+            case DMUS_FOURCC_CATEGORY_CHUNK: {
+                if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &description.wszCategory,
+                            chunk.size))) {
+                    WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+                    return hr;
+                }
+                description.dwValidData |= DMUS_OBJ_CATEGORY;
+                break;
+            }
+        }
+    }
+
+    dump_DMUS_OBJECTDESC(&description);
+
+    hr = IStream_QueryInterface (stream, &IID_IDirectMusicGetLoader, (void**)&getloader);
+    if (FAILED(hr))
+        return hr;
+
+    hr = IDirectMusicGetLoader_GetLoader (getloader, &loader);
+    if (FAILED(hr))
+        return hr;
+    IDirectMusicGetLoader_Release (getloader);
+
+    hr = IDirectMusicLoader_GetObject (loader, &description, &IID_IDirectMusicObject, (void**)&object);
+    IDirectMusicLoader_Release (loader);
+
+    return SUCCEEDED(hr) ? S_OK : hr;
+}
+
+static HRESULT parse_wave_item(IDirectMusicWaveTrack *This, IStream *stream,
+        struct chunk_entry *wave, struct DMUS_PRIVATE_WAVE_ITEM *item)
+{
+    HRESULT hr;
+    struct chunk_entry chunk = {.parent = wave};
+
+    if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+        return hr;
+
+    if(chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVE_LIST)
+    {
+        struct chunk_entry child = {.parent = &chunk};
+        DMUS_IO_WAVE_ITEM_HEADER header;
+
+        if (FAILED(hr = stream_next_chunk(stream, &child)))
+            return  hr;
+
+        if(child.id != DMUS_FOURCC_WAVEITEM_CHUNK)
+            return DMUS_E_UNSUPPORTED_STREAM;
+
+        if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, child.size))) {
+            WARN("Failed to read data of %s\n", debugstr_chunk(&child));
+            return hr;
+        }
+
+        TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
+        TRACE("  - lVolume %d\n", header.lVolume);
+        TRACE("  - dwVariations %d\n", header.dwVariations);
+        TRACE("  - rtTime %d\n", header.rtTime);
+        TRACE("  - rtStartOffset %d\n", header.rtStartOffset);
+        TRACE("  - rtReserved %d\n", header.rtReserved);
+        TRACE("  - rtDuration %d\n", header.rtDuration);
+        TRACE("  - dwLoopStart %d\n", header.dwLoopStart);
+        TRACE("  - dwLoopEnd %d\n", header.dwLoopEnd);
+        TRACE("  - dwFlags 0x%08x\n", header.dwFlags);
+        TRACE("  - wVolumeRange %d\n", header.wVolumeRange);
+        TRACE("  - wPitchRange %d\n", header.wPitchRange);
+
+        if (FAILED(hr = stream_next_chunk(stream, &child)))
+            return  hr;
+
+        if(child.id == FOURCC_LIST && child.type == DMUS_FOURCC_REF_LIST)
+        {
+            hr = stream_parse_reference(stream, &child, &item->object);
+        }
+    }
+    else
+        hr = DMUS_E_UNSUPPORTED_STREAM;
+
+    return SUCCEEDED(hr) ? S_OK : hr;
+}
+
+static HRESULT parse_wavetrack_list(IDirectMusicWaveTrack *This, IStream *stream,
+        struct chunk_entry *wave)
+{
+    HRESULT hr;
+    struct chunk_entry chunk = {.parent = wave};
+    struct DMUS_PRIVATE_WAVE_ITEM *item = NULL;
+
+    TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(wave));
+
+    if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+        return hr;
+
+    if (chunk.id != DMUS_FOURCC_WAVETRACK_CHUNK)
+        return DMUS_E_UNSUPPORTED_STREAM;
+
+    item = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct DMUS_PRIVATE_WAVE_ITEM));
+    if (!item)
+        return  E_OUTOFMEMORY;
+
+    list_add_tail (&This->items, &item->entry);
+
+    if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+        return hr;
+
+    if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVEPART_LIST)
+    {
+        struct chunk_entry child = {.parent = wave};
+        DMUS_IO_WAVE_PART_HEADER header;
+
+        if (FAILED(hr = stream_next_chunk(stream, &child)))
+            return hr;
+
+        if (child.id != DMUS_FOURCC_WAVEPART_CHUNK)
+            return DMUS_E_UNSUPPORTED_STREAM;
+
+        if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, child.size))) {
+            WARN("Failed to read data of %s\n", debugstr_chunk(&child));
+            return hr;
+        }
+
+        TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
+        TRACE("  - lVolume %d\n", header.lVolume);
+        TRACE("  - dwVariations %d\n", header.dwVariations);
+        TRACE("  - dwPChannel %d\n", header.dwPChannel);
+        TRACE("  - dwLockToPart %d\n", header.dwLockToPart);
+        TRACE("  - dwFlags 0x%08x\n", header.dwFlags);
+        TRACE("  - dwIndex %d\n", header.dwIndex);
+
+        if (FAILED(hr = stream_next_chunk(stream, &child)))
+            return hr;
+
+        if(child.id != FOURCC_LIST || child.type != DMUS_FOURCC_WAVEITEM_LIST)
+            return DMUS_E_UNSUPPORTED_STREAM;
+
+        hr = parse_wave_item(This, stream, &child, item);
+    }
+    else
+        hr = DMUS_E_UNSUPPORTED_STREAM;
+
+    return SUCCEEDED(hr) ? S_OK : hr;
+}
+
 static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream)
 {
-	FIXME(": Loading not implemented yet\n");
-	return S_OK;
+    IDirectMusicWaveTrack *This = impl_from_IPersistStream(iface);
+    HRESULT hr;
+    struct chunk_entry chunk = {0};
+
+    TRACE("%p, %p\n", This, stream);
+
+    if (!stream)
+        return E_POINTER;
+
+    if ((hr = stream_get_chunk(stream, &chunk) != S_OK))
+        return hr;
+
+    if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVETRACK_LIST)
+        hr = parse_wavetrack_list(This, stream, &chunk);
+    else
+        hr = DMUS_E_UNSUPPORTED_STREAM;
+
+    return hr;
 }
 
 static const IPersistStreamVtbl persiststream_vtbl = {
@@ -313,6 +572,7 @@ HRESULT WINAPI create_dmwavetrack(REFIID lpcGUID, void **ppobj)
     dmobject_init(&track->dmobj, &CLSID_DirectMusicWaveTrack,
                   (IUnknown *)&track->IDirectMusicTrack8_iface);
     track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
+    list_init(&track->items);
 
     DMIME_LockModule();
     hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
-- 
2.26.2




More information about the wine-devel mailing list