style.c 31.7 KB
Newer Older
1
/* IDirectMusicStyle8 Implementation
2
 *
3
 * Copyright (C) 2003-2004 Rok Mandeljc
4
 * Copyright (C) 2003-2004 Raphael Junqueira
5
 *
6 7 8 9
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
10 11 12
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
15
 *
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21
#include "dmstyle_private.h"
22
#include "dmobject.h"
23
#include "wine/heap.h"
24

25
WINE_DEFAULT_DEBUG_CHANNEL(dmstyle);
26
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
struct style_band {
    struct list entry;
    IDirectMusicBand *pBand;
};

struct style_partref_item {
    struct list entry;
    DMUS_OBJECTDESC desc;
    DMUS_IO_PARTREF part_ref;
};

struct style_motif {
    struct list entry;
    DWORD dwRhythm;
    DMUS_IO_PATTERN pattern;
    DMUS_OBJECTDESC desc;
    /** optional for motifs */
    DMUS_IO_MOTIFSETTINGS settings;
    IDirectMusicBand *pBand;
    struct list Items;
};

50 51 52
/*****************************************************************************
 * IDirectMusicStyleImpl implementation
 */
53 54
typedef struct IDirectMusicStyle8Impl {
    IDirectMusicStyle8 IDirectMusicStyle8_iface;
55
    struct dmobject dmobj;
56 57
    LONG ref;
    DMUS_IO_STYLE style;
58 59
    struct list motifs;
    struct list bands;
60 61
} IDirectMusicStyle8Impl;

62 63 64 65 66
static inline IDirectMusicStyle8Impl *impl_from_IDirectMusicStyle8(IDirectMusicStyle8 *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicStyle8Impl, IDirectMusicStyle8_iface);
}

67 68 69 70 71
/* DirectMusicStyle8Impl IDirectMusicStyle8 part: */
static HRESULT WINAPI IDirectMusicStyle8Impl_QueryInterface(IDirectMusicStyle8 *iface, REFIID riid,
        void **ret_iface)
{
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
72

73
    TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface);
74

75
    *ret_iface = NULL;
76

77 78 79 80
    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicStyle) ||
            IsEqualIID(riid, &IID_IDirectMusicStyle8))
        *ret_iface = iface;
    else if (IsEqualIID(riid, &IID_IDirectMusicObject))
81
        *ret_iface = &This->dmobj.IDirectMusicObject_iface;
82
    else if (IsEqualIID(riid, &IID_IPersistStream))
83
        *ret_iface = &This->dmobj.IPersistStream_iface;
84 85 86 87
    else {
        WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface);
        return E_NOINTERFACE;
    }
Rok Mandeljc's avatar
Rok Mandeljc committed
88

89 90
    IUnknown_AddRef((IUnknown*)*ret_iface);
    return S_OK;
91 92
}

93 94
static ULONG WINAPI IDirectMusicStyle8Impl_AddRef(IDirectMusicStyle8 *iface)
{
95
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
96 97
    LONG ref = InterlockedIncrement(&This->ref);

98
    TRACE("(%p) ref=%ld\n", This, ref);
99 100

    return ref;
101
}
Rok Mandeljc's avatar
Rok Mandeljc committed
102

103 104
static ULONG WINAPI IDirectMusicStyle8Impl_Release(IDirectMusicStyle8 *iface)
{
105
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
106 107
    LONG ref = InterlockedDecrement(&This->ref);

108
    TRACE("(%p) ref=%ld\n", This, ref);
109 110

    if (!ref) {
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        struct style_band *band, *band2;
        struct style_motif *motif, *motif2;
        struct style_partref_item *item, *item2;

        LIST_FOR_EACH_ENTRY_SAFE(band, band2, &This->bands, struct style_band, entry) {
            list_remove(&band->entry);
            if (band->pBand)
                IDirectMusicBand_Release(band->pBand);
            heap_free(band);
        }
        LIST_FOR_EACH_ENTRY_SAFE(motif, motif2, &This->motifs, struct style_motif, entry) {
            list_remove(&motif->entry);
            LIST_FOR_EACH_ENTRY_SAFE(item, item2, &motif->Items, struct style_partref_item, entry) {
                list_remove(&item->entry);
                heap_free(item);
            }
            heap_free(motif);
        }
        heap_free(This);
130 131 132 133
        DMSTYLE_UnlockModule();
    }

    return ref;
134
}
Rok Mandeljc's avatar
Rok Mandeljc committed
135

