Fixes loading more than one tempo items.
Signed-off-by: Michael Stefaniuc mstefani@winehq.org --- Turns out the pattern of storing an array in a chunk as DWORD - size of element elements[] - array of elements is pretty common. 10 IDirectMusicTrack implementations have it, some of them in multiple chunk types.
dlls/dmime/dmobject.c | 45 ++++++++++++++++++ dlls/dmime/dmobject.h | 2 + dlls/dmime/tempotrack.c | 102 +++++++++++++++------------------------- 3 files changed, 85 insertions(+), 64 deletions(-)
diff --git a/dlls/dmime/dmobject.c b/dlls/dmime/dmobject.c index 0ef007530fd..e6a1ce906a7 100644 --- a/dlls/dmime/dmobject.c +++ b/dlls/dmime/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); @@ -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) { diff --git a/dlls/dmime/dmobject.h b/dlls/dmime/dmobject.h index a1729c83232..afe721dc824 100644 --- a/dlls/dmime/dmobject.h +++ b/dlls/dmime/dmobject.h @@ -35,6 +35,8 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HI HRESULT stream_next_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, diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index 94e4430b7f9..9d25ccc298c 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -29,11 +29,13 @@ WINE_DECLARE_DEBUG_CHANNEL(dmfile); /***************************************************************************** * IDirectMusicTempoTrack implementation */ + typedef struct IDirectMusicTempoTrack { IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; - struct list Items; + DMUS_IO_TEMPO_ITEM *items; + unsigned int count; } IDirectMusicTempoTrack;
/* IDirectMusicTempoTrack IDirectMusicTrack8 part: */ @@ -83,16 +85,7 @@ static ULONG WINAPI tempo_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%d\n", This, ref);
if (!ref) { - struct list *cursor, *cursor2; - DMUS_PRIVATE_TEMPO_ITEM *item; - - LIST_FOR_EACH_SAFE(cursor, cursor2, &This->Items) { - item = LIST_ENTRY(cursor, DMUS_PRIVATE_TEMPO_ITEM, entry); - list_remove(cursor); - - heap_free(item); - } - + heap_free(This->items); heap_free(This); DMIME_UnlockModule(); } @@ -157,8 +150,8 @@ static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID ty MUSIC_TIME *next, void *param) { IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface); - DMUS_PRIVATE_TEMPO_ITEM *item = NULL; DMUS_TEMPO_PARAM *prm = param; + unsigned int i;
TRACE("(%p, %s, %d, %p, %p)\n", This, debugstr_dmguid(type), time, next, param);
@@ -174,15 +167,15 @@ static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID ty prm->mtTime = 0; prm->dblTempo = 0.123456;
- LIST_FOR_EACH_ENTRY(item, &This->Items, DMUS_PRIVATE_TEMPO_ITEM, entry) { - if (item->item.lTime <= time) { - MUSIC_TIME ofs = item->item.lTime - time; + for (i = 0; i < This->count; i++) { + if (This->items[i].lTime <= time) { + MUSIC_TIME ofs = This->items[i].lTime - time; if (ofs > prm->mtTime) { prm->mtTime = ofs; - prm->dblTempo = item->item.dblTempo; + prm->dblTempo = This->items[i].dblTempo; } - if (next && item->item.lTime > time && item->item.lTime < *next) - *next = item->item.lTime; + if (next && This->items[i].lTime > time && This->items[i].lTime < *next) + *next = This->items[i].lTime; } }
@@ -334,53 +327,35 @@ static inline IDirectMusicTempoTrack *impl_from_IPersistStream(IPersistStream *i return CONTAINING_RECORD(iface, IDirectMusicTempoTrack, dmobj.IPersistStream_iface); }
-static HRESULT WINAPI tempo_IPersistStream_Load(IPersistStream *iface, IStream *pStm) +static HRESULT WINAPI tempo_IPersistStream_Load(IPersistStream *iface, IStream *stream) { - IDirectMusicTempoTrack *This = impl_from_IPersistStream(iface); - DMUS_PRIVATE_CHUNK Chunk; - DWORD StreamSize, StreamCount; - LARGE_INTEGER liMove; - DMUS_IO_TEMPO_ITEM item; - LPDMUS_PRIVATE_TEMPO_ITEM pNewItem = NULL; - DWORD nItem = 0; - FIXME("(%p, %p): Loading not fully implemented yet\n", This, pStm); - - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case DMUS_FOURCC_TEMPO_TRACK: { - TRACE_(dmfile)(": Tempo track\n"); - IStream_Read (pStm, &StreamSize, sizeof(DWORD), NULL); - StreamSize -= sizeof(DWORD); - StreamCount = 0; - TRACE_(dmfile)(" - sizeof(DMUS_IO_TEMPO_ITEM): %u (chunkSize = %u)\n", StreamSize, Chunk.dwSize); - do { - IStream_Read (pStm, &item, sizeof(item), NULL); - ++nItem; - TRACE_(dmfile)("DMUS_IO_TEMPO_ITEM #%d\n", nItem); - TRACE_(dmfile)(" - lTime = %u\n", item.lTime); - TRACE_(dmfile)(" - dblTempo = %g\n", item.dblTempo); - pNewItem = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_TEMPO_ITEM)); - if (NULL == pNewItem) - return E_OUTOFMEMORY; - - pNewItem->item = item; - list_add_tail (&This->Items, &pNewItem->entry); - pNewItem = NULL; - StreamCount += sizeof(item); - TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize); - } while (StreamCount < StreamSize); - break; - } - default: { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - return E_FAIL; - } - } + IDirectMusicTempoTrack *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; + unsigned int i; + HRESULT hr;
- return S_OK; + 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 != DMUS_FOURCC_TEMPO_TRACK) + return DMUS_E_UNSUPPORTED_STREAM; + + hr = stream_chunk_get_array(stream, &chunk, (void **)&This->items, &This->count, + sizeof(DMUS_IO_TEMPO_ITEM)); + if (FAILED(hr)) + return hr; + + for (i = 0; i < This->count; i++) { + TRACE_(dmfile)("DMUS_IO_TEMPO_ITEM #%u\n", i); + TRACE_(dmfile)(" - lTime = %u\n", This->items[i].lTime); + TRACE_(dmfile)(" - dblTempo = %g\n", This->items[i].dblTempo); + } + + return S_OK; }
static const IPersistStreamVtbl persiststream_vtbl = { @@ -410,7 +385,6 @@ HRESULT WINAPI create_dmtempotrack(REFIID lpcGUID, void **ppobj) dmobject_init(&track->dmobj, &CLSID_DirectMusicTempoTrack, (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);