windowscodecs: Implement JpegEncoder_CreateNewFrame.
[wine] / dlls / dmusic / instrument.c
1 /* IDirectMusicInstrument Implementation
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "dmusic_private.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
23
24 static const GUID IID_IDirectMusicInstrumentPRIVATE = {0xbcb20080,0xa40c,0x11d1,{0x86,0xbc,0x00,0xc0,0x4f,0xbf,0x8f,0xef}};
25
26 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface);
27 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface);
28
29 /* IDirectMusicInstrument IUnknown part: */
30 static HRESULT WINAPI IDirectMusicInstrumentImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
31         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
32         TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
33         
34         if (IsEqualIID (riid, &IID_IUnknown)) {
35                 *ppobj = &This->UnknownVtbl;
36                 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
37                 return S_OK;    
38         } else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
39                 *ppobj = &This->InstrumentVtbl;
40                 IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
41                 return S_OK;
42         } else if (IsEqualIID (riid, &IID_IDirectMusicInstrumentPRIVATE)) {     
43                 /* it seems to me that this interface is only basic IUnknown, without any
44                         other inherited functions... *sigh* this is the worst scenario, since it means 
45                         that whoever calls it knows the layout of original implementation table and therefore
46                         tries to get data by direct access... expect crashes */
47                 FIXME("*sigh*... requested private/unspecified interface\n");
48                 *ppobj = &This->UnknownVtbl;
49                 IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
50                 return S_OK;    
51         }
52         
53         WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
54         return E_NOINTERFACE;
55 }
56
57 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface) {
58         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
59         ULONG refCount = InterlockedIncrement(&This->ref);
60
61         TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
62
63         DMUSIC_LockModule();
64
65         return refCount;
66 }
67
68 static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
69         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
70         ULONG refCount = InterlockedDecrement(&This->ref);
71
72         TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
73
74         if (!refCount) {
75                 HeapFree(GetProcessHeap(), 0, This);
76         }
77
78         DMUSIC_UnlockModule();
79         
80         return refCount;
81 }
82
83 static const IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
84         IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
85         IDirectMusicInstrumentImpl_IUnknown_AddRef,
86         IDirectMusicInstrumentImpl_IUnknown_Release
87 };
88
89 /* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
90 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
91         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
92         return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
93 }
94
95 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
96         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
97         return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
98 }
99
100 static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
101         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
102         return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
103 }
104
105 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
106         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
107         TRACE("(%p, %p)\n", This, pdwPatch);    
108         *pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
109         return S_OK;
110 }
111
112 static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
113         ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
114         TRACE("(%p, %d): stub\n", This, dwPatch);
115         Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
116         return S_OK;
117 }
118
119 static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
120         IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
121         IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
122         IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
123         IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
124         IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
125 };
126
127 /* for ClassFactory */
128 HRESULT WINAPI DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
129         IDirectMusicInstrumentImpl* dminst;
130         
131         dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
132         if (NULL == dminst) {
133                 *ppobj = NULL;
134                 return E_OUTOFMEMORY;
135         }
136         dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
137         dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
138         dminst->ref = 0; /* will be inited by QueryInterface */
139         
140         return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
141 }
142
143 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
144 {
145     ULONG readed;
146     HRESULT hr;
147
148     hr = IStream_Read(stream, data, size, &readed);
149     if(FAILED(hr)){
150         TRACE("IStream_Read failed: %08x\n", hr);
151         return hr;
152     }
153     if(readed < size){
154         TRACE("Didn't read full chunk: %u < %u\n", readed, size);
155         return E_FAIL;
156     }
157
158     return S_OK;
159 }
160
161 static inline DWORD subtract_bytes(DWORD len, DWORD bytes)
162 {
163     if(bytes > len){
164         TRACE("Apparent mismatch in chunk lengths? %u bytes remaining, %u bytes read\n", len, bytes);
165         return 0;
166     }
167     return len - bytes;
168 }
169
170 static HRESULT load_instrument(IDirectMusicInstrumentImpl *This, IStream *stream, DWORD length)
171 {
172     HRESULT hr;
173     FOURCC fourcc;
174     DWORD bytes;
175     LARGE_INTEGER move;
176
177     while(length){
178         hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
179         if(FAILED(hr))
180             return hr;
181
182         hr = read_from_stream(stream, &bytes, sizeof(bytes));
183         if(FAILED(hr))
184             return hr;
185
186         length = subtract_bytes(length, sizeof(fourcc) + sizeof(bytes));
187
188         switch(fourcc){
189         case FOURCC_INSH:
190             TRACE("INSH chunk: %u bytes\n", bytes);
191             hr = read_from_stream(stream, This->pHeader, sizeof(*This->pHeader));
192             if(FAILED(hr))
193                 return hr;
194
195             move.QuadPart = bytes - sizeof(*This->pHeader);
196             hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
197             if(FAILED(hr)){
198                 WARN("IStream_Seek failed: %08x\n", hr);
199                 return hr;
200             }
201
202             length = subtract_bytes(length, bytes);
203             break;
204
205         case FOURCC_DLID:
206             TRACE("DLID chunk: %u bytes\n", bytes);
207             hr = read_from_stream(stream, This->pInstrumentID, sizeof(*This->pInstrumentID));
208             if(FAILED(hr))
209                 return hr;
210
211             move.QuadPart = bytes - sizeof(*This->pInstrumentID);
212             hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
213             if(FAILED(hr)){
214                 WARN("IStream_Seek failed: %08x\n", hr);
215                 return hr;
216             }
217
218             length = subtract_bytes(length, bytes);
219             break;
220
221         default:
222             TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(fourcc), bytes);
223
224             move.QuadPart = bytes;
225             hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
226             if(FAILED(hr)){
227                 WARN("IStream_Seek failed: %08x\n", hr);
228                 return hr;
229             }
230
231             length = subtract_bytes(length, bytes);
232             break;
233         }
234     }
235
236     return S_OK;
237 }
238
239 /* aux. function that completely loads instrument; my tests indicate that it's 
240    called somewhere around IDirectMusicCollection_GetInstrument */
241 HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM stream)
242 {
243     ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
244     LARGE_INTEGER move;
245     FOURCC fourcc;
246     DWORD bytes;
247     HRESULT hr;
248
249     TRACE("(%p, %p, offset = %s)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart));
250
251     hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
252     if(FAILED(hr)){
253         WARN("IStream_Seek failed: %08x\n", hr);
254         goto load_failure;
255     }
256
257     hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
258     if(FAILED(hr))
259         goto load_failure;
260
261     if(fourcc != FOURCC_LIST){
262         WARN("Loading failed: Expected LIST chunk, got: %s\n", debugstr_fourcc(fourcc));
263         goto load_failure;
264     }
265
266     hr = read_from_stream(stream, &bytes, sizeof(bytes));
267     if(FAILED(hr))
268         goto load_failure;
269
270     TRACE("LIST chunk: %u bytes\n", bytes);
271     while(1){
272         hr = read_from_stream(stream, &fourcc, sizeof(fourcc));
273         if(FAILED(hr))
274             goto load_failure;
275
276         switch(fourcc){
277         case FOURCC_INS:
278             TRACE("INS  chunk: (no byte count)\n");
279             hr = load_instrument(This, stream, bytes - sizeof(FOURCC));
280             if(FAILED(hr))
281                 goto load_failure;
282             break;
283
284         default:
285             hr = read_from_stream(stream, &bytes, sizeof(bytes));
286             if(FAILED(hr))
287                 goto load_failure;
288
289             TRACE("Unknown chunk %s: %u bytes\n", debugstr_fourcc(fourcc), bytes);
290
291             move.QuadPart = bytes;
292             hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL);
293             if(FAILED(hr)){
294                 WARN("IStream_Seek failed: %08x\n", hr);
295                 return hr;
296             }
297
298             break;
299         }
300     }
301
302     return S_OK;
303
304 load_failure:
305     return DMUS_E_UNSUPPORTED_STREAM;
306 }