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