Move OpenQuery into msiquery.c and make it non-static.
[wine] / dlls / avifil32 / editstream.c
1 /*
2  * Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define COM_NO_WINDOWS_H
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
27 #include "winnls.h"
28 #include "winerror.h"
29 #include "windowsx.h"
30 #include "mmsystem.h"
31 #include "vfw.h"
32
33 #include "avifile_private.h"
34 #include "extrachunk.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
39
40 /***********************************************************************/
41
42 /* internal interface to get access to table of stream in an editable stream */
43 typedef struct IEditStreamInternal IEditStreamInternal;
44
45 typedef struct _EditStreamTable {
46   PAVISTREAM pStream;  /* stream which contains the data */
47   DWORD      dwStart;  /* where starts the part which is also our */
48   DWORD      dwLength; /* how many is also in this stream */
49 } EditStreamTable;
50
51 #define INTERFACE IEditStreamInternal
52 DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
53 {
54     /*** IUnknown methods ***/
55     STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
56     STDMETHOD_(ULONG,AddRef)(THIS) PURE;
57     STDMETHOD_(ULONG,Release)(THIS) PURE;
58     /*** IEditStreamInternal methods ***/
59     STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
60 };
61 #undef INTERFACE
62
63 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
64                                       (This)->pStreams[streamNr].dwLength)
65
66 /***********************************************************************/
67
68 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
69 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
70 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
71 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
72                                            LONG*plLength,PAVISTREAM*ppResult);
73 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
74                                             LONG*plLength,PAVISTREAM*ppResult);
75 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
76                                              LONG*plLength,PAVISTREAM pSource,
77                                              LONG lStart,LONG lEnd);
78 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
79                                              PAVISTREAM*ppResult);
80 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
81                                                LPAVISTREAMINFOW asi,LONG size);
82
83 struct IAVIEditStreamVtbl ieditstream = {
84   IAVIEditStream_fnQueryInterface,
85   IAVIEditStream_fnAddRef,
86   IAVIEditStream_fnRelease,
87   IAVIEditStream_fnCut,
88   IAVIEditStream_fnCopy,
89   IAVIEditStream_fnPaste,
90   IAVIEditStream_fnClone,
91   IAVIEditStream_fnSetInfo
92 };
93
94 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
95 static ULONG   WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
96 static ULONG   WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
97 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
98 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
99 static LONG    WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
100                                                   LONG flags);
101 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
102 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
103 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
104                                             LONG samples,LPVOID buffer,
105                                             LONG buffersize,LONG*bytesread,
106                                             LONG*samplesread);
107 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
108                                              LONG samples,LPVOID buffer,
109                                              LONG buffersize,DWORD flags,
110                                              LONG*sampwritten,LONG*byteswritten);
111 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
112 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
113                                                 LPVOID lp,LONG *lpread);
114 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
115                                                  LPVOID lp,LONG size);
116 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
117
118 struct IAVIStreamVtbl ieditstast = {
119   IEditAVIStream_fnQueryInterface,
120   IEditAVIStream_fnAddRef,
121   IEditAVIStream_fnRelease,
122   IEditAVIStream_fnCreate,
123   IEditAVIStream_fnInfo,
124   IEditAVIStream_fnFindSample,
125   IEditAVIStream_fnReadFormat,
126   IEditAVIStream_fnSetFormat,
127   IEditAVIStream_fnRead,
128   IEditAVIStream_fnWrite,
129   IEditAVIStream_fnDelete,
130   IEditAVIStream_fnReadData,
131   IEditAVIStream_fnWriteData,
132   IEditAVIStream_fnSetInfo
133 };
134
135 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
136 static ULONG   WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
137 static ULONG   WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
138 static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
139
140 struct IEditStreamInternalVtbl ieditstreaminternal = {
141   IEditStreamInternal_fnQueryInterface,
142   IEditStreamInternal_fnAddRef,
143   IEditStreamInternal_fnRelease,
144   IEditStreamInternal_fnGetEditStreamImpl
145 };
146
147 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
148
149 typedef struct _IEditAVIStreamImpl {
150   /* IUnknown stuff */
151   IAVIStreamVtbl *lpVtbl;
152
153   /* IAVIStream stuff */
154   IAVIEditStreamImpl *pae;
155 } IEditAVIStreamImpl;
156
157 typedef struct _IEditStreamInternalImpl {
158   /* IUnknown stuff */
159   IEditStreamInternalVtbl *lpVtbl;
160
161   /* IEditStreamInternal stuff */
162   IAVIEditStreamImpl *pae;
163 } IEditStreamInternalImpl;
164
165 struct _IAVIEditStreamImpl {
166   /* IUnknown stuff */
167   IAVIEditStreamVtbl *lpVtbl;
168   DWORD  ref;
169
170   /* IAVIEditStream stuff */
171   IEditAVIStreamImpl      iAVIStream;
172   IEditStreamInternalImpl iEditStreamInternal;
173
174   AVISTREAMINFOW       sInfo;
175
176   EditStreamTable     *pStreams;
177   DWORD                nStreams;   /* current fill level of pStreams table */
178   DWORD                nTableSize; /* size of pStreams table */
179
180   BOOL                 bDecompress;
181   PAVISTREAM           pCurStream;
182   PGETFRAME            pg;         /* IGetFrame for pCurStream */
183   LPBITMAPINFOHEADER   lpFrame;    /* frame of pCurStream */
184 };
185
186 /***********************************************************************/
187
188 PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
189 {
190   IAVIEditStreamImpl *pedit = NULL;
191
192   pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl));
193   if (pedit == NULL)
194     return NULL;
195
196   pedit->lpVtbl            = &ieditstream;
197   pedit->iAVIStream.lpVtbl = &ieditstast;
198   pedit->iAVIStream.pae    = pedit;
199   pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
200   pedit->iEditStreamInternal.pae    = pedit;
201   pedit->ref = 1;
202
203   IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
204
205   return (PAVIEDITSTREAM)pedit;
206 }
207
208 static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
209                                          DWORD pos,PAVISTREAM *ppStream,
210                                          DWORD* streamPos,
211                                          DWORD* streamNr,BOOL bFindSample)
212 {
213   DWORD n;
214
215   TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
216         streamNr,bFindSample);
217
218   if (pos < This->sInfo.dwStart)
219     return AVIERR_BADPARAM;
220
221   pos -= This->sInfo.dwStart;
222   for (n = 0; n < This->nStreams; n++) {
223     if (pos < This->pStreams[n].dwLength) {
224       *ppStream  = This->pStreams[n].pStream;
225       *streamPos = This->pStreams[n].dwStart + pos;
226       if (streamNr != NULL)
227         *streamNr = n;
228
229       return AVIERR_OK;
230     }
231     pos -= This->pStreams[n].dwLength;
232   }
233   if (pos == 0 && bFindSample) {
234     *ppStream  = This->pStreams[--n].pStream;
235     *streamPos = EditStreamEnd(This, n);
236     if (streamNr != NULL)
237       *streamNr = n;
238
239     TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
240     return AVIERR_OK;
241   } else {
242     *ppStream = NULL;
243     *streamPos = 0;
244     if (streamNr != NULL)
245       *streamNr = 0;
246
247     TRACE(" -> ERROR (NULL,0,0)\n");
248     return AVIERR_BADPARAM;
249   }
250 }
251
252 static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
253                                 PAVISTREAM pstream, LONG pos)
254 {
255   PGETFRAME pg;
256
257   TRACE("(%p,%p,%ld)\n",This,pstream,pos);
258
259   if (pstream == NULL)
260     return NULL;
261
262   /* if stream changes make sure that only palette changes */
263   if (This->pCurStream != pstream) {
264     pg = AVIStreamGetFrameOpen(pstream, NULL);
265     if (pg == NULL)
266       return NULL;
267     if (This->pg != NULL) {
268       if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
269         AVIStreamGetFrameClose(pg);
270         ERR(": IGetFrame_SetFormat failed\n");
271         return NULL;
272       }
273       AVIStreamGetFrameClose(This->pg);
274     }
275     This->pg         = pg;
276     This->pCurStream = pstream;
277   }
278
279   /* now get the decompressed frame */
280   This->lpFrame = AVIStreamGetFrame(This->pg, pos);
281   if (This->lpFrame != NULL)
282     This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
283
284   return This->lpFrame;
285 }
286
287 static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
288 {
289   assert(This != NULL);
290   assert(nr < This->nStreams);
291
292   /* remove part nr */
293   IAVIStream_Release(This->pStreams[nr].pStream);
294   This->nStreams--;
295   if (This->nStreams - nr > 0) {
296     memmove(This->pStreams + nr, This->pStreams + nr + 1,
297             (This->nStreams - nr) * sizeof(EditStreamTable));
298   }
299   This->pStreams[This->nStreams].pStream  = NULL;
300   This->pStreams[This->nStreams].dwStart  = 0;
301   This->pStreams[This->nStreams].dwLength = 0;
302
303   /* try to merge the part before the deleted one and the one after it */
304   if (0 < nr && 0 < This->nStreams &&
305       This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
306     if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
307       This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
308       return AVIFILE_RemoveStream(This, nr);
309     }
310   }
311
312   return AVIERR_OK;
313 }
314
315 static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
316 {
317   LPVOID fmt1 = NULL, fmt2 = NULL;
318   LONG size1, size2, start1, start2;
319   BOOL status = FALSE;
320
321   assert(avi1 != NULL && avi2 != NULL);
322
323   /* get stream starts and check format sizes */
324   start1 = AVIStreamStart(avi1);
325   start2 = AVIStreamStart(avi2);
326   if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
327     return FALSE;
328   if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
329     return FALSE;
330   if (size1 != size2)
331     return FALSE;
332
333   /* sizes match, now get formats and compare them */
334   fmt1 = GlobalAllocPtr(GHND, size1);
335   if (fmt1 == NULL)
336     return FALSE;
337   if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
338     fmt2 = GlobalAllocPtr(GHND, size1);
339     if (fmt2 != NULL) {
340       if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
341         status = (memcmp(fmt1, fmt2, size1) == 0);
342     }
343   }
344
345   if (fmt2 != NULL)
346     GlobalFreePtr(fmt2);
347   GlobalFreePtr(fmt1);
348
349   return status;
350 }
351
352 /***********************************************************************/
353
354 static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
355 {
356   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
357
358   TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
359
360   if (IsEqualGUID(&IID_IUnknown, refiid) ||
361       IsEqualGUID(&IID_IAVIEditStream, refiid)) {
362     *obj = iface;
363     IAVIEditStream_AddRef(iface);
364
365     return S_OK;
366   } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
367     *obj = &This->iAVIStream;
368     IAVIEditStream_AddRef(iface);
369
370     return S_OK;
371   } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
372     *obj = &This->iEditStreamInternal;
373     IAVIEditStream_AddRef(iface);
374
375     return S_OK;
376   }
377
378   return OLE_E_ENUM_NOMORE;
379 }
380
381 static ULONG   WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
382 {
383   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
384   ULONG ref = InterlockedIncrement(&This->ref);
385
386   TRACE("(%p) -> %ld\n", iface, ref);
387
388   return ref;
389 }
390
391 static ULONG   WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
392 {
393   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
394   DWORD i;
395   ULONG ref = InterlockedDecrement(&This->ref);
396
397   TRACE("(%p) -> %ld\n", iface, ref);
398
399   if (!ref) {
400     /* release memory */
401     if (This->pg != NULL)
402       AVIStreamGetFrameClose(This->pg);
403     if (This->pStreams != NULL) {
404       for (i = 0; i < This->nStreams; i++) {
405         if (This->pStreams[i].pStream != NULL)
406           IAVIStream_Release(This->pStreams[i].pStream);
407       }
408       GlobalFreePtr(This->pStreams);
409     }
410
411     LocalFree((HLOCAL)This);
412     return 0;
413   }
414   return ref;
415 }
416
417 static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
418                                            LONG*plLength,PAVISTREAM*ppResult)
419 {
420   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
421   PAVISTREAM stream;
422   DWORD      start, len, streamPos, streamNr;
423   HRESULT    hr;
424
425   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
426
427   if (ppResult != NULL)
428     *ppResult = NULL;
429   if (plStart == NULL || plLength == NULL || *plStart < 0)
430     return AVIERR_BADPARAM;
431
432   /* if asked for cutted part copy it before deleting */
433   if (ppResult != NULL) {
434     hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
435     if (FAILED(hr))
436       return hr;
437   }
438
439   start = *plStart;
440   len   = *plLength;
441
442   /* now delete the requested part */
443   while (len > 0) {
444     hr = AVIFILE_FindStreamInTable(This, start, &stream,
445                                    &streamPos, &streamNr, FALSE);
446     if (FAILED(hr))
447       return hr;
448     if (This->pStreams[streamNr].dwStart == streamPos) {
449       /* deleting from start of part */
450       if (len < This->pStreams[streamNr].dwLength) {
451         start += len;
452         This->pStreams[streamNr].dwStart  += len;
453         This->pStreams[streamNr].dwLength -= len;
454         This->sInfo.dwLength -= len;
455         len = 0;
456
457         /* we must return decompressed data now */
458         This->bDecompress = TRUE;
459       } else {
460         /* deleting hole part */
461         len -= This->pStreams[streamNr].dwLength;
462         AVIFILE_RemoveStream(This,streamNr);
463       }
464     } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
465       /* deleting at end of a part */
466       DWORD count = EditStreamEnd(This, streamNr) - streamPos;
467       This->sInfo.dwLength -= count;
468       len                  -= count;
469       This->pStreams[streamNr].dwLength =
470         streamPos - This->pStreams[streamNr].dwStart;
471     } else {
472       /* splitting */
473       if (This->nStreams + 1 >= This->nTableSize) {
474         This->pStreams =
475           GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND);
476         if (This->pStreams == NULL)
477           return AVIERR_MEMORY;
478         This->nTableSize += 32;
479       }
480       memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
481               (This->nStreams - streamNr) * sizeof(EditStreamTable));
482       This->nStreams++;
483
484       IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
485       This->pStreams[streamNr + 1].dwStart  = streamPos + len;
486       This->pStreams[streamNr + 1].dwLength =
487         EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
488
489       This->pStreams[streamNr].dwLength =
490         streamPos - This->pStreams[streamNr].dwStart;
491       This->sInfo.dwLength -= len;
492       len = 0;
493     }
494   }
495
496   This->sInfo.dwEditCount++;
497
498   return AVIERR_OK;
499 }
500
501 static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
502                                             LONG*plLength,PAVISTREAM*ppResult)
503 {
504   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
505   IAVIEditStreamImpl* pEdit;
506   HRESULT hr;
507   LONG start = 0;
508
509   TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
510
511   if (ppResult == NULL)
512     return AVIERR_BADPARAM;
513   *ppResult = NULL;
514   if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
515     return AVIERR_BADPARAM;
516
517   /* check bounds */
518   if (*(LPDWORD)plLength > This->sInfo.dwLength)
519     *(LPDWORD)plLength = This->sInfo.dwLength;
520   if (*(LPDWORD)plStart < This->sInfo.dwStart) {
521     *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
522     *(LPDWORD)plStart   = This->sInfo.dwStart;
523     if (*plLength < 0)
524       return AVIERR_BADPARAM;
525   }
526   if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
527     *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
528       *(LPDWORD)plStart;
529
530   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
531   if (pEdit == NULL)
532     return AVIERR_MEMORY;
533
534   hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
535                             (PAVISTREAM)&This->iAVIStream,*plStart,
536                             *plStart + *plLength);
537   *plStart = start;
538   if (FAILED(hr))
539     IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
540   else
541     *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
542
543   return hr;
544 }
545
546 static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
547                                              LONG*plLength,PAVISTREAM pSource,
548                                              LONG lStart,LONG lLength)
549 {
550   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
551   AVISTREAMINFOW      srcInfo;
552   IEditStreamInternal*pInternal = NULL;
553   IAVIEditStreamImpl *pEdit = NULL;
554   PAVISTREAM          pStream;
555   DWORD               startPos, endPos, streamNr, nStreams;
556   LONG                n;
557
558   TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
559         pSource,lStart,lLength);
560
561   if (pSource == NULL)
562     return AVIERR_BADHANDLE;
563   if (plStart == NULL || *plStart < 0)
564     return AVIERR_BADPARAM;
565   if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
566     return AVIERR_BADPARAM; /* Can't paste with holes */
567   if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
568     return AVIERR_ERROR;
569   if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
570     return AVIERR_BADPARAM;
571   if (This->sInfo.fccType == 0) {
572     /* This stream is empty */
573     IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
574     This->sInfo.dwStart  = *plStart;
575     This->sInfo.dwLength = 0;
576   }
577   if (This->sInfo.fccType != srcInfo.fccType)
578     return AVIERR_UNSUPPORTED; /* different stream types */
579   if (lLength == -1) /* Copy the hole stream */
580     lLength = srcInfo.dwLength;
581   if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
582     lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
583   if (lLength + *plStart >= 0x80000000)
584     return AVIERR_MEMORY;
585
586   /* streamtype specific tests */
587   if (srcInfo.fccType == streamtypeVIDEO) {
588     LONG size;
589
590     size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
591     if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
592       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
593     size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
594     if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
595       return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
596   } else if (srcInfo.fccType == streamtypeAUDIO) {
597     if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
598       return AVIERR_UNSUPPORTED;
599   } else {
600     /* FIXME: streamtypeMIDI and streamtypeTEXT */
601     return AVIERR_UNSUPPORTED;
602   }
603
604   /* try to get an IEditStreamInternal interface */
605   if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
606                                           (LPVOID*)&pInternal))) {
607     pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
608     pInternal->lpVtbl->Release(pInternal);
609   }
610
611   /* for video must check for change of format */
612   if (This->sInfo.fccType == streamtypeVIDEO) {
613     if (! This->bDecompress) {
614       /* Need to decompress if any of the following conditions matches:
615        *  - pSource is an editable stream which decompresses
616        *  - the nearest keyframe of pSource isn't lStart
617        *  - the nearest keyframe of this stream isn't *plStart
618        *  - the format of pSource doesn't match this one
619        */
620       if ((pEdit != NULL && pEdit->bDecompress) ||
621           AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
622           AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
623           (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
624         /* Use first stream part to get format to convert everything to */
625         AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
626                           This->pStreams[0].dwStart);
627
628         /* Check if we could convert the source streams to the disired format... */
629         if (pEdit != NULL) {
630           if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
631                                                &startPos, &streamNr, TRUE)))
632             return AVIERR_INTERNAL;
633           for (n = lStart; n < lStart + lLength; streamNr++) {
634             if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
635               return AVIERR_BADFORMAT;
636             startPos = pEdit->pStreams[streamNr].dwStart;
637             n += pEdit->pStreams[streamNr].dwLength;
638           }
639         } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
640           return AVIERR_BADFORMAT;
641
642         This->bDecompress      = TRUE;
643         This->sInfo.fccHandler = 0;
644       }
645     } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
646       return AVIERR_BADFORMAT; /* Can't convert source to own format */
647   } /* FIXME: something special for the other formats? */
648
649   /* Make sure we have enough memory for parts */
650   if (pEdit != NULL) {
651     DWORD nLastStream;
652
653     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
654                               &endPos, &nLastStream, TRUE);
655     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
656                               &startPos, &streamNr, FALSE);
657     if (nLastStream == streamNr)
658       nLastStream++;
659
660     nStreams = nLastStream - streamNr;
661   } else 
662     nStreams = 1;
663   if (This->nStreams + nStreams + 1 > This->nTableSize) {
664     n = This->nStreams + nStreams + 33;
665
666     This->pStreams =
667       GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND);
668     if (This->pStreams == NULL)
669       return AVIERR_MEMORY;
670     This->nTableSize = n;
671   }
672
673   if (plLength != NULL)
674     *plLength = lLength;
675
676   /* now do the real work */
677   if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
678     AVIFILE_FindStreamInTable(This, *plStart, &pStream,
679                               &startPos, &streamNr, FALSE);
680     if (startPos != This->pStreams[streamNr].dwStart) {
681       /* split stream streamNr at startPos */
682       memmove(This->pStreams + streamNr + nStreams + 1,
683               This->pStreams + streamNr,
684               (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
685
686       This->pStreams[streamNr + 2].dwLength =
687         EditStreamEnd(This, streamNr + 2) - startPos;
688       This->pStreams[streamNr + 2].dwStart = startPos;
689       This->pStreams[streamNr].dwLength =
690         startPos - This->pStreams[streamNr].dwStart;
691       IAVIStream_AddRef(This->pStreams[streamNr].pStream);
692       streamNr++;
693     } else {
694       /* insert before stream at streamNr */
695       memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
696               (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
697     }
698   } else /* append the streams */
699     streamNr = This->nStreams;
700
701   if (pEdit != NULL) {
702     /* insert the parts of the editable stream instead of itself */
703     AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
704                               &endPos, NULL, FALSE);
705     AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
706
707     memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
708            nStreams * sizeof(EditStreamTable));
709     if (This->pStreams[streamNr].dwStart < startPos) {
710       This->pStreams[streamNr].dwLength =
711         EditStreamEnd(This, streamNr) - startPos;
712       This->pStreams[streamNr].dwStart  = startPos;
713     }
714     if (endPos < EditStreamEnd(This, streamNr + nStreams))
715       This->pStreams[streamNr + nStreams].dwLength =
716         endPos - This->pStreams[streamNr + nStreams].dwStart;
717   } else {
718     /* a simple stream */
719     This->pStreams[streamNr].pStream  = pSource;
720     This->pStreams[streamNr].dwStart  = lStart;
721     This->pStreams[streamNr].dwLength = lLength;
722   }
723
724   for (n = 0; n < nStreams; n++) {
725     IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
726     if (0 < streamNr + n &&
727         This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
728       This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
729       This->sInfo.dwFormatChangeCount++;
730     }
731   }
732   This->sInfo.dwEditCount++;
733   This->sInfo.dwLength += lLength;
734   This->nStreams += nStreams;
735
736   return AVIERR_OK;
737 }
738
739 static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
740                                              PAVISTREAM*ppResult)
741 {
742   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
743   IAVIEditStreamImpl* pEdit;
744   DWORD i;
745
746   TRACE("(%p,%p)\n",iface,ppResult);
747
748   if (ppResult == NULL)
749     return AVIERR_BADPARAM;
750   *ppResult = NULL;
751
752   pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
753   if (pEdit == NULL)
754     return AVIERR_MEMORY;
755   if (This->nStreams > pEdit->nTableSize) {
756     pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND);
757     if (pEdit->pStreams == NULL)
758       return AVIERR_MEMORY;
759     pEdit->nTableSize = This->nStreams;
760   }
761   pEdit->nStreams = This->nStreams;
762   memcpy(pEdit->pStreams, This->pStreams,
763          This->nStreams * sizeof(EditStreamTable));
764   memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
765   for (i = 0; i < This->nStreams; i++) {
766     if (pEdit->pStreams[i].pStream != NULL)
767       IAVIStream_AddRef(pEdit->pStreams[i].pStream);
768   }
769
770   *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
771
772   return AVIERR_OK;
773 }
774
775 static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
776                                                LPAVISTREAMINFOW asi,LONG size)
777 {
778   IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
779
780   TRACE("(%p,%p,%ld)\n",iface,asi,size);
781
782   /* check parameters */
783   if (asi == NULL)
784     return AVIERR_BADPARAM;
785   if (size != sizeof(AVISTREAMINFOW))
786     return AVIERR_BADSIZE;
787   if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
788       asi->dwQuality > ICQUALITY_HIGH)
789     return AVIERR_ERROR;
790
791   This->sInfo.wLanguage = asi->wLanguage;
792   This->sInfo.wPriority = asi->wPriority;
793   This->sInfo.dwStart   = asi->dwStart;
794   if (asi->dwRate != 0)
795     This->sInfo.dwRate  = asi->dwRate;
796   if (asi->dwScale != 0)
797     This->sInfo.dwScale = asi->dwScale;
798   if (asi->dwQuality <= ICQUALITY_HIGH)
799     This->sInfo.dwQuality = ICQUALITY_HIGH;
800   CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
801   memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
802   This->sInfo.dwEditCount++;
803
804   return AVIERR_OK;
805 }
806
807 static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
808                                                       REFIID refiid,LPVOID*obj)
809 {
810   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
811
812   assert(This->pae != NULL);
813
814   return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
815 }
816
817 static ULONG   WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
818 {
819   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
820
821   assert(This->pae != NULL);
822
823   return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
824 }
825
826 static ULONG   WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
827 {
828   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
829
830   assert(This->pae != NULL);
831
832   return IAVIEditStream_Release((IAVIEditStream*)This->pae);
833 }
834
835 static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
836                                               LPARAM lParam1,LPARAM lParam2)
837 {
838   IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
839
840   if (lParam2 != 0)
841     return AVIERR_ERROR;
842
843   if (This->pStreams == NULL) {
844     This->pStreams =
845       GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable));
846     if (This->pStreams == NULL)
847       return AVIERR_MEMORY;
848     This->nTableSize = 256;
849   }
850
851   if (lParam1 != 0) {
852     IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
853     IAVIStream_AddRef((PAVISTREAM)lParam1);
854     This->pStreams[0].pStream  = (PAVISTREAM)lParam1;
855     This->pStreams[0].dwStart  = This->sInfo.dwStart;
856     This->pStreams[0].dwLength = This->sInfo.dwLength;
857     This->nStreams = 1;
858   }
859   return AVIERR_OK;
860 }
861
862 static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
863                                             AVISTREAMINFOW *psi,LONG size)
864 {
865   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
866
867   TRACE("(%p,%p,%ld)\n",iface,psi,size);
868
869   assert(This->pae != NULL);
870
871   if (psi == NULL)
872     return AVIERR_BADPARAM;
873   if (size < 0)
874     return AVIERR_BADSIZE;
875
876   if (This->pae->bDecompress)
877     This->pae->sInfo.fccHandler = 0;
878
879   memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
880
881   if ((DWORD)size < sizeof(This->pae->sInfo))
882     return AVIERR_BUFFERTOOSMALL;
883   return AVIERR_OK;
884 }
885
886 static LONG    WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
887                                                   LONG flags)
888 {
889   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
890   PAVISTREAM stream;
891   DWORD      streamPos, streamNr;
892
893   TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
894
895   if (flags & FIND_FROM_START)
896     pos = (LONG)This->sInfo.dwStart;
897
898   /* outside of stream? */
899   if (pos < (LONG)This->sInfo.dwStart ||
900       (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
901     return -1;
902
903   /* map our position to a stream and position in it */
904   if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
905                                 &streamNr, TRUE))
906     return -1; /* doesn't exist */
907
908   if (This->bDecompress) {
909     /* only one stream -- format changes only at start */
910     if (flags & FIND_FORMAT)
911       return (flags & FIND_NEXT ? -1 : 0);
912
913     /* FIXME: map positions back to us */
914     return IAVIStream_FindSample(stream, streamPos, flags);
915   } else {
916     /* assume change of format every frame */
917     return pos;
918   }
919 }
920
921 static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
922                                                   LPVOID format,LONG*fmtsize)
923 {
924   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
925   LPBITMAPINFOHEADER  lp;
926   PAVISTREAM          stream;
927   DWORD               n;
928   HRESULT             hr;
929
930   TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
931
932   if (fmtsize == NULL || pos < This->sInfo.dwStart ||
933       This->sInfo.dwStart + This->sInfo.dwLength <= pos)
934     return AVIERR_BADPARAM;
935
936   /* find stream corresponding to position */
937   hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
938   if (FAILED(hr))
939     return hr;
940
941   if (! This->bDecompress)
942     return IAVIStream_ReadFormat(stream, n, format, fmtsize);
943
944   lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
945   if (lp == NULL)
946     return AVIERR_ERROR;
947   if (lp->biBitCount <= 8) {
948     n  = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
949     n *= sizeof(RGBQUAD);
950   } else
951     n = 0;
952   n += lp->biSize;
953   
954   memcpy(format, lp, min((LONG)n, *fmtsize));
955   hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
956   *fmtsize = n;
957
958   return hr;
959 }
960
961 static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
962                                                  LPVOID format,LONG formatsize)
963 {
964   TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
965
966   return AVIERR_UNSUPPORTED;
967 }
968
969 static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
970                                             LONG samples,LPVOID buffer,
971                                             LONG buffersize,LONG*bytesread,
972                                             LONG*samplesread)
973 {
974   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
975   PAVISTREAM stream;
976   DWORD   streamPos, streamNr;
977   LONG    readBytes, readSamples, count;
978   HRESULT hr;
979
980   TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
981         buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
982
983   /* check parameters */
984   if (bytesread != NULL)
985     *bytesread = 0;
986   if (samplesread != NULL)
987     *samplesread = 0;
988   if (buffersize < 0)
989     return AVIERR_BADSIZE;
990   if ((DWORD)start < This->sInfo.dwStart ||
991       This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
992     return AVIERR_BADPARAM;
993
994   if (! This->bDecompress) {
995     /* audio like data -- sample-based */
996     do {
997       if (samples == 0)
998         return AVIERR_OK; /* nothing at all or already done */
999
1000       if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1001                                            &streamPos, &streamNr, FALSE)))
1002         return AVIERR_ERROR;
1003
1004       /* limit to end of the stream */
1005       count = samples;
1006       if (streamPos + count > EditStreamEnd(This, streamNr))
1007         count = EditStreamEnd(This, streamNr) - streamPos;
1008
1009       hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
1010                            &readBytes, &readSamples);
1011       if (FAILED(hr))
1012         return hr;
1013       if (readBytes == 0 && readSamples == 0 && count != 0)
1014         return AVIERR_FILEREAD; /* for bad stream implementations */
1015
1016       if (samplesread != NULL)
1017         *samplesread += readSamples;
1018       if (bytesread != NULL)
1019         *bytesread += readBytes;
1020       if (buffer != NULL) {
1021         buffer = ((LPBYTE)buffer)+readBytes;
1022         buffersize     -= readBytes;
1023       }
1024       start   += count;
1025       samples -= count;
1026     } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
1027   } else {
1028     /* video like data -- frame-based */
1029     LPBITMAPINFOHEADER lp;
1030
1031     if (samples == 0)
1032       return AVIERR_OK;
1033
1034     if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
1035                                          &streamPos, &streamNr, FALSE)))
1036       return AVIERR_ERROR;
1037
1038     lp = AVIFILE_ReadFrame(This, stream, streamPos);
1039     if (lp == NULL)
1040       return AVIERR_ERROR;
1041
1042     if (buffer != NULL) {
1043       /* need size of format to skip */
1044       if (lp->biBitCount <= 8) {
1045         count  = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
1046         count *= sizeof(RGBQUAD);
1047       } else
1048         count = 0;
1049       count += lp->biSize;
1050
1051       if (buffersize < lp->biSizeImage)
1052         return AVIERR_BUFFERTOOSMALL;
1053       memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
1054     }
1055
1056     if (bytesread != NULL)
1057       *bytesread = lp->biSizeImage;
1058     if (samplesread != NULL)
1059       *samplesread = 1;
1060   }
1061
1062   return AVIERR_OK;
1063 }
1064
1065 static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
1066                                              LONG samples,LPVOID buffer,
1067                                              LONG buffersize,DWORD flags,
1068                                              LONG*sampwritten,LONG*byteswritten)
1069 {
1070   TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
1071         buffersize,flags,sampwritten,byteswritten);
1072
1073   /* be sure return parameters have correct values */
1074   if (sampwritten != NULL)
1075     *sampwritten = 0;
1076   if (byteswritten != NULL)
1077     *byteswritten = 0;
1078
1079   return AVIERR_UNSUPPORTED;
1080 }
1081
1082 static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
1083                                               LONG samples)
1084 {
1085   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1086
1087   TRACE("(%p,%ld,%ld)\n",iface,start,samples);
1088
1089   return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
1090 }
1091
1092 static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
1093                                                 LPVOID lp,LONG *lpread)
1094 {
1095   IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
1096   DWORD n;
1097
1098   TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
1099
1100   /* check parameters */
1101   if (lp == NULL || lpread == NULL)
1102     return AVIERR_BADPARAM;
1103
1104   /* simply ask every stream and return the first block found */
1105   for (n = 0; n < This->nStreams; n++) {
1106     HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
1107
1108     if (SUCCEEDED(hr))
1109       return hr;
1110   }
1111
1112   *lpread = 0;
1113   return AVIERR_NODATA;
1114 }
1115
1116 static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
1117                                                  LPVOID lp,LONG size)
1118 {
1119   TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
1120
1121   return AVIERR_UNSUPPORTED;
1122 }
1123
1124 static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
1125                                                AVISTREAMINFOW*info,LONG len)
1126 {
1127   IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
1128
1129   TRACE("(%p,%p,%ld)\n",iface,info,len);
1130
1131   return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
1132 }
1133
1134 static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
1135 {
1136   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1137
1138   assert(This->pae != NULL);
1139
1140   return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
1141 }
1142
1143 static ULONG   WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
1144 {
1145   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1146
1147   assert(This->pae != NULL);
1148
1149   return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
1150 }
1151
1152 static ULONG   WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
1153 {
1154   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1155
1156   assert(This->pae != NULL);
1157
1158   return IAVIEditStream_Release((IAVIEditStream*)This->pae);
1159 }
1160
1161 static HRESULT  WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
1162 {
1163   IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
1164
1165   TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
1166
1167   assert(This->pae != NULL);
1168   assert(ppimpl != NULL);
1169
1170   *ppimpl = This->pae;
1171   return AVIERR_OK;
1172 }