[AVIFIL32]
[reactos.git] / reactos / dll / win32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "avifile_private.h"
20
21 /* reads a chunk out of the extrachunk-structure */
22 HRESULT ReadExtraChunk(const EXTRACHUNKS *extra,FOURCC ckid,LPVOID lpData,LPLONG size)
23 {
24 LPBYTE lp;
25 DWORD cb;
26
27 /* pre-conditions */
28 assert(extra != NULL);
29 assert(size != NULL);
30
31 lp = extra->lp;
32 cb = extra->cb;
33
34 if (lp != NULL) {
35 while (cb > 0) {
36 if (((FOURCC*)lp)[0] == ckid) {
37 /* found correct chunk */
38 if (lpData != NULL && *size > 0)
39 memcpy(lpData, lp + 2 * sizeof(DWORD),
40 min(((LPDWORD)lp)[1], *(LPDWORD)size));
41
42 *(LPDWORD)size = ((LPDWORD)lp)[1];
43
44 return AVIERR_OK;
45 } else {
46 /* skip to next chunk */
47 cb -= ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
48 lp += ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
49 }
50 }
51 }
52
53 /* wanted chunk doesn't exist */
54 *size = 0;
55
56 return AVIERR_NODATA;
57 }
58
59 /* writes a chunk into the extrachunk-structure */
60 HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPCVOID lpData, LONG size)
61 {
62 LPDWORD lp;
63
64 /* pre-conditions */
65 assert(extra != NULL);
66 assert(lpData != NULL);
67 assert(size > 0);
68
69 if (extra->lp)
70 lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + size + 2 * sizeof(DWORD));
71 else
72 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 2 * sizeof(DWORD));
73
74 if (lp == NULL)
75 return AVIERR_MEMORY;
76
77 extra->lp = lp;
78 lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
79 extra->cb += size + 2 * sizeof(DWORD);
80
81 /* insert chunk-header in block */
82 lp[0] = ckid;
83 lp[1] = size;
84
85 if (lpData != NULL && size > 0)
86 memcpy(lp + 2, lpData, size);
87
88 return AVIERR_OK;
89 }
90
91 /* reads a chunk from the HMMIO into the extrachunk-structure */
92 HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,const MMCKINFO *lpck)
93 {
94 LPDWORD lp;
95 DWORD cb;
96
97 /* pre-conditions */
98 assert(extra != NULL);
99 assert(hmmio != NULL);
100 assert(lpck != NULL);
101
102 cb = lpck->cksize + 2 * sizeof(DWORD);
103 cb += (cb & 1);
104
105 if (extra->lp != NULL)
106 lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + cb);
107 else
108 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
109
110 if (lp == NULL)
111 return AVIERR_MEMORY;
112
113 extra->lp = lp;
114 lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
115 extra->cb += cb;
116
117 /* insert chunk-header in block */
118 lp[0] = lpck->ckid;
119 lp[1] = lpck->cksize;
120
121 if (lpck->cksize > 0) {
122 if (mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET) == -1)
123 return AVIERR_FILEREAD;
124 if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != (LONG)lpck->cksize)
125 return AVIERR_FILEREAD;
126 }
127
128 return AVIERR_OK;
129 }
130
131 /* reads all non-junk chunks into the extrachunk-structure until it finds
132 * the given chunk or the optional parent-chunk is at the end */
133 HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck,
134 MMCKINFO *lpckParent,UINT flags)
135 {
136 FOURCC ckid;
137 FOURCC fccType;
138 MMRESULT mmr;
139
140 /* pre-conditions */
141 assert(extra != NULL);
142 assert(hmmio != NULL);
143 assert(lpck != NULL);
144
145 TRACE("({%p,%u},%p,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck,
146 lpckParent, flags);
147
148 /* what chunk id and form/list type should we search? */
149 if (flags & MMIO_FINDCHUNK) {
150 ckid = lpck->ckid;
151 fccType = 0;
152 } else if (flags & MMIO_FINDLIST) {
153 ckid = FOURCC_LIST;
154 fccType = lpck->fccType;
155 } else if (flags & MMIO_FINDRIFF) {
156 ckid = FOURCC_RIFF;
157 fccType = lpck->fccType;
158 } else
159 ckid = fccType = (FOURCC)-1; /* collect everything into extra! */
160
161 TRACE(": find ckid=0x%08X fccType=0x%08X\n", ckid, fccType);
162
163 for (;;) {
164 mmr = mmioDescend(hmmio, lpck, lpckParent, 0);
165 if (mmr != MMSYSERR_NOERROR) {
166 /* No extra chunks in front of desired chunk? */
167 if (flags == 0 && mmr == MMIOERR_CHUNKNOTFOUND)
168 return AVIERR_OK;
169 else
170 return AVIERR_FILEREAD;
171 }
172
173 /* Have we found what we search for? */
174 if ((lpck->ckid == ckid) &&
175 (fccType == 0 || lpck->fccType == fccType))
176 return AVIERR_OK;
177
178 /* Skip padding chunks, the others put into the extrachunk-structure */
179 if (lpck->ckid == ckidAVIPADDING ||
180 lpck->ckid == mmioFOURCC('p','a','d','d'))
181 {
182 mmr = mmioAscend(hmmio, lpck, 0);
183 if (mmr != MMSYSERR_NOERROR) return AVIERR_FILEREAD;
184 }
185 else
186 {
187 HRESULT hr = ReadChunkIntoExtra(extra, hmmio, lpck);
188 if (FAILED(hr))
189 return hr;
190 }
191 }
192 }