136
/* IDirectMusicStyle8Impl IDirectMusicStyle(8) part: */
137 138
static HRESULT WINAPI IDirectMusicStyle8Impl_GetBand(IDirectMusicStyle8 *iface, WCHAR *name,
        IDirectMusicBand **band)
139
{
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
    struct style_band *sband;
    HRESULT hr;

    TRACE("(%p, %s, %p)\n", This, debugstr_w(name), band);

    if (!name)
        return E_POINTER;

    LIST_FOR_EACH_ENTRY(sband, &This->bands, struct style_band, entry) {
        IDirectMusicObject *obj;

        hr = IDirectMusicBand_QueryInterface(sband->pBand, &IID_IDirectMusicObject, (void**)&obj);
        if (SUCCEEDED(hr)) {
            DMUS_OBJECTDESC desc;

            if (IDirectMusicObject_GetDescriptor(obj, &desc) == S_OK) {
                if (desc.dwValidData & DMUS_OBJ_NAME && !lstrcmpW(name, desc.wszName)) {
                    IDirectMusicObject_Release(obj);
                    IDirectMusicBand_AddRef(sband->pBand);
                    *band = sband->pBand;
                    return S_OK;
                }
            }

            IDirectMusicObject_Release(obj);
        }
    }

    return S_FALSE;
170 171
}

172 173 174
static HRESULT WINAPI IDirectMusicStyle8Impl_EnumBand(IDirectMusicStyle8 *iface, DWORD dwIndex,
        WCHAR *pwszName)
{
175
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
176
	FIXME("(%p, %ld, %p): stub\n", This, dwIndex, pwszName);
177 178
	return S_OK;
}
Rok Mandeljc's avatar
Rok Mandeljc committed
179

180
static HRESULT WINAPI IDirectMusicStyle8Impl_GetDefaultBand(IDirectMusicStyle8 *iface,
181
        IDirectMusicBand **band)
182
{
183 184 185 186 187 188 189 190 191
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
    FIXME("(%p, %p): stub\n", This, band);

    if (!band)
        return E_POINTER;

    *band = NULL;

    return S_FALSE;
192 193
}

194 195
static HRESULT WINAPI IDirectMusicStyle8Impl_EnumMotif(IDirectMusicStyle8 *iface, DWORD index,
        WCHAR *name)
196
{
197 198 199 200 201
    IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
    const struct style_motif *motif = NULL;
    const struct list *cursor;
    unsigned int i = 0;

202
    TRACE("(%p, %lu, %p)\n", This, index, name);
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

    if (!name)
        return E_POINTER;

    /* index is zero based */
    LIST_FOR_EACH(cursor, &This->motifs) {
        if (i == index) {
            motif = LIST_ENTRY(cursor, struct style_motif, entry);
            break;
        }
        i++;
    }
    if (!motif)
        return S_FALSE;

    if (motif->desc.dwValidData & DMUS_OBJ_NAME)
        lstrcpynW(name, motif->desc.wszName, DMUS_MAX_NAME);
    else
        name[0] = 0;

    TRACE("returning name: %s\n", debugstr_w(name));
    return S_OK;
225 226
}

227 228 229
static HRESULT WINAPI IDirectMusicStyle8Impl_GetMotif(IDirectMusicStyle8 *iface, WCHAR *pwszName,
        IDirectMusicSegment **ppSegment)
{
230
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
231 232
        FIXME("(%p, %s, %p): stub\n", This, debugstr_w(pwszName), ppSegment);
        return S_FALSE;
233 234
}

235 236 237
static HRESULT WINAPI IDirectMusicStyle8Impl_GetDefaultChordMap(IDirectMusicStyle8 *iface,
        IDirectMusicChordMap **ppChordMap)
{
238
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
239 240
	FIXME("(%p, %p): stub\n", This, ppChordMap);
	return S_OK;
241 242
}

243 244 245
static HRESULT WINAPI IDirectMusicStyle8Impl_EnumChordMap(IDirectMusicStyle8 *iface, DWORD dwIndex,
        WCHAR *pwszName)
{
246
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
247
	FIXME("(%p, %ld, %p): stub\n", This, dwIndex, pwszName);
Rok Mandeljc's avatar
Rok Mandeljc committed
248
	return S_OK;
249 250
}

251 252 253
static HRESULT WINAPI IDirectMusicStyle8Impl_GetChordMap(IDirectMusicStyle8 *iface, WCHAR *pwszName,
        IDirectMusicChordMap **ppChordMap)
{
254
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
255 256
	FIXME("(%p, %p, %p): stub\n", This, pwszName, ppChordMap);
	return S_OK;
257 258
}

