wininet: Use return value of sprintf() instead of calling strlen() and simplify code.
[wine.git] / dlls / msacm32 / stream.c
blob6e81151e550dfc0e132b74825cf699f4ad86358f
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 /* TODO
25 * + asynchronous conversion is not implemented
26 * + callback/notification
27 * * acmStreamMessage
28 * + properly close ACM streams
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "wine/debug.h"
37 #include "mmsystem.h"
38 #define NOBITMAP
39 #include "mmreg.h"
40 #include "msacm.h"
41 #include "msacmdrv.h"
42 #include "wineacm.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
46 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
48 TRACE("(%p)\n", has);
50 return (PWINE_ACMSTREAM)has;
53 static BOOL ACM_ValidatePointers(PACMDRVSTREAMHEADER padsh)
55 /* check that pointers have not been modified */
56 return !(padsh->pbPreparedSrc != padsh->pbSrc ||
57 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
58 padsh->pbPreparedDst != padsh->pbDst ||
59 padsh->cbPreparedDstLength < padsh->cbDstLength);
62 /***********************************************************************
63 * acmStreamClose (MSACM32.@)
65 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
67 PWINE_ACMSTREAM was;
68 MMRESULT ret;
70 TRACE("(%p, %d)\n", has, fdwClose);
72 if ((was = ACM_GetStream(has)) == NULL) {
73 WARN("invalid handle\n");
74 return MMSYSERR_INVALHANDLE;
76 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_CLOSE, (LPARAM)&was->drvInst, 0);
77 if (ret == MMSYSERR_NOERROR) {
78 if (was->hAcmDriver)
79 acmDriverClose(was->hAcmDriver, 0L);
80 HeapFree(MSACM_hHeap, 0, was);
82 TRACE("=> (%d)\n", ret);
83 return ret;
86 /***********************************************************************
87 * acmStreamConvert (MSACM32.@)
89 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
90 DWORD fdwConvert)
92 PWINE_ACMSTREAM was;
93 MMRESULT ret = MMSYSERR_NOERROR;
94 PACMDRVSTREAMHEADER padsh;
96 TRACE("(%p, %p, %d)\n", has, pash, fdwConvert);
98 if ((was = ACM_GetStream(has)) == NULL) {
99 WARN("invalid handle\n");
100 return MMSYSERR_INVALHANDLE;
102 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
103 WARN("invalid parameter\n");
104 return MMSYSERR_INVALPARAM;
106 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
107 WARN("unprepared header\n");
108 return ACMERR_UNPREPARED;
111 pash->cbSrcLengthUsed = 0;
112 pash->cbDstLengthUsed = 0;
114 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
115 * size. some fields are private to msacm internals, and are exposed
116 * in ACMSTREAMHEADER in the dwReservedDriver array
118 padsh = (PACMDRVSTREAMHEADER)pash;
120 if (!ACM_ValidatePointers(padsh)) {
121 WARN("invalid parameter\n");
122 return MMSYSERR_INVALPARAM;
125 padsh->fdwConvert = fdwConvert;
127 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_CONVERT, (LPARAM)&was->drvInst, (LPARAM)padsh);
128 if (ret == MMSYSERR_NOERROR) {
129 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
131 TRACE("=> (%d)\n", ret);
132 return ret;
135 /***********************************************************************
136 * acmStreamMessage (MSACM32.@)
138 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
139 LPARAM lParam2)
141 FIXME("(%p, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
142 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
143 return MMSYSERR_ERROR;
146 /***********************************************************************
147 * acmStreamOpen (MSACM32.@)
149 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had,
150 PWAVEFORMATEX pwfxSrc, PWAVEFORMATEX pwfxDst,
151 PWAVEFILTER pwfltr, DWORD_PTR dwCallback,
152 DWORD_PTR dwInstance, DWORD fdwOpen)
154 PWINE_ACMSTREAM was;
155 PWINE_ACMDRIVER wad;
156 MMRESULT ret;
157 int wfxSrcSize;
158 int wfxDstSize;
159 WAVEFORMATEX wfxSrc, wfxDst;
161 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %d)\n",
162 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
164 /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
165 * WAVEFORMATEX so don't use them directly when not sure */
166 if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) {
167 memcpy(&wfxSrc, pwfxSrc, sizeof(PCMWAVEFORMAT));
168 wfxSrc.wBitsPerSample = pwfxSrc->wBitsPerSample;
169 wfxSrc.cbSize = 0;
170 pwfxSrc = &wfxSrc;
173 if (pwfxDst->wFormatTag == WAVE_FORMAT_PCM) {
174 memcpy(&wfxDst, pwfxDst, sizeof(PCMWAVEFORMAT));
175 wfxDst.wBitsPerSample = pwfxDst->wBitsPerSample;
176 wfxDst.cbSize = 0;
177 pwfxDst = &wfxDst;
180 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
181 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
182 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
184 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
185 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
186 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
188 /* (WS) In query mode, phas should be NULL. If it is not, then instead
189 * of returning an error we are making sure it is NULL, preventing some
190 * applications that pass garbage for phas from crashing.
192 if (fdwOpen & ACM_STREAMOPENF_QUERY) phas = NULL;
194 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) {
195 WARN("invalid parameter\n");
196 return MMSYSERR_INVALPARAM;
199 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
200 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
201 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
203 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize +
204 ((pwfltr) ? sizeof(WAVEFILTER) : 0));
205 if (was == NULL) {
206 WARN("no memory\n");
207 return MMSYSERR_NOMEM;
210 was->drvInst.cbStruct = sizeof(was->drvInst);
211 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
212 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
213 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
214 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
215 if (pwfltr) {
216 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
217 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
218 } else {
219 was->drvInst.pwfltr = NULL;
221 was->drvInst.dwCallback = dwCallback;
222 was->drvInst.dwInstance = dwInstance;
223 was->drvInst.fdwOpen = fdwOpen;
224 was->drvInst.fdwDriver = 0L;
225 was->drvInst.dwDriver = 0L;
226 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
227 was->drvInst.has = 0L;
229 if (had) {
230 if (!(wad = MSACM_GetDriver(had))) {
231 ret = MMSYSERR_INVALPARAM;
232 goto errCleanUp;
235 was->obj.dwType = WINE_ACMOBJ_STREAM;
236 was->obj.pACMDriverID = wad->obj.pACMDriverID;
237 was->pDrv = wad;
238 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
240 ret = MSACM_Message((HACMDRIVER)wad, ACMDM_STREAM_OPEN, (LPARAM)&was->drvInst, 0L);
241 if (ret != MMSYSERR_NOERROR)
242 goto errCleanUp;
243 } else {
244 PWINE_ACMDRIVERID wadi;
246 ret = ACMERR_NOTPOSSIBLE;
247 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
248 if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
249 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
250 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
251 continue;
252 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
253 if (ret != MMSYSERR_NOERROR)
254 continue;
255 if ((wad = MSACM_GetDriver(had)) != 0) {
256 was->obj.dwType = WINE_ACMOBJ_STREAM;
257 was->obj.pACMDriverID = wad->obj.pACMDriverID;
258 was->pDrv = wad;
259 was->hAcmDriver = had;
261 ret = MSACM_Message((HACMDRIVER)wad, ACMDM_STREAM_OPEN, (LPARAM)&was->drvInst, 0L);
262 TRACE("%s => %08x\n", debugstr_w(wadi->pszDriverAlias), ret);
263 if (ret == MMSYSERR_NOERROR) {
264 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
265 MSACM_Message((HACMDRIVER)wad, ACMDM_STREAM_CLOSE, (LPARAM)&was->drvInst, 0);
266 acmDriverClose(had, 0L);
268 break;
271 /* no match, close this acm driver and try next one */
272 acmDriverClose(had, 0L);
274 if (ret != MMSYSERR_NOERROR) {
275 ret = ACMERR_NOTPOSSIBLE;
276 goto errCleanUp;
279 ret = MMSYSERR_NOERROR;
280 was->drvInst.has = (HACMSTREAM)was;
281 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
282 if (phas)
283 *phas = (HACMSTREAM)was;
284 TRACE("=> (%d)\n", ret);
285 return ret;
287 errCleanUp:
288 if (phas)
289 *phas = NULL;
290 HeapFree(MSACM_hHeap, 0, was);
291 TRACE("=> (%d)\n", ret);
292 return ret;
296 /***********************************************************************
297 * acmStreamPrepareHeader (MSACM32.@)
299 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
300 DWORD fdwPrepare)
302 PWINE_ACMSTREAM was;
303 MMRESULT ret = MMSYSERR_NOERROR;
304 PACMDRVSTREAMHEADER padsh;
306 TRACE("(%p, %p, %d)\n", has, pash, fdwPrepare);
308 if ((was = ACM_GetStream(has)) == NULL) {
309 WARN("invalid handle\n");
310 return MMSYSERR_INVALHANDLE;
312 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
313 WARN("invalid parameter\n");
314 return MMSYSERR_INVALPARAM;
316 if (fdwPrepare) {
317 WARN("invalid use of reserved parameter\n");
318 return MMSYSERR_INVALFLAG;
320 if (pash->cbSrcLength < was->drvInst.pwfxSrc->nBlockAlign) {
321 WARN("source smaller than block align (%d < %d)\n",
322 pash->cbSrcLength, was->drvInst.pwfxSrc->nBlockAlign);
323 return pash->cbSrcLength ? ACMERR_NOTPOSSIBLE : MMSYSERR_INVALPARAM;
326 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
327 * size. some fields are private to msacm internals, and are exposed
328 * in ACMSTREAMHEADER in the dwReservedDriver array
330 padsh = (PACMDRVSTREAMHEADER)pash;
332 padsh->fdwConvert = fdwPrepare;
333 padsh->padshNext = NULL;
334 padsh->fdwDriver = padsh->dwDriver = 0L;
336 padsh->fdwPrepared = 0;
337 padsh->dwPrepared = 0;
338 padsh->pbPreparedSrc = 0;
339 padsh->cbPreparedSrcLength = 0;
340 padsh->pbPreparedDst = 0;
341 padsh->cbPreparedDstLength = 0;
343 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_PREPARE, (LPARAM)&was->drvInst, (LPARAM)padsh);
344 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
345 ret = MMSYSERR_NOERROR;
346 padsh->fdwStatus &= ~ACMSTREAMHEADER_STATUSF_INQUEUE;
347 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
348 padsh->fdwPrepared = padsh->fdwStatus;
349 padsh->dwPrepared = 0;
350 padsh->pbPreparedSrc = padsh->pbSrc;
351 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
352 padsh->pbPreparedDst = padsh->pbDst;
353 padsh->cbPreparedDstLength = padsh->cbDstLength;
354 } else {
355 padsh->fdwPrepared = 0;
356 padsh->dwPrepared = 0;
357 padsh->pbPreparedSrc = 0;
358 padsh->cbPreparedSrcLength = 0;
359 padsh->pbPreparedDst = 0;
360 padsh->cbPreparedDstLength = 0;
362 TRACE("=> (%d)\n", ret);
363 return ret;
366 /***********************************************************************
367 * acmStreamReset (MSACM32.@)
369 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
371 PWINE_ACMSTREAM was;
372 MMRESULT ret = MMSYSERR_NOERROR;
374 TRACE("(%p, %d)\n", has, fdwReset);
376 if (fdwReset) {
377 WARN("invalid flag\n");
378 ret = MMSYSERR_INVALFLAG;
379 } else if ((was = ACM_GetStream(has)) == NULL) {
380 WARN("invalid handle\n");
381 return MMSYSERR_INVALHANDLE;
382 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
383 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_RESET, (LPARAM)&was->drvInst, 0);
385 TRACE("=> (%d)\n", ret);
386 return ret;
389 /***********************************************************************
390 * acmStreamSize (MSACM32.@)
392 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
393 LPDWORD pdwOutputBytes, DWORD fdwSize)
395 PWINE_ACMSTREAM was;
396 ACMDRVSTREAMSIZE adss;
397 MMRESULT ret;
399 TRACE("(%p, %d, %p, %d)\n", has, cbInput, pdwOutputBytes, fdwSize);
401 if ((was = ACM_GetStream(has)) == NULL) {
402 WARN("invalid handle\n");
403 return MMSYSERR_INVALHANDLE;
405 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
406 WARN("invalid flag\n");
407 return MMSYSERR_INVALFLAG;
410 *pdwOutputBytes = 0L;
412 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
413 case ACM_STREAMSIZEF_DESTINATION:
414 adss.cbDstLength = cbInput;
415 adss.cbSrcLength = 0;
416 break;
417 case ACM_STREAMSIZEF_SOURCE:
418 adss.cbSrcLength = cbInput;
419 adss.cbDstLength = 0;
420 break;
421 default:
422 WARN("invalid flag\n");
423 return MMSYSERR_INVALFLAG;
426 adss.cbStruct = sizeof(adss);
427 adss.fdwSize = fdwSize;
428 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_SIZE,
429 (LPARAM)&was->drvInst, (LPARAM)&adss);
430 if (ret == MMSYSERR_NOERROR) {
431 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
432 case ACM_STREAMSIZEF_DESTINATION:
433 *pdwOutputBytes = adss.cbSrcLength;
434 break;
435 case ACM_STREAMSIZEF_SOURCE:
436 *pdwOutputBytes = adss.cbDstLength;
437 break;
440 TRACE("=> (%d) [%u]\n", ret, *pdwOutputBytes);
441 return ret;
444 /***********************************************************************
445 * acmStreamUnprepareHeader (MSACM32.@)
447 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
448 DWORD fdwUnprepare)
450 PWINE_ACMSTREAM was;
451 MMRESULT ret = MMSYSERR_NOERROR;
452 PACMDRVSTREAMHEADER padsh;
454 TRACE("(%p, %p, %d)\n", has, pash, fdwUnprepare);
456 if ((was = ACM_GetStream(has)) == NULL) {
457 WARN("invalid handle\n");
458 return MMSYSERR_INVALHANDLE;
460 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
461 WARN("invalid parameter\n");
462 return MMSYSERR_INVALPARAM;
464 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
465 WARN("unprepared header\n");
466 return ACMERR_UNPREPARED;
469 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
470 * size. some fields are private to msacm internals, and are exposed
471 * in ACMSTREAMHEADER in the dwReservedDriver array
473 padsh = (PACMDRVSTREAMHEADER)pash;
475 if (!ACM_ValidatePointers(padsh)) {
476 WARN("invalid parameter\n");
477 return MMSYSERR_INVALPARAM;
480 padsh->fdwConvert = fdwUnprepare;
482 ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_UNPREPARE, (LPARAM)&was->drvInst, (LPARAM)padsh);
483 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
484 ret = MMSYSERR_NOERROR;
485 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
487 TRACE("=> (%d)\n", ret);
488 return ret;