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