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