dmime: Simplify loading/storing of the Tempo Track data.

Fixes loading more than one tempo items.

Signed-off-by: Michael Stefaniuc <mstefani@winehq.org>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Michael Stefaniuc 2020-08-05 00:14:32 +02:00 committed by Alexandre Julliard
parent 4fc685a8b7
commit c64b31c71d
3 changed files with 83 additions and 62 deletions

View file

@ -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)
{

View file

@ -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,

View file

@ -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);
IDirectMusicTempoTrack *This = impl_from_IPersistStream(iface);
struct chunk_entry chunk = {0};
unsigned int i;
HRESULT hr;
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;
TRACE("%p, %p\n", This, stream);
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;
}
}
if (!stream)
return E_POINTER;
return S_OK;
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);