- Implement URL_ESCAPE_SEGEMENT_ONLY, URL_ESCAPE_PERCENT,
[wine] / dlls / msacm / stream.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  *      MSACM32 library
5  *
6  *      Copyright 1998  Patrik Stridvall
7  *                1999  Eric Pouech
8  */
9
10 /* TODO
11  *      + asynchronous conversion is not implemented
12  *      + callback/notification
13  *      * acmStreamMessage
14  *      + properly close ACM streams
15  */
16
17 #include <string.h>
18 #include "winbase.h"
19 #include "winerror.h"
20 #include "windef.h"
21 #include "debugtools.h"
22 #include "mmsystem.h"
23 #include "msacm.h"
24 #include "msacmdrv.h"
25 #include "wineacm.h"
26
27 DEFAULT_DEBUG_CHANNEL(msacm);
28     
29 static PWINE_ACMSTREAM  ACM_GetStream(HACMSTREAM has)
30 {
31     return (PWINE_ACMSTREAM)has;
32 }
33
34 /***********************************************************************
35  *           acmStreamClose (MSACM32.@)
36  */
37 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
38 {
39     PWINE_ACMSTREAM     was;
40     MMRESULT            ret;
41                 
42     TRACE("(0x%08x, %ld)\n", has, fdwClose);
43     
44     if ((was = ACM_GetStream(has)) == NULL) {
45         return MMSYSERR_INVALHANDLE;
46     }
47     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
48     if (ret == MMSYSERR_NOERROR) {
49         if (was->hAcmDriver)
50             acmDriverClose(was->hAcmDriver, 0L);        
51         HeapFree(MSACM_hHeap, 0, was);
52     }
53     TRACE("=> (%d)\n", ret);
54     return ret;
55 }
56
57 /***********************************************************************
58  *           acmStreamConvert (MSACM32.@)
59  */
60 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, 
61                                  DWORD fdwConvert)
62 {
63     PWINE_ACMSTREAM     was;
64     MMRESULT            ret = MMSYSERR_NOERROR;
65     PACMDRVSTREAMHEADER padsh;
66
67     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
68     
69     if ((was = ACM_GetStream(has)) == NULL)
70         return MMSYSERR_INVALHANDLE;
71     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
72         return MMSYSERR_INVALPARAM;
73
74     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
75         return ACMERR_UNPREPARED;
76
77     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
78      * size. some fields are private to msacm internals, and are exposed
79      * in ACMSTREAMHEADER in the dwReservedDriver array
80      */
81     padsh = (PACMDRVSTREAMHEADER)pash;
82
83     /* check that pointers have not been modified */
84     if (padsh->pbPreparedSrc != padsh->pbSrc ||
85         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
86         padsh->pbPreparedDst != padsh->pbDst ||
87         padsh->cbPreparedDstLength < padsh->cbDstLength) {
88         return MMSYSERR_INVALPARAM;
89     }   
90
91     padsh->fdwConvert = fdwConvert;
92
93     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
94     if (ret == MMSYSERR_NOERROR) {
95         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
96     }
97     TRACE("=> (%d)\n", ret);
98     return ret;
99 }
100
101 /***********************************************************************
102  *           acmStreamMessage (MSACM32.@)
103  */
104 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1, 
105                                  LPARAM lParam2)
106 {
107     FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
108     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
109     return MMSYSERR_ERROR;
110 }
111
112 /***********************************************************************
113  *           acmStreamOpen (MSACM32.@)
114  */
115 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
116                               PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
117                               DWORD dwInstance, DWORD fdwOpen)
118 {
119     PWINE_ACMSTREAM     was;
120     PWINE_ACMDRIVER     wad;
121     MMRESULT            ret;
122     int                 wfxSrcSize;
123     int                 wfxDstSize;
124     
125     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
126           phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
127
128     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
129           pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, 
130           pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
131
132     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
133           pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, 
134           pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
135
136     if ((fdwOpen & ACM_STREAMOPENF_QUERY) && phas) return MMSYSERR_INVALPARAM;
137     if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) return MMSYSERR_INVALPARAM;
138
139     wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
140     if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
141     if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
142
143     was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + 
144                     ((pwfltr) ? sizeof(WAVEFILTER) : 0));
145     if (was == NULL)
146         return MMSYSERR_NOMEM;
147     
148     was->drvInst.cbStruct = sizeof(was->drvInst);
149     was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
150     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
151     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
152     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
153     if (pwfltr) {
154         was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
155         memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
156     } else {
157         was->drvInst.pwfltr = NULL;
158     }
159     was->drvInst.dwCallback = dwCallback;    
160     was->drvInst.dwInstance = dwInstance;
161     was->drvInst.fdwOpen = fdwOpen;
162     was->drvInst.fdwDriver = 0L;  
163     was->drvInst.dwDriver = 0L;     
164     /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
165     was->drvInst.has = 0L;
166     
167     if (had) {
168         if (!(wad = MSACM_GetDriver(had))) {
169             ret = MMSYSERR_INVALPARAM;
170             goto errCleanUp;
171         }
172         
173         was->obj.dwType = WINE_ACMOBJ_STREAM;
174         was->obj.pACMDriverID = wad->obj.pACMDriverID;
175         was->pDrv = wad;
176         was->hAcmDriver = 0; /* not to close it in acmStreamClose */
177
178         ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
179         if (ret != MMSYSERR_NOERROR)
180             goto errCleanUp;
181     } else {
182         PWINE_ACMDRIVERID wadi;
183         
184         ret = ACMERR_NOTPOSSIBLE;
185         for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
186             if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) || 
187                 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
188                 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
189                 continue;
190             ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
191             if (ret != MMSYSERR_NOERROR)
192                 continue;
193             if ((wad = MSACM_GetDriver(had)) != 0) {
194                 was->obj.dwType = WINE_ACMOBJ_STREAM;
195                 was->obj.pACMDriverID = wad->obj.pACMDriverID;
196                 was->pDrv = wad;
197                 was->hAcmDriver = had;
198                 
199                 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
200                 TRACE("%s => %08x\n", wadi->pszDriverAlias, ret);
201                 if (ret == MMSYSERR_NOERROR) {
202                     if (fdwOpen & ACM_STREAMOPENF_QUERY) {
203                         acmDriverClose(had, 0L);
204                     }
205                     break;
206                 }
207             }
208             /* no match, close this acm driver and try next one */
209             acmDriverClose(had, 0L);
210         }
211         if (ret != MMSYSERR_NOERROR) {
212             ret = ACMERR_NOTPOSSIBLE;
213             goto errCleanUp;
214         }
215     }
216     ret = MMSYSERR_NOERROR;
217     was->drvInst.has = (HACMSTREAM)was;
218     if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
219         if (phas)
220             *phas = (HACMSTREAM)was;
221         TRACE("=> (%d)\n", ret);
222         return ret;
223     }
224 errCleanUp:             
225     if (phas)
226         *phas = (HACMSTREAM)0;
227     HeapFree(MSACM_hHeap, 0, was);
228     TRACE("=> (%d)\n", ret);
229     return ret;
230 }
231
232
233 /***********************************************************************
234  *           acmStreamPrepareHeader (MSACM32.@)
235  */
236 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
237                                        DWORD fdwPrepare)
238 {
239     PWINE_ACMSTREAM     was;
240     MMRESULT            ret = MMSYSERR_NOERROR;
241     PACMDRVSTREAMHEADER padsh;
242
243     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
244     
245     if ((was = ACM_GetStream(has)) == NULL)
246         return MMSYSERR_INVALHANDLE;
247     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
248         return MMSYSERR_INVALPARAM;
249     if (fdwPrepare)
250         ret = MMSYSERR_INVALFLAG;
251
252     if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
253         return MMSYSERR_NOERROR;
254
255     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
256      * size. some fields are private to msacm internals, and are exposed
257      * in ACMSTREAMHEADER in the dwReservedDriver array
258      */
259     padsh = (PACMDRVSTREAMHEADER)pash;
260
261     padsh->fdwConvert = fdwPrepare;
262     padsh->padshNext = NULL;
263     padsh->fdwDriver = padsh->dwDriver = 0L;
264
265     padsh->fdwPrepared = 0;
266     padsh->dwPrepared = 0;
267     padsh->pbPreparedSrc = 0;
268     padsh->cbPreparedSrcLength = 0;
269     padsh->pbPreparedDst = 0;
270     padsh->cbPreparedDstLength = 0;
271
272     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
273     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
274         ret = MMSYSERR_NOERROR;
275         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
276         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
277         padsh->fdwPrepared = padsh->fdwStatus;
278         padsh->dwPrepared = 0;
279         padsh->pbPreparedSrc = padsh->pbSrc;
280         padsh->cbPreparedSrcLength = padsh->cbSrcLength;
281         padsh->pbPreparedDst = padsh->pbDst;
282         padsh->cbPreparedDstLength = padsh->cbDstLength;
283     } else {
284         padsh->fdwPrepared = 0;
285         padsh->dwPrepared = 0;
286         padsh->pbPreparedSrc = 0;
287         padsh->cbPreparedSrcLength = 0;
288         padsh->pbPreparedDst = 0;
289         padsh->cbPreparedDstLength = 0;
290     }
291     TRACE("=> (%d)\n", ret);
292     return ret;
293 }
294
295 /***********************************************************************
296  *           acmStreamReset (MSACM32.@)
297  */
298 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
299 {
300     PWINE_ACMSTREAM     was;
301     MMRESULT            ret = MMSYSERR_NOERROR;
302
303     TRACE("(0x%08x, %ld)\n", has, fdwReset);
304
305     if (fdwReset) {
306         ret = MMSYSERR_INVALFLAG;
307     } else if ((was = ACM_GetStream(has)) == NULL) {
308         return MMSYSERR_INVALHANDLE;
309     } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
310         ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
311     }
312     TRACE("=> (%d)\n", ret);
313     return ret;
314 }
315
316 /***********************************************************************
317  *           acmStreamSize (MSACM32.@)
318  */
319 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, 
320                               LPDWORD pdwOutputBytes, DWORD fdwSize)
321 {
322     PWINE_ACMSTREAM     was;
323     ACMDRVSTREAMSIZE    adss;
324     MMRESULT            ret;
325     
326     TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
327     
328     if ((was = ACM_GetStream(has)) == NULL) {
329         return MMSYSERR_INVALHANDLE;
330     }
331     if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
332         return MMSYSERR_INVALFLAG;
333     }
334
335     *pdwOutputBytes = 0L;
336     
337     switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
338     case ACM_STREAMSIZEF_DESTINATION:
339         adss.cbDstLength = cbInput;
340         adss.cbSrcLength = 0;
341         break;
342     case ACM_STREAMSIZEF_SOURCE:
343         adss.cbSrcLength = cbInput;
344         adss.cbDstLength = 0;
345         break;
346     default:    
347         return MMSYSERR_INVALFLAG;
348     }
349     
350     adss.cbStruct = sizeof(adss);
351     adss.fdwSize = fdwSize;
352     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, 
353                             (DWORD)&was->drvInst, (DWORD)&adss);
354     if (ret == MMSYSERR_NOERROR) {
355         switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
356         case ACM_STREAMSIZEF_DESTINATION:
357             *pdwOutputBytes = adss.cbSrcLength;
358             break;
359         case ACM_STREAMSIZEF_SOURCE:
360             *pdwOutputBytes = adss.cbDstLength;
361             break;
362         }
363     }
364     TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
365     return ret;
366 }
367
368 /***********************************************************************
369  *           acmStreamUnprepareHeader (MSACM32.@)
370  */
371 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
372                                          DWORD fdwUnprepare)
373 {
374     PWINE_ACMSTREAM     was;
375     MMRESULT            ret = MMSYSERR_NOERROR;
376     PACMDRVSTREAMHEADER padsh;
377
378     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
379     
380     if ((was = ACM_GetStream(has)) == NULL)
381         return MMSYSERR_INVALHANDLE;
382     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
383         return MMSYSERR_INVALPARAM;
384
385     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
386         return ACMERR_UNPREPARED;
387
388     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
389      * size. some fields are private to msacm internals, and are exposed
390      * in ACMSTREAMHEADER in the dwReservedDriver array
391      */
392     padsh = (PACMDRVSTREAMHEADER)pash;
393
394     /* check that pointers have not been modified */
395     if (padsh->pbPreparedSrc != padsh->pbSrc ||
396         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
397         padsh->pbPreparedDst != padsh->pbDst ||
398         padsh->cbPreparedDstLength < padsh->cbDstLength) {
399         return MMSYSERR_INVALPARAM;
400     }   
401
402     padsh->fdwConvert = fdwUnprepare;
403
404     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
405     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
406         ret = MMSYSERR_NOERROR;
407         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
408     }
409     TRACE("=> (%d)\n", ret);
410     return ret;
411 }