sane.ds: Add simplified and traditional Chinese resources.
[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., 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 outof 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 fomr 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   HRESULT hr;
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     hr = mmioDescend(hmmio, lpck, lpckParent, 0);
175     if (hr != S_OK) {
176       /* No extra chunks in front of desired chunk? */
177       if (flags == 0 && hr == MMIOERR_CHUNKNOTFOUND)
178         hr = AVIERR_OK;
179       return hr;
180     }
181
182     /* Have we found what we search for? */
183     if ((lpck->ckid == ckid) &&
184         (fccType == (FOURCC)0 || lpck->fccType == fccType))
185       return AVIERR_OK;
186
187     /* Skip padding chunks, the others put into the extrachunk-structure */
188     if (lpck->ckid == ckidAVIPADDING ||
189         lpck->ckid == mmioFOURCC('p','a','d','d'))
190       hr = mmioAscend(hmmio, lpck, 0);
191     else
192       hr = ReadChunkIntoExtra(extra, hmmio, lpck);
193     if (FAILED(hr))
194       return hr;
195   }
196 }