259 260 261
static HRESULT WINAPI IDirectMusicStyle8Impl_GetTimeSignature(IDirectMusicStyle8 *iface,
        DMUS_TIMESIGNATURE *pTimeSig)
{
262
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
263 264
	FIXME("(%p, %p): stub\n", This, pTimeSig);
	return S_OK;
265 266
}

267 268 269
static HRESULT WINAPI IDirectMusicStyle8Impl_GetEmbellishmentLength(IDirectMusicStyle8 *iface,
        DWORD dwType, DWORD dwLevel, DWORD *pdwMin, DWORD *pdwMax)
{
270
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
271
	FIXME("(%p, %ld, %ld, %p, %p): stub\n", This, dwType, dwLevel, pdwMin, pdwMax);
Rok Mandeljc's avatar
Rok Mandeljc committed
272
	return S_OK;
273 274
}

275 276
static HRESULT WINAPI IDirectMusicStyle8Impl_GetTempo(IDirectMusicStyle8 *iface, double *pTempo)
{
277
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
Rok Mandeljc's avatar
Rok Mandeljc committed
278 279
	FIXME("(%p, %p): stub\n", This, pTempo);
	return S_OK;
280 281
}

282 283 284
static HRESULT WINAPI IDirectMusicStyle8Impl_EnumPattern(IDirectMusicStyle8 *iface, DWORD dwIndex,
        DWORD dwPatternType, WCHAR *pwszName)
{
285
        IDirectMusicStyle8Impl *This = impl_from_IDirectMusicStyle8(iface);
286
	FIXME("(%p, %ld, %ld, %p): stub\n", This, dwIndex, dwPatternType, pwszName);
Rok Mandeljc's avatar
Rok Mandeljc committed
287
	return S_OK;
288 289
}

290
static const IDirectMusicStyle8Vtbl dmstyle8_vtbl = {
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
    IDirectMusicStyle8Impl_QueryInterface,
    IDirectMusicStyle8Impl_AddRef,
    IDirectMusicStyle8Impl_Release,
    IDirectMusicStyle8Impl_GetBand,
    IDirectMusicStyle8Impl_EnumBand,
    IDirectMusicStyle8Impl_GetDefaultBand,
    IDirectMusicStyle8Impl_EnumMotif,
    IDirectMusicStyle8Impl_GetMotif,
    IDirectMusicStyle8Impl_GetDefaultChordMap,
    IDirectMusicStyle8Impl_EnumChordMap,
    IDirectMusicStyle8Impl_GetChordMap,
    IDirectMusicStyle8Impl_GetTimeSignature,
    IDirectMusicStyle8Impl_GetEmbellishmentLength,
    IDirectMusicStyle8Impl_GetTempo,
    IDirectMusicStyle8Impl_EnumPattern
306
};
307

308
/* IDirectMusicStyle8Impl IDirectMusicObject part: */
309 310
static HRESULT WINAPI style_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface,
        IStream *stream, DMUS_OBJECTDESC *desc)
311
{
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    struct chunk_entry riff = {0};
    HRESULT hr;

    TRACE("(%p, %p, %p)\n", iface, stream, desc);

    if (!stream || !desc)
        return E_POINTER;

    if ((hr = stream_get_chunk(stream, &riff)) != S_OK)
        return hr;
    if (riff.id != FOURCC_RIFF || riff.type != DMUS_FOURCC_STYLE_FORM) {
        TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff));
        stream_skip_chunk(stream, &riff);
        return DMUS_E_CHUNKNOTFOUND;
    }

    hr = dmobj_parsedescriptor(stream, &riff, desc,
            DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_VERSION);
    if (FAILED(hr))
        return hr;

    desc->guidClass = CLSID_DirectMusicStyle;
    desc->dwValidData |= DMUS_OBJ_CLASS;

336
    dump_DMUS_OBJECTDESC(desc);
337
    return S_OK;
338
}
339

340 341 342 343 344 345
static const IDirectMusicObjectVtbl dmobject_vtbl = {
    dmobj_IDirectMusicObject_QueryInterface,
    dmobj_IDirectMusicObject_AddRef,
    dmobj_IDirectMusicObject_Release,
    dmobj_IDirectMusicObject_GetDescriptor,
    dmobj_IDirectMusicObject_SetDescriptor,
346
    style_IDirectMusicObject_ParseDescriptor
347 348 349
};

/* IDirectMusicStyle8Impl IPersistStream part: */
350 351 352
static inline IDirectMusicStyle8Impl *impl_from_IPersistStream(IPersistStream *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicStyle8Impl, dmobj.IPersistStream_iface);
353 354
}

