~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/avifil32/wavfile.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright 2002 Michael Günnewig
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the Free Software
 16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 17  */
 18 
 19 #include <assert.h>
 20 #include <stdarg.h>
 21 
 22 #include "windef.h"
 23 #include "winbase.h"
 24 #include "wingdi.h"
 25 #include "winuser.h"
 26 #include "winnls.h"
 27 #include "winerror.h"
 28 #include "mmsystem.h"
 29 #include "vfw.h"
 30 #include "msacm.h"
 31 
 32 #include "avifile_private.h"
 33 #include "extrachunk.h"
 34 
 35 #include "wine/unicode.h"
 36 #include "wine/debug.h"
 37 
 38 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
 39 
 40 /***********************************************************************/
 41 
 42 #define formtypeWAVE    mmioFOURCC('W','A','V','E')
 43 #define ckidWAVEFORMAT  mmioFOURCC('f','m','t',' ')
 44 #define ckidWAVEFACT    mmioFOURCC('f','a','c','t')
 45 #define ckidWAVEDATA    mmioFOURCC('d','a','t','a')
 46 
 47 /***********************************************************************/
 48 
 49 #define ENDIAN_SWAPWORD(x)  ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
 50 #define ENDIAN_SWAPDWORD(x) (ENDIAN_SWAPWORD((x >> 16) & 0xFFFF) | \
 51                              ENDIAN_SWAPWORD(x & 0xFFFF) << 16)
 52 
 53 #ifdef WORDS_BIGENDIAN
 54 #define BE2H_WORD(x)  (x)
 55 #define BE2H_DWORD(x) (x)
 56 #define LE2H_WORD(x)  ENDIAN_SWAPWORD(x)
 57 #define LE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
 58 #else
 59 #define BE2H_WORD(x)  ENDIAN_SWAPWORD(x)
 60 #define BE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
 61 #define LE2H_WORD(x)  (x)
 62 #define LE2H_DWORD(x) (x)
 63 #endif
 64 
 65 typedef struct {
 66   FOURCC  fccType;
 67   DWORD   offset;
 68   DWORD   size;
 69   INT     encoding;
 70   DWORD   sampleRate;
 71   DWORD   channels;
 72 } SUNAUDIOHEADER;
 73 
 74 #define AU_ENCODING_ULAW_8                 1
 75 #define AU_ENCODING_PCM_8                  2
 76 #define AU_ENCODING_PCM_16                 3
 77 #define AU_ENCODING_PCM_24                 4
 78 #define AU_ENCODING_PCM_32                 5
 79 #define AU_ENCODING_FLOAT                  6
 80 #define AU_ENCODING_DOUBLE                 7
 81 #define AU_ENCODING_ADPCM_G721_32         23
 82 #define AU_ENCODING_ADPCM_G722            24
 83 #define AU_ENCODING_ADPCM_G723_24         25
 84 #define AU_ENCODING_ADPCM_G723_5          26
 85 #define AU_ENCODING_ALAW_8                27
 86 
 87 /***********************************************************************/
 88 
 89 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
 90 static ULONG   WINAPI IAVIFile_fnAddRef(IAVIFile* iface);
 91 static ULONG   WINAPI IAVIFile_fnRelease(IAVIFile* iface);
 92 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
 93 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
 94 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
 95 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
 96 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
 97 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface);
 98 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
 99 
100 static const struct IAVIFileVtbl iwavft = {
101   IAVIFile_fnQueryInterface,
102   IAVIFile_fnAddRef,
103   IAVIFile_fnRelease,
104   IAVIFile_fnInfo,
105   IAVIFile_fnGetStream,
106   IAVIFile_fnCreateStream,
107   IAVIFile_fnWriteData,
108   IAVIFile_fnReadData,
109   IAVIFile_fnEndRecord,
110   IAVIFile_fnDeleteStream
111 };
112 
113 static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile*iface,REFIID refiid,LPVOID*obj);
114 static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile*iface);
115 static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile*iface);
116 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile*iface,CLSID*pClassID);
117 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile*iface);
118 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile*iface,LPCOLESTR pszFileName,DWORD dwMode);
119 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile*iface,LPCOLESTR pszFileName,BOOL fRemember);
120 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile*iface,LPCOLESTR pszFileName);
121 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile*iface,LPOLESTR*ppszFileName);
122 
123 static const struct IPersistFileVtbl iwavpft = {
124   IPersistFile_fnQueryInterface,
125   IPersistFile_fnAddRef,
126   IPersistFile_fnRelease,
127   IPersistFile_fnGetClassID,
128   IPersistFile_fnIsDirty,
129   IPersistFile_fnLoad,
130   IPersistFile_fnSave,
131   IPersistFile_fnSaveCompleted,
132   IPersistFile_fnGetCurFile
133 };
134 
135 static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
136 static ULONG   WINAPI IAVIStream_fnAddRef(IAVIStream*iface);
137 static ULONG   WINAPI IAVIStream_fnRelease(IAVIStream* iface);
138 static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
139 static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
140 static LONG    WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
141 static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
142 static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
143 static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
144 static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
145 static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
146 static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
147 static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
148 static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
149 
150 static const struct IAVIStreamVtbl iwavst = {
151   IAVIStream_fnQueryInterface,
152   IAVIStream_fnAddRef,
153   IAVIStream_fnRelease,
154   IAVIStream_fnCreate,
155   IAVIStream_fnInfo,
156   IAVIStream_fnFindSample,
157   IAVIStream_fnReadFormat,
158   IAVIStream_fnSetFormat,
159   IAVIStream_fnRead,
160   IAVIStream_fnWrite,
161   IAVIStream_fnDelete,
162   IAVIStream_fnReadData,
163   IAVIStream_fnWriteData,
164   IAVIStream_fnSetInfo
165 };
166 
167 typedef struct _IAVIFileImpl IAVIFileImpl;
168 
169 typedef struct _IPersistFileImpl {
170   /* IUnknown stuff */
171   const IPersistFileVtbl *lpVtbl;
172 
173   /* IPersistFile stuff */
174   IAVIFileImpl     *paf;
175 } IPersistFileImpl;
176 
177 typedef struct _IAVIStreamImpl {
178   /* IUnknown stuff */
179   const IAVIStreamVtbl *lpVtbl;
180 
181   /* IAVIStream stuff */
182   IAVIFileImpl     *paf;
183 } IAVIStreamImpl;
184 
185 struct _IAVIFileImpl {
186   /* IUnknown stuff */
187   const IAVIFileVtbl *lpVtbl;
188   LONG              ref;
189 
190   /* IAVIFile, IAVIStream stuff... */
191   IPersistFileImpl  iPersistFile;
192   IAVIStreamImpl    iAVIStream;
193 
194   AVIFILEINFOW      fInfo;
195   AVISTREAMINFOW    sInfo;
196 
197   LPWAVEFORMATEX    lpFormat;
198   LONG              cbFormat;
199 
200   MMCKINFO          ckData;
201 
202   EXTRACHUNKS       extra;
203 
204   /* IPersistFile stuff ... */
205   HMMIO             hmmio;
206   LPWSTR            szFileName;
207   UINT              uMode;
208   BOOL              fDirty;
209 };
210 
211 /***********************************************************************/
212 
213 static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
214 static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This);
215 static HRESULT AVIFILE_SaveFile(const IAVIFileImpl *This);
216 
217 HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppv)
218 {
219   IAVIFileImpl *pfile;
220   HRESULT       hr;
221 
222   assert(riid != NULL && ppv != NULL);
223 
224   *ppv = NULL;
225 
226   pfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIFileImpl));
227   if (pfile == NULL)
228     return AVIERR_MEMORY;
229 
230   pfile->lpVtbl                = &iwavft;
231   pfile->iPersistFile.lpVtbl   = &iwavpft;
232   pfile->iAVIStream.lpVtbl     = &iwavst;
233   pfile->ref = 0;
234   pfile->iPersistFile.paf = pfile;
235   pfile->iAVIStream.paf   = pfile;
236 
237   hr = IAVIFile_QueryInterface((IAVIFile*)pfile, riid, ppv);
238   if (FAILED(hr))
239     HeapFree(GetProcessHeap(), 0, pfile);
240 
241   return hr;
242 }
243 
244 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
245                                                 LPVOID *obj)
246 {
247   IAVIFileImpl *This = (IAVIFileImpl *)iface;
248 
249   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
250 
251   if (IsEqualGUID(&IID_IUnknown, refiid) ||
252       IsEqualGUID(&IID_IAVIFile, refiid)) {
253     *obj = iface;
254     return S_OK;
255   } else if (This->fInfo.dwStreams == 1 &&
256              IsEqualGUID(&IID_IAVIStream, refiid)) {
257     *obj = &This->iAVIStream;
258     return S_OK;
259   } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
260     *obj = &This->iPersistFile;
261     return S_OK;
262   }
263 
264   return OLE_E_ENUM_NOMORE;
265 }
266 
267 static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
268 {
269   IAVIFileImpl *This = (IAVIFileImpl *)iface;
270 
271   TRACE("(%p)\n",iface);
272 
273   return InterlockedIncrement(&This->ref);
274 }
275 
276 static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
277 {
278   IAVIFileImpl *This = (IAVIFileImpl *)iface;
279   ULONG ref = InterlockedDecrement(&This->ref);
280 
281   TRACE("(%p)\n",iface);
282 
283   if (!ref) {
284     if (This->fDirty) {
285       /* need to write headers to file */
286       AVIFILE_SaveFile(This);
287     }
288 
289     if (This->lpFormat != NULL) {
290       HeapFree(GetProcessHeap(), 0, This->lpFormat);
291       This->lpFormat = NULL;
292       This->cbFormat = 0;
293     }
294     if (This->extra.lp != NULL) {
295       HeapFree(GetProcessHeap(), 0, This->extra.lp);
296       This->extra.lp = NULL;
297       This->extra.cb = 0;
298     }
299     HeapFree(GetProcessHeap(), 0, This->szFileName);
300     This->szFileName = NULL;
301     if (This->hmmio != NULL) {
302       mmioClose(This->hmmio, 0);
303       This->hmmio = NULL;
304     }
305 
306     HeapFree(GetProcessHeap(), 0, This);
307     return 0;
308   }
309   return ref;
310 }
311 
312 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, LPAVIFILEINFOW afi,
313                                       LONG size)
314 {
315   IAVIFileImpl *This = (IAVIFileImpl *)iface;
316 
317   TRACE("(%p,%p,%d)\n",iface,afi,size);
318 
319   if (afi == NULL)
320     return AVIERR_BADPARAM;
321   if (size < 0)
322     return AVIERR_BADSIZE;
323 
324   /* update file info */
325   This->fInfo.dwFlags = 0;
326   This->fInfo.dwCaps  = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
327   if (This->lpFormat != NULL) {
328     assert(This->sInfo.dwScale != 0);
329 
330     This->fInfo.dwStreams             = 1;
331     This->fInfo.dwScale               = This->sInfo.dwScale;
332     This->fInfo.dwRate                = This->sInfo.dwRate;
333     This->fInfo.dwLength              = This->sInfo.dwLength;
334     This->fInfo.dwSuggestedBufferSize = This->ckData.cksize;
335     This->fInfo.dwMaxBytesPerSec =
336       MulDiv(This->sInfo.dwSampleSize,This->sInfo.dwRate,This->sInfo.dwScale);
337   }
338 
339   memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
340 
341   if ((DWORD)size < sizeof(This->fInfo))
342     return AVIERR_BUFFERTOOSMALL;
343   return AVIERR_OK;
344 }
345 
346 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
347                                            DWORD fccType, LONG lParam)
348 {
349   IAVIFileImpl *This = (IAVIFileImpl *)iface;
350 
351   TRACE("(%p,%p,0x%08X,%d)\n", iface, avis, fccType, lParam);
352 
353   /* check parameter */
354   if (avis == NULL)
355     return AVIERR_BADPARAM;
356 
357   *avis = NULL;
358 
359   /* Does our stream exists? */
360   if (lParam != 0 || This->fInfo.dwStreams == 0)
361     return AVIERR_NODATA;
362   if (fccType != 0 && fccType != streamtypeAUDIO)
363     return AVIERR_NODATA;
364 
365   *avis = (PAVISTREAM)&This->iAVIStream;
366   IAVIFile_AddRef(iface);
367 
368   return AVIERR_OK;
369 }
370 
371 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
372                                               LPAVISTREAMINFOW asi)
373 {
374   IAVIFileImpl *This = (IAVIFileImpl *)iface;
375 
376   TRACE("(%p,%p,%p)\n", iface, avis, asi);
377 
378   /* check parameters */
379   if (avis == NULL || asi == NULL)
380     return AVIERR_BADPARAM;
381 
382   *avis = NULL;
383 
384   /* We only support one audio stream */
385   if (This->fInfo.dwStreams != 0 || This->lpFormat != NULL)
386     return AVIERR_UNSUPPORTED;
387   if (asi->fccType != streamtypeAUDIO)
388     return AVIERR_UNSUPPORTED;
389 
390   /* Does the user have write permission? */
391   if ((This->uMode & MMIO_RWMODE) == 0)
392     return AVIERR_READONLY;
393 
394   This->cbFormat = 0;
395   This->lpFormat = NULL;
396 
397   memcpy(&This->sInfo, asi, sizeof(This->sInfo));
398 
399   /* make sure streaminfo if okay for us */
400   This->sInfo.fccHandler          = 0;
401   This->sInfo.dwFlags             = 0;
402   This->sInfo.dwCaps              = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
403   This->sInfo.dwStart             = 0;
404   This->sInfo.dwInitialFrames     = 0;
405   This->sInfo.dwFormatChangeCount = 0;
406   memset(&This->sInfo.rcFrame, 0, sizeof(This->sInfo.rcFrame));
407 
408   This->fInfo.dwStreams = 1;
409   This->fInfo.dwScale   = This->sInfo.dwScale;
410   This->fInfo.dwRate    = This->sInfo.dwRate;
411   This->fInfo.dwLength  = This->sInfo.dwLength;
412 
413   This->ckData.dwDataOffset = 0;
414   This->ckData.cksize       = 0;
415 
416   *avis = (PAVISTREAM)&This->iAVIStream;
417   IAVIFile_AddRef(iface);
418 
419   return AVIERR_OK;
420 }
421 
422 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
423                                            LPVOID lpData, LONG size)
424 {
425   IAVIFileImpl *This = (IAVIFileImpl *)iface;
426 
427   TRACE("(%p,0x%08X,%p,%d)\n", iface, ckid, lpData, size);
428 
429   /* check parameters */
430   if (lpData == NULL)
431     return AVIERR_BADPARAM;
432   if (size < 0)
433     return AVIERR_BADSIZE;
434 
435   /* Do we have write permission? */
436   if ((This->uMode & MMIO_RWMODE) == 0)
437     return AVIERR_READONLY;
438 
439   This->fDirty = TRUE;
440 
441   return WriteExtraChunk(&This->extra, ckid, lpData, size);
442 }
443 
444 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
445                                           LPVOID lpData, LONG *size)
446 {
447   IAVIFileImpl *This = (IAVIFileImpl *)iface;
448 
449   TRACE("(%p,0x%08X,%p,%p)\n", iface, ckid, lpData, size);
450 
451   return ReadExtraChunk(&This->extra, ckid, lpData, size);
452 }
453 
454 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
455 {
456   TRACE("(%p)\n",iface);
457 
458   /* This is only needed for interleaved files.
459    * We have only one stream, which can't be interleaved.
460    */
461   return AVIERR_OK;
462 }
463 
464 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
465                                               LONG lParam)
466 {
467   IAVIFileImpl *This = (IAVIFileImpl *)iface;
468 
469   TRACE("(%p,0x%08X,%d)\n", iface, fccType, lParam);
470 
471   /* check parameter */
472   if (lParam < 0)
473     return AVIERR_BADPARAM;
474 
475   /* Do we have our audio stream? */
476   if (lParam != 0 || This->fInfo.dwStreams == 0 ||
477       (fccType != 0 && fccType != streamtypeAUDIO))
478     return AVIERR_NODATA;
479 
480   /* Have user write permissions? */
481   if ((This->uMode & MMIO_RWMODE) == 0)
482     return AVIERR_READONLY;
483 
484   HeapFree(GetProcessHeap(), 0, This->lpFormat);
485   This->lpFormat = NULL;
486   This->cbFormat = 0;
487 
488   /* update infos */
489   This->ckData.dwDataOffset = 0;
490   This->ckData.cksize       = 0;
491 
492   This->sInfo.dwScale   = 0;
493   This->sInfo.dwRate    = 0;
494   This->sInfo.dwLength  = 0;
495   This->sInfo.dwSuggestedBufferSize = 0;
496 
497   This->fInfo.dwStreams = 0;
498   This->fInfo.dwEditCount++;
499 
500   This->fDirty = TRUE;
501 
502   return AVIERR_OK;
503 }
504 
505 /***********************************************************************/
506 
507 static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface,
508                                                     REFIID refiid, LPVOID *obj)
509 {
510   IPersistFileImpl *This = (IPersistFileImpl *)iface;
511 
512   assert(This->paf != NULL);
513 
514   return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
515 }
516 
517 static ULONG   WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
518 {
519   IPersistFileImpl *This = (IPersistFileImpl *)iface;
520 
521   assert(This->paf != NULL);
522 
523   return IAVIFile_AddRef((PAVIFILE)This->paf);
524 }
525 
526 static ULONG   WINAPI IPersistFile_fnRelease(IPersistFile *iface)
527 {
528   IPersistFileImpl *This = (IPersistFileImpl *)iface;
529 
530   assert(This->paf != NULL);
531 
532   return IAVIFile_Release((PAVIFILE)This->paf);
533 }
534 
535 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
536                                                 LPCLSID pClassID)
537 {
538   TRACE("(%p,%p)\n", iface, pClassID);
539 
540   if (pClassID == NULL)
541     return AVIERR_BADPARAM;
542 
543   *pClassID = CLSID_WAVFile;
544 
545   return AVIERR_OK;
546 }
547 
548 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
549 {
550   IPersistFileImpl *This = (IPersistFileImpl *)iface;
551 
552   TRACE("(%p)\n", iface);
553 
554   assert(This->paf != NULL);
555 
556   return (This->paf->fDirty ? S_OK : S_FALSE);
557 }
558 
559 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface,
560                                           LPCOLESTR pszFileName, DWORD dwMode)
561 {
562   IAVIFileImpl *This = ((IPersistFileImpl*)iface)->paf;
563 
564   WCHAR wszStreamFmt[50];
565   INT   len;
566 
567   TRACE("(%p,%s,0x%08X)\n", iface, debugstr_w(pszFileName), dwMode);
568 
569   /* check parameter */
570   if (pszFileName == NULL)
571     return AVIERR_BADPARAM;
572 
573   assert(This != NULL);
574   if (This->hmmio != NULL)
575     return AVIERR_ERROR; /* No reuse of this object for another file! */
576 
577   /* remember mode and name */
578   This->uMode = dwMode;
579 
580   len = lstrlenW(pszFileName) + 1;
581   This->szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
582   if (This->szFileName == NULL)
583     return AVIERR_MEMORY;
584   lstrcpyW(This->szFileName, pszFileName);
585 
586   /* try to open the file */
587   This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
588   if (This->hmmio == NULL) {
589     /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
590     LPSTR szFileName;
591     len = WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1,
592                               NULL, 0, NULL, NULL);
593     szFileName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR));
594     if (szFileName == NULL)
595       return AVIERR_MEMORY;
596 
597     WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, szFileName,
598                         len, NULL, NULL);
599 
600     This->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
601     HeapFree(GetProcessHeap(), 0, szFileName);
602     if (This->hmmio == NULL)
603       return AVIERR_FILEOPEN;
604   }
605 
606   memset(& This->fInfo, 0, sizeof(This->fInfo));
607   memset(& This->sInfo, 0, sizeof(This->sInfo));
608 
609   LoadStringW(AVIFILE_hModule, IDS_WAVEFILETYPE, This->fInfo.szFileType,
610               sizeof(This->fInfo.szFileType)/sizeof(This->fInfo.szFileType[0]));
611   if (LoadStringW(AVIFILE_hModule, IDS_WAVESTREAMFORMAT,
612                   wszStreamFmt, sizeof(wszStreamFmt)/sizeof(wszStreamFmt[0])) > 0) {
613     wsprintfW(This->sInfo.szName, wszStreamFmt,
614               AVIFILE_BasenameW(This->szFileName));
615   }
616 
617   /* should we create a new file? */
618   if (dwMode & OF_CREATE) {
619     /* nothing more to do */
620     return AVIERR_OK;
621   } else
622     return AVIFILE_LoadFile(This);
623 }
624 
625 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
626                                           LPCOLESTR pszFileName,BOOL fRemember)
627 {
628   TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
629 
630   /* We write directly to disk, so nothing to do. */
631 
632   return AVIERR_OK;
633 }
634 
635 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
636                                                    LPCOLESTR pszFileName)
637 {
638   TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
639 
640   /* We write directly to disk, so nothing to do. */
641 
642   return AVIERR_OK;
643 }
644 
645 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface,
646                                                 LPOLESTR *ppszFileName)
647 {
648   IPersistFileImpl *This = (IPersistFileImpl *)iface;
649 
650   TRACE("(%p,%p)\n", iface, ppszFileName);
651 
652   if (ppszFileName == NULL)
653     return AVIERR_BADPARAM;
654 
655   *ppszFileName = NULL;
656 
657   assert(This->paf != NULL);
658 
659   if (This->paf->szFileName != NULL) {
660     int len = lstrlenW(This->paf->szFileName) + 1;
661 
662     *ppszFileName = CoTaskMemAlloc(len * sizeof(WCHAR));
663     if (*ppszFileName == NULL)
664       return AVIERR_MEMORY;
665 
666     strcpyW(*ppszFileName, This->paf->szFileName);
667   }
668 
669   return AVIERR_OK;
670 }
671 
672 /***********************************************************************/
673 
674 static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface,
675                                                   REFIID refiid, LPVOID *obj)
676 {
677   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
678 
679   assert(This->paf != NULL);
680 
681   return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
682 }
683 
684 static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
685 {
686   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
687 
688   assert(This->paf != NULL);
689 
690   return IAVIFile_AddRef((PAVIFILE)This->paf);
691 }
692 
693 static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
694 {
695   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
696 
697   assert(This->paf != NULL);
698 
699   return IAVIFile_Release((PAVIFILE)This->paf);
700 }
701 
702 static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
703                                           LPARAM lParam2)
704 {
705   TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
706 
707   /* This IAVIStream interface needs an WAVFile */
708   return AVIERR_UNSUPPORTED;
709 }
710 
711 static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
712                                         LONG size)
713 {
714   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
715 
716   TRACE("(%p,%p,%d)\n", iface, psi, size);
717 
718   if (psi == NULL)
719     return AVIERR_BADPARAM;
720   if (size < 0)
721     return AVIERR_BADSIZE;
722 
723   memcpy(psi, &This->paf->sInfo, min((DWORD)size, sizeof(This->paf->sInfo)));
724 
725   if ((DWORD)size < sizeof(This->paf->sInfo))
726     return AVIERR_BUFFERTOOSMALL;
727   return AVIERR_OK;
728 }
729 
730 static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
731                                            LONG flags)
732 {
733   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
734 
735   TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
736 
737   /* Do we have data? */
738   if (This->lpFormat == NULL)
739     return -1;
740 
741   /* We don't have an index */
742   if (flags & FIND_INDEX)
743     return -1;
744 
745   if (flags & FIND_FROM_START) {
746     pos = This->sInfo.dwStart;
747     flags &= ~(FIND_FROM_START|FIND_PREV);
748     flags |= FIND_NEXT;
749   }
750 
751   if (flags & FIND_FORMAT) {
752     if ((flags & FIND_NEXT) && pos > 0)
753       pos = -1;
754     else
755       pos = 0;
756   }
757 
758   if ((flags & FIND_RET) == FIND_LENGTH ||
759       (flags & FIND_RET) == FIND_SIZE)
760     return This->sInfo.dwSampleSize;
761   if ((flags & FIND_RET) == FIND_OFFSET)
762     return This->ckData.dwDataOffset + pos * This->sInfo.dwSampleSize;
763 
764   return pos;
765 }
766 
767 static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
768                                               LPVOID format, LONG *formatsize)
769 {
770   IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
771 
772   TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
773 
774   if (formatsize == NULL)
775     return AVIERR_BADPARAM;
776 
777   /* only interested in needed buffersize? */
778   if (format == NULL || *formatsize <= 0) {
779     *formatsize = This->paf->cbFormat;
780 
781     return AVIERR_OK;
782   }
783 
784   /* copy initial format (only as much as will fit) */
785   memcpy(format, This->paf->lpFormat, min(*formatsize, This->paf->cbFormat));
786   if (*formatsize < This->paf->cbFormat) {
787     *formatsize = This->paf->cbFormat;
788     return AVIERR_BUFFERTOOSMALL;
789   }
790 
791   *formatsize = This->paf->cbFormat;
792   return AVIERR_OK;
793 }
794 
795 static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
796                                              LPVOID format, LONG formatsize)
797 {
798   IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
799 
800   TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
801 
802   /* check parameters */
803   if (format == NULL || formatsize <= sizeof(PCMWAVEFORMAT))
804     return AVIERR_BADPARAM;
805 
806   /* We can only do this to an empty wave file, but ignore call
807    * if still same format */
808   if (This->lpFormat != NULL) {
809     if (formatsize != This->cbFormat ||
810         memcmp(format, This->lpFormat, formatsize) != 0)
811       return AVIERR_UNSUPPORTED;
812 
813     return AVIERR_OK;
814   }
815 
816   /* only support start at position 0 */
817   if (pos != 0)
818     return AVIERR_UNSUPPORTED;
819 
820   /* Do we have write permission? */
821   if ((This->uMode & MMIO_RWMODE) == 0)
822     return AVIERR_READONLY;
823 
824   /* get memory for format and copy it */
825   This->lpFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
826   if (This->lpFormat == NULL)
827     return AVIERR_MEMORY;
828 
829   This->cbFormat = formatsize;
830   memcpy(This->lpFormat, format, formatsize);
831 
832   /* update info's about 'data' chunk */
833   This->ckData.dwDataOffset = formatsize + 7 * sizeof(DWORD);
834   This->ckData.cksize       = 0;
835 
836   /* for non-pcm format we need also a 'fact' chunk */
837   if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM)
838     This->ckData.dwDataOffset += 3 * sizeof(DWORD);
839 
840   /* update stream and file info */
841   This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
842   This->sInfo.dwScale      = This->lpFormat->nBlockAlign;
843   This->sInfo.dwRate       = This->lpFormat->nAvgBytesPerSec;
844   This->sInfo.dwLength     = 0;
845   This->sInfo.dwSuggestedBufferSize = 0;
846 
847   return AVIERR_OK;
848 }
849 
850 static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,