avifil32: Fix a regression caused by patch removing GlobalAllocs by using HEAP_ZERO_INIT.
[wine] / dlls / avifil32 / extrachunk.c
1 /*
2  * Copyright 2002 Michael Günnewig
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define COM_NO_WINDOWS_H
20 #include <assert.h>
21
22 #include "extrachunk.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winuser.h"
26 #include "vfw.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
31
32 /* reads a chunk outof the extrachunk-structure */
33 HRESULT ReadExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
34                        LPLONG size)
35 {
36   LPBYTE lp;
37   DWORD  cb;
38
39   /* pre-conditions */
40   assert(extra != NULL);
41   assert(size != NULL);
42
43   lp = extra->lp;
44   cb = extra->cb;
45
46   if (lp != NULL) {
47     while (cb > 0) {
48       if (((FOURCC*)lp)[0] == ckid) {
49         /* found correct chunk */
50         if (lpData != NULL && *size > 0)
51           memcpy(lpData, lp + 2 * sizeof(DWORD),
52                  min(((LPDWORD)lp)[1], *(LPDWORD)size));
53
54         *(LPDWORD)size = ((LPDWORD)lp)[1];
55
56         return AVIERR_OK;
57       } else {
58         /* skip to next chunk */
59         cb -= ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
60         lp += ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
61       }
62     }
63   }
64
65   /* wanted chunk doesn't exist */
66   *size = 0;
67
68   return AVIERR_NODATA;
69 }
70
71 /* writes a chunk into the extrachunk-structure */
72 HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
73                         LONG size)
74 {
75   LPDWORD lp;
76
77   /* pre-conditions */
78   assert(extra != NULL);
79   assert(lpData != NULL);
80   assert(size > 0);
81
82   if (extra->lp)
83     lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + size + 2 * sizeof(DWORD));
84   else
85     lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 2 * sizeof(DWORD));
86
87   if (lp == NULL)
88     return AVIERR_MEMORY;
89
90   extra->lp  = lp;
91   lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
92   extra->cb += size + 2 * sizeof(DWORD);
93
94   /* insert chunk-header in block */
95   lp[0] = ckid;
96   lp[1] = size;
97
98   if (lpData != NULL && size > 0)
99     memcpy(lp + 2, lpData, size);
100
101   return AVIERR_OK;
102 }
103
104 /* reads a chunk fomr the HMMIO into the extrachunk-structure */
105 HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck)
106 {
107   LPDWORD lp;
108   DWORD   cb;
109
110   /* pre-conditions */
111   assert(extra != NULL);
112   assert(hmmio != NULL);
113   assert(lpck  != NULL);
114
115   cb  = lpck->cksize + 2 * sizeof(DWORD);
116   cb += (cb & 1);
117
118   if (extra->lp != NULL)
119     lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + cb);
120   else
121     lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
122
123   if (lp == NULL)
124     return AVIERR_MEMORY;
125
126   extra->lp  = lp;
127   lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
128   extra->cb += cb;
129
130   /* insert chunk-header in block */
131   lp[0] = lpck->ckid;
132   lp[1] = lpck->cksize;
133
134   if (lpck->cksize > 0) {
135     if (mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET) == -1)
136       return AVIERR_FILEREAD;
137     if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != (LONG)lpck->cksize)
138       return AVIERR_FILEREAD;
139   }
140
141   return AVIERR_OK;
142 }
143
144 /* reads all non-junk chunks into the extrachunk-structure until it finds
145  * the given chunk or the optional parent-chunk is at the end */
146 HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck,
147                                MMCKINFO *lpckParent,UINT flags)
148 {
149   FOURCC  ckid;
150   FOURCC  fccType;
151   HRESULT hr;
152
153   /* pre-conditions */
154   assert(extra != NULL);
155   assert(hmmio != NULL);
156   assert(lpck  != NULL);
157
158   TRACE("({%p,%lu},%p,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck,
159         lpckParent, flags);
160
161   /* what chunk id and form/list type should we search? */
162   if (flags & MMIO_FINDCHUNK) {
163     ckid    = lpck->ckid;
164     fccType = 0;
165   } else if (flags & MMIO_FINDLIST) {
166     ckid    = FOURCC_LIST;
167     fccType = lpck->fccType;
168   } else if (flags & MMIO_FINDRIFF) {
169     ckid    = FOURCC_RIFF;
170     fccType = lpck->fccType;
171   } else
172     ckid = fccType = (FOURCC)-1; /* collect everything into extra! */
173
174   TRACE(": find ckid=0x%08lX fccType=0x%08lX\n", ckid, fccType);
175
176   for (;;) {
177     hr = mmioDescend(hmmio, lpck, lpckParent, 0);
178     if (hr != S_OK) {
179       /* No extra chunks in front of desired chunk? */
180       if (flags == 0 && hr == MMIOERR_CHUNKNOTFOUND)
181         hr = AVIERR_OK;
182       return hr;
183     }
184
185     /* Have we found what we search for? */
186     if ((lpck->ckid == ckid) &&
187         (fccType == (FOURCC)0 || lpck->fccType == fccType))
188       return AVIERR_OK;
189
190     /* Skip padding chunks, the others put into the extrachunk-structure */
191     if (lpck->ckid == ckidAVIPADDING ||
192         lpck->ckid == mmioFOURCC('p','a','d','d'))
193       hr = mmioAscend(hmmio, lpck, 0);
194     else
195       hr = ReadChunkIntoExtra(extra, hmmio, lpck);
196     if (FAILED(hr))
197       return hr;
198   }
199 }