355 356
static HRESULT load_band(IStream *pClonedStream, IDirectMusicBand **ppBand)
{
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
  HRESULT hr = E_FAIL;
  IPersistStream* pPersistStream = NULL;
  
  hr = CoCreateInstance (&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicBand, (LPVOID*) ppBand);
  if (FAILED(hr)) {
    ERR(": could not create object\n");
    return hr;
  }
  /* acquire PersistStream interface */
  hr = IDirectMusicBand_QueryInterface (*ppBand, &IID_IPersistStream, (LPVOID*) &pPersistStream);
  if (FAILED(hr)) {
    ERR(": could not acquire IPersistStream\n");
    return hr;
  }
  /* load */
  hr = IPersistStream_Load (pPersistStream, pClonedStream);
  if (FAILED(hr)) {
    ERR(": failed to load object\n");
    return hr;
  }
  
  /* release all loading-related stuff */
  IPersistStream_Release (pPersistStream);

  return S_OK;
}

384
static HRESULT parse_part_ref_list(DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm,
385
        struct style_motif *pNewMotif)
386
{
387 388 389 390
  HRESULT hr = E_FAIL;
  DMUS_PRIVATE_CHUNK Chunk;
  DWORD ListSize[3], ListCount[3];
  LARGE_INTEGER liMove; /* used when skipping chunks */
391
  struct style_partref_item *pNewItem = NULL;
392

393 394 395 396 397 398 399 400 401 402 403 404

  if (pChunk->fccID != DMUS_FOURCC_PARTREF_LIST) {
    ERR_(dmfile)(": %s chunk should be a PARTREF list\n", debugstr_fourcc (pChunk->fccID));
    return E_FAIL;
  }  

  ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
  ListCount[0] = 0;

  do {
    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
    ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
405
    TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
406 407
    switch (Chunk.fccID) {
    case DMUS_FOURCC_PARTREF_CHUNK: {
408
      TRACE_(dmfile)(": PartRef chunk\n");
409
      pNewItem = heap_alloc_zero(sizeof(*pNewItem));
410
      if (!pNewItem) {
411
	ERR(": no more memory\n");
412
	return E_OUTOFMEMORY;
413 414 415 416
      }
      hr = IStream_Read (pStm, &pNewItem->part_ref, sizeof(DMUS_IO_PARTREF), NULL);
      /*TRACE_(dmfile)(" - sizeof %lu\n",  sizeof(DMUS_IO_PARTREF));*/
      list_add_tail (&pNewMotif->Items, &pNewItem->entry);      
417
      pNewItem->desc.dwSize = sizeof(pNewItem->desc);
418
      break;
419
    }    
420 421 422 423 424 425 426 427 428 429 430
    case FOURCC_LIST: {
      IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
      TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
      ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
      ListCount[1] = 0;
      switch (Chunk.fccID) {  
      case DMUS_FOURCC_UNFO_LIST: { 
	TRACE_(dmfile)(": UNFO list\n");
	do {
	  IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
	  ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
431
          TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
432
	  
433 434 435 436
          if (!pNewItem) {
	    ERR(": pNewItem not yet allocated, chunk order bad?\n");
	    return E_OUTOFMEMORY;
          }
437
	  hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &pNewItem->desc);
438 439 440 441 442
	  if (FAILED(hr)) return hr;
	  
	  if (hr == S_FALSE) {
	    switch (Chunk.fccID) {
	    default: {
443
	      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
444 445 446 447 448 449
	      liMove.QuadPart = Chunk.dwSize;
	      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	      break;				
	    }
	    }
	  }  
450
          TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
451 452 453 454 455 456 457 458 459 460 461 462 463
	} while (ListCount[1] < ListSize[1]);
	break;
      }
      default: {
	TRACE_(dmfile)(": unknown chunk (skipping)\n");
	liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	break;						
      }
      }
      break;
    }
    default: {
464
      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
465 466 467 468 469
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;						
    }
    }
470
    TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
471 472 473 474 475
  } while (ListCount[0] < ListSize[0]);

  return S_OK;
}

