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