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