476 477
static HRESULT parse_part_list(DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm)
{
478 479 480 481 482 483
  HRESULT hr = E_FAIL;
  DMUS_PRIVATE_CHUNK Chunk;
  DWORD ListSize[3], ListCount[3];
  LARGE_INTEGER liMove; /* used when skipping chunks */

  DMUS_OBJECTDESC desc;
484 485
  DWORD dwSize = 0;
  DWORD cnt = 0;
486 487 488 489 490 491 492 493 494 495 496 497

  if (pChunk->fccID != DMUS_FOURCC_PART_LIST) {
    ERR_(dmfile)(": %s chunk should be a PART list\n", debugstr_fourcc (pChunk->fccID));
    return E_FAIL;
  }  

  ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
  ListCount[0] = 0;

  do {
    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
    ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
498
    TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
499 500
    switch (Chunk.fccID) {
    case DMUS_FOURCC_PART_CHUNK: {
501
      TRACE_(dmfile)(": Part chunk (skipping for now)\n" );
502 503 504 505 506
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_NOTE_CHUNK: { 
507
      TRACE_(dmfile)(": Note chunk (skipping for now)\n");
508 509
      IStream_Read (pStm, &dwSize, sizeof(DWORD), NULL);
      cnt = (Chunk.dwSize - sizeof(DWORD));
510 511
      TRACE_(dmfile)(" - dwSize: %lu\n", dwSize);
      TRACE_(dmfile)(" - cnt: %lu (%lu / %lu)\n", cnt / dwSize, (DWORD)(Chunk.dwSize - sizeof(DWORD)), dwSize);
512
      if (cnt % dwSize != 0) {
513
	ERR("Invalid Array Size\n");
514 515 516 517 518
	return E_FAIL;
      }
      cnt /= dwSize;
      /** skip for now */
      liMove.QuadPart = cnt * dwSize;
519 520 521 522
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_CURVE_CHUNK: { 
523
      TRACE_(dmfile)(": Curve chunk (skipping for now)\n");
524 525
      IStream_Read (pStm, &dwSize, sizeof(DWORD), NULL);
      cnt = (Chunk.dwSize - sizeof(DWORD));
526 527
      TRACE_(dmfile)(" - dwSize: %lu\n", dwSize);
      TRACE_(dmfile)(" - cnt: %lu (%lu / %lu)\n", cnt / dwSize, (DWORD)(Chunk.dwSize - sizeof(DWORD)), dwSize);
528
      if (cnt % dwSize != 0) {
529
	ERR("Invalid Array Size\n");
530 531 532 533 534
	return E_FAIL;
      }
      cnt /= dwSize;
      /** skip for now */
      liMove.QuadPart = cnt * dwSize;
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_MARKER_CHUNK: { 
      TRACE_(dmfile)(": Marker chunk (skipping for now)\n");
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_RESOLUTION_CHUNK: { 
      TRACE_(dmfile)(": Resolution chunk (skipping for now)\n");
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_ANTICIPATION_CHUNK: { 
      TRACE_(dmfile)(": Anticipation chunk (skipping for now)\n");
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case FOURCC_LIST: {
      IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
      TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
      ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
      ListCount[1] = 0;
      switch (Chunk.fccID) { 
      case DMUS_FOURCC_UNFO_LIST: { 
	TRACE_(dmfile)(": UNFO list\n");
	do {
	  IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
	  ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
567
          TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
568 569 570 571 572 573 574
	  
	  hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &desc);
	  if (FAILED(hr)) return hr;
	  
	  if (hr == S_FALSE) {
	    switch (Chunk.fccID) {
	    default: {
575
	      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
576 577 578 579 580 581
	      liMove.QuadPart = Chunk.dwSize;
	      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	      break;				
	    }
	    }
	  }  
582
          TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
583 584 585 586
	} while (ListCount[1] < ListSize[1]);
	break;
      }
      default: {
587
	TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
588 589 590 591 592 593 594 595
	liMove.QuadPart = Chunk.dwSize;
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	break;						
      }
      }
    break;
    }
    default: {
596
      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
597 598 599 600 601
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;						
    }
    }
602
    TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
603 604 605 606 607
  } while (ListCount[0] < ListSize[0]);

  return S_OK;
}

608 609 610
static HRESULT parse_pattern_list(IDirectMusicStyle8Impl *This, DMUS_PRIVATE_CHUNK *pChunk,
        IStream *pStm)
{
611 612 613 614
  HRESULT hr = E_FAIL;
  DMUS_PRIVATE_CHUNK Chunk;
  DWORD ListSize[3], ListCount[3];
  LARGE_INTEGER liMove; /* used when skipping chunks */
615
  IDirectMusicBand* pBand = NULL;
616
  struct style_motif *pNewMotif = NULL;
617 618 619 620 621 622 623 624 625 626 627 628

  if (pChunk->fccID != DMUS_FOURCC_PATTERN_LIST) {
    ERR_(dmfile)(": %s chunk should be a PATTERN list\n", debugstr_fourcc (pChunk->fccID));
    return E_FAIL;
  }  

  ListSize[0] = pChunk->dwSize - sizeof(FOURCC);
  ListCount[0] = 0;

  do {
    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
    ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
629
    TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
630 631 632
    switch (Chunk.fccID) {
    case DMUS_FOURCC_PATTERN_CHUNK: {
      TRACE_(dmfile)(": Pattern chunk\n");
633
      /** alloc new motif entry */
634
      pNewMotif = heap_alloc_zero(sizeof(*pNewMotif));
635 636 637 638
      if (NULL == pNewMotif) {
	ERR(": no more memory\n");
	return  E_OUTOFMEMORY;
      }
639
      list_add_tail(&This->motifs, &pNewMotif->entry);
640 641

      IStream_Read (pStm, &pNewMotif->pattern, Chunk.dwSize, NULL);
642
      /** TODO trace pattern */
643

Austin English's avatar
Austin English committed
644
      /** reset all data, as a new pattern begin */
645
      pNewMotif->desc.dwSize = sizeof(pNewMotif->desc);
646
      list_init (&pNewMotif->Items);
647 648 649
      break;
    }
    case DMUS_FOURCC_RHYTHM_CHUNK: { 
650 651
      TRACE_(dmfile)(": Rhythm chunk\n");
      IStream_Read (pStm, &pNewMotif->dwRhythm, sizeof(DWORD), NULL);
652
      TRACE_(dmfile)(" - dwRhythm: %lu\n", pNewMotif->dwRhythm);
653 654 655 656 657 658
      /** TODO understand why some Chunks have size > 4 */
      liMove.QuadPart = Chunk.dwSize - sizeof(DWORD);
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;
    }
    case DMUS_FOURCC_MOTIFSETTINGS_CHUNK: {
659
      TRACE_(dmfile)(": MotifSettings chunk (skipping for now)\n");
660 661 662 663 664 665
      IStream_Read (pStm, &pNewMotif->settings, Chunk.dwSize, NULL);
      /** TODO trace settings */
      break;
    }
    case FOURCC_RIFF: {
      /**
Austin English's avatar
Austin English committed
666
       * should be embedded Bands into pattern
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
       */
      IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
      TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
      ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
      ListCount[1] = 0;
      switch (Chunk.fccID) {
      case DMUS_FOURCC_BAND_FORM: { 
	LPSTREAM pClonedStream = NULL;
	
	TRACE_(dmfile)(": BAND RIFF\n");
	
	IStream_Clone (pStm, &pClonedStream);
	
	liMove.QuadPart = 0;
	liMove.QuadPart -= sizeof(FOURCC) + (sizeof(FOURCC)+sizeof(DWORD));
	IStream_Seek (pClonedStream, liMove, STREAM_SEEK_CUR, NULL);
683 684

        hr = load_band(pClonedStream, &pBand);
685 686 687 688 689 690 691 692 693
	if (FAILED(hr)) {
	  ERR(": could not load track\n");
	  return hr;
	}
	IStream_Release (pClonedStream);
	
	pNewMotif->pBand = pBand;
	IDirectMusicBand_AddRef(pBand);

Austin English's avatar
Austin English committed
694
	IDirectMusicTrack_Release(pBand); pBand = NULL;  /* now we can release it as it's inserted */
695 696 697 698 699 700 701 702
	
	/** now safe move the cursor */
	liMove.QuadPart = ListSize[1];
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	
	break;
      }
      default: {
703
	TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
704 705 706 707 708
	liMove.QuadPart = ListSize[1];
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	break;
      }
      }
709 710 711 712 713 714 715 716 717 718 719 720 721
      break;
    }
    case FOURCC_LIST: {
      IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
      TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
      ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
      ListCount[1] = 0;
      switch (Chunk.fccID) {
      case DMUS_FOURCC_UNFO_LIST: { 
	TRACE_(dmfile)(": UNFO list\n");
	do {
	  IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
	  ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
722
          TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
723
	  
724
	  hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &pNewMotif->desc);
725 726 727 728 729
	  if (FAILED(hr)) return hr;
	  
	  if (hr == S_FALSE) {
	    switch (Chunk.fccID) {
	    default: {
730
	      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
731 732 733 734 735 736
	      liMove.QuadPart = Chunk.dwSize;
	      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	      break;				
	    }
	    }
	  }  
737
          TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]);
738 739 740 741 742
	} while (ListCount[1] < ListSize[1]);
	break;
      }
      case DMUS_FOURCC_PARTREF_LIST: {
	TRACE_(dmfile)(": PartRef list\n");
743
        hr = parse_part_ref_list(&Chunk, pStm, pNewMotif);
744 745 746 747 748 749 750 751 752 753 754 755 756
	if (FAILED(hr)) return hr;
	break;
      }
      default: {
	TRACE_(dmfile)(": unknown (skipping)\n");
	liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	break;						
      }
      }
      break;	
    }
    default: {
757
      TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
758 759 760 761 762
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
      break;						
    }
    }
763
    TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
764 765 766 767 768
  } while (ListCount[0] < ListSize[0]);

  return S_OK;
}

769 770 771
static HRESULT parse_style_form(IDirectMusicStyle8Impl *This, DMUS_PRIVATE_CHUNK *pChunk,
        IStream *pStm)
{
772 773 774 775 776
  HRESULT hr = E_FAIL;
  DMUS_PRIVATE_CHUNK Chunk;
  DWORD StreamSize, StreamCount, ListSize[3], ListCount[3];
  LARGE_INTEGER liMove; /* used when skipping chunks */

777 778
  IDirectMusicBand* pBand = NULL;

779 780 781 782 783 784 785 786 787 788 789
  if (pChunk->fccID != DMUS_FOURCC_STYLE_FORM) {
    ERR_(dmfile)(": %s chunk should be a STYLE form\n", debugstr_fourcc (pChunk->fccID));
    return E_FAIL;
  }  

  StreamSize = pChunk->dwSize - sizeof(FOURCC);
  StreamCount = 0;

  do {
    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
    StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
790
    TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
791 792

    hr = IDirectMusicUtils_IPersistStream_ParseDescGeneric(&Chunk, pStm, &This->dmobj.desc);
793 794 795 796 797 798 799 800 801 802 803 804 805
    if (FAILED(hr)) return hr;

    if (hr == S_FALSE) {
      switch (Chunk.fccID) {
      case DMUS_FOURCC_STYLE_CHUNK: {
	TRACE_(dmfile)(": Style chunk\n");
	IStream_Read (pStm, &This->style, sizeof(DMUS_IO_STYLE), NULL);
	/** TODO dump DMUS_IO_TIMESIG style.timeSig */
	TRACE_(dmfile)(" - dblTempo: %g\n", This->style.dblTempo);
	break;
      }   
      case FOURCC_RIFF: {
	/**
Austin English's avatar
Austin English committed
806
	 * should be embedded Bands into style
807 808 809 810 811 812
	 */
	IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
	TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
	ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
	ListCount[0] = 0;
	switch (Chunk.fccID) {
813
	case DMUS_FOURCC_BAND_FORM: { 
814
          ULARGE_INTEGER save;
815
          struct style_band *pNewBand;
816

817
	  TRACE_(dmfile)(": BAND RIFF\n");
818 819

          /* Can be application provided IStream without Clone method */
820 821
	  liMove.QuadPart = 0;
	  liMove.QuadPart -= sizeof(FOURCC) + (sizeof(FOURCC)+sizeof(DWORD));
822
          IStream_Seek(pStm, liMove, STREAM_SEEK_CUR, &save);
823

824
          hr = load_band(pStm, &pBand);
825 826 827 828
	  if (FAILED(hr)) {
	    ERR(": could not load track\n");
	    return hr;
	  }
829 830

          pNewBand = heap_alloc_zero(sizeof(*pNewBand));
831 832 833 834 835 836
	  if (NULL == pNewBand) {
	    ERR(": no more memory\n");
	    return  E_OUTOFMEMORY;
	  }
	  pNewBand->pBand = pBand;
	  IDirectMusicBand_AddRef(pBand);
837
	  list_add_tail(&This->bands, &pNewBand->entry);
838

Austin English's avatar
Austin English committed
839
	  IDirectMusicTrack_Release(pBand); pBand = NULL;  /* now we can release it as it's inserted */
840
	
Austin English's avatar
Austin English committed
841
	  /** now safely move the cursor */
842 843 844
          liMove.QuadPart = save.QuadPart - liMove.QuadPart + ListSize[0];
          IStream_Seek(pStm, liMove, STREAM_SEEK_SET, NULL);

845 846 847
	  break;
	}
	default: {
848
	  TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	  liMove.QuadPart = ListSize[0];
	  IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	  break;
	}
	}
	break;
      }
      case FOURCC_LIST: {
	IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
	TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
	ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
	ListCount[0] = 0;
	switch (Chunk.fccID) {
	case DMUS_FOURCC_UNFO_LIST: { 
	  TRACE_(dmfile)(": UNFO list\n");
	  do {
	    IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
	    ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
867
            TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
868 869

            hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &This->dmobj.desc);
870 871 872 873 874
	    if (FAILED(hr)) return hr;
	    
	    if (hr == S_FALSE) {
	      switch (Chunk.fccID) {
	      default: {
875
		TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
876 877 878 879 880 881
		liMove.QuadPart = Chunk.dwSize;
		IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
		break;				
	      }
	      }
	    }  
882
            TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]);
883 884 885 886 887
	  } while (ListCount[0] < ListSize[0]);
	  break;
	}
	case DMUS_FOURCC_PART_LIST: {
	  TRACE_(dmfile)(": PART list\n");
888
          hr = parse_part_list(&Chunk, pStm);
889 890 891 892 893
	  if (FAILED(hr)) return hr;
	  break;
	}
	case  DMUS_FOURCC_PATTERN_LIST: {
	  TRACE_(dmfile)(": PATTERN list\n");
894
          hr = parse_pattern_list(This, &Chunk, pStm);
895 896 897 898 899 900 901 902 903 904 905 906 907
	  if (FAILED(hr)) return hr;
	  break;
	}
	default: {
	  TRACE_(dmfile)(": unknown (skipping)\n");
	  liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
	  IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	  break;						
	}
	}
	break;
      }
      default: {
908
	TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
909 910 911 912 913 914
	liMove.QuadPart = Chunk.dwSize;
	IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
	break;						
      }
      }
    }
915
    TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize);
916 917 918
  } while (StreamCount < StreamSize);  

  return S_OK;
919 920
}

921 922 923
static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pStm)
{
  IDirectMusicStyle8Impl *This = impl_from_IPersistStream(iface);
924 925 926 927 928 929 930
  DMUS_PRIVATE_CHUNK Chunk;
  LARGE_INTEGER liMove; /* used when skipping chunks */
  HRESULT hr;

  FIXME("(%p, %p): Loading\n", This, pStm);

  IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
931
  TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
932 933 934
  switch (Chunk.fccID) {
  case FOURCC_RIFF: {
    IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);
935
    TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
936 937 938
    switch (Chunk.fccID) {
    case DMUS_FOURCC_STYLE_FORM: {
      TRACE_(dmfile)(": Style form\n");
939
      hr = parse_style_form(This, &Chunk, pStm);
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
      if (FAILED(hr)) return hr;
      break;
    }
    default: {
      TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
      liMove.QuadPart = Chunk.dwSize;
      IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
      return E_FAIL;
    }
    }
    TRACE_(dmfile)(": reading finished\n");
    break;
  }
  default: {
    TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
    liMove.QuadPart = Chunk.dwSize;
    IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
    return E_FAIL;
  }
  }
  
  return S_OK;
962 963
}

964 965 966 967 968 969 970 971 972
static const IPersistStreamVtbl persiststream_vtbl = {
    dmobj_IPersistStream_QueryInterface,
    dmobj_IPersistStream_AddRef,
    dmobj_IPersistStream_Release,
    dmobj_IPersistStream_GetClassID,
    unimpl_IPersistStream_IsDirty,
    IPersistStreamImpl_Load,
    unimpl_IPersistStream_Save,
    unimpl_IPersistStream_GetSizeMax
973
};
974 975

/* for ClassFactory */
976 977
HRESULT WINAPI create_dmstyle(REFIID lpcGUID, void **ppobj)
{
978
  IDirectMusicStyle8Impl* obj;
979 980
  HRESULT hr;

981 982
  obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicStyle8Impl));
  if (NULL == obj) {
983
    *ppobj = NULL;
984 985
    return E_OUTOFMEMORY;
  }
986
  obj->IDirectMusicStyle8_iface.lpVtbl = &dmstyle8_vtbl;
987
  obj->ref = 1;
988 989 990
  dmobject_init(&obj->dmobj, &CLSID_DirectMusicStyle, (IUnknown *)&obj->IDirectMusicStyle8_iface);
  obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl;
  obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
991 992
  list_init(&obj->bands);
  list_init(&obj->motifs);
993

994 995 996 997 998
  DMSTYLE_LockModule();
  hr = IDirectMusicStyle8_QueryInterface(&obj->IDirectMusicStyle8_iface, lpcGUID, ppobj);
  IDirectMusicStyle8_Release(&obj->IDirectMusicStyle8_iface);

  return hr;
999
}