| /* |
| * Copyright 2002 Michael Günnewig |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <assert.h> |
| |
| #include "extrachunk.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "vfw.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(avifile); |
| |
| /* reads a chunk out of the extrachunk-structure */ |
| HRESULT ReadExtraChunk(const EXTRACHUNKS *extra,FOURCC ckid,LPVOID lpData,LPLONG size) |
| { |
| LPBYTE lp; |
| DWORD cb; |
| |
| /* pre-conditions */ |
| assert(extra != NULL); |
| assert(size != NULL); |
| |
| lp = extra->lp; |
| cb = extra->cb; |
| |
| if (lp != NULL) { |
| while (cb > 0) { |
| if (((FOURCC*)lp)[0] == ckid) { |
| /* found correct chunk */ |
| if (lpData != NULL && *size > 0) |
| memcpy(lpData, lp + 2 * sizeof(DWORD), |
| min(((LPDWORD)lp)[1], *(LPDWORD)size)); |
| |
| *(LPDWORD)size = ((LPDWORD)lp)[1]; |
| |
| return AVIERR_OK; |
| } else { |
| /* skip to next chunk */ |
| cb -= ((LPDWORD)lp)[1] + 2 * sizeof(DWORD); |
| lp += ((LPDWORD)lp)[1] + 2 * sizeof(DWORD); |
| } |
| } |
| } |
| |
| /* wanted chunk doesn't exist */ |
| *size = 0; |
| |
| return AVIERR_NODATA; |
| } |
| |
| /* writes a chunk into the extrachunk-structure */ |
| HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPCVOID lpData, LONG size) |
| { |
| LPDWORD lp; |
| |
| /* pre-conditions */ |
| assert(extra != NULL); |
| assert(lpData != NULL); |
| assert(size > 0); |
| |
| if (extra->lp) |
| lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + size + 2 * sizeof(DWORD)); |
| else |
| lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 2 * sizeof(DWORD)); |
| |
| if (lp == NULL) |
| return AVIERR_MEMORY; |
| |
| extra->lp = lp; |
| lp = (LPDWORD) ((LPBYTE)lp + extra->cb); |
| extra->cb += size + 2 * sizeof(DWORD); |
| |
| /* insert chunk-header in block */ |
| lp[0] = ckid; |
| lp[1] = size; |
| |
| if (lpData != NULL && size > 0) |
| memcpy(lp + 2, lpData, size); |
| |
| return AVIERR_OK; |
| } |
| |
| /* reads a chunk from the HMMIO into the extrachunk-structure */ |
| HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,const MMCKINFO *lpck) |
| { |
| LPDWORD lp; |
| DWORD cb; |
| |
| /* pre-conditions */ |
| assert(extra != NULL); |
| assert(hmmio != NULL); |
| assert(lpck != NULL); |
| |
| cb = lpck->cksize + 2 * sizeof(DWORD); |
| cb += (cb & 1); |
| |
| if (extra->lp != NULL) |
| lp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, extra->lp, extra->cb + cb); |
| else |
| lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb); |
| |
| if (lp == NULL) |
| return AVIERR_MEMORY; |
| |
| extra->lp = lp; |
| lp = (LPDWORD) ((LPBYTE)lp + extra->cb); |
| extra->cb += cb; |
| |
| /* insert chunk-header in block */ |
| lp[0] = lpck->ckid; |
| lp[1] = lpck->cksize; |
| |
| if (lpck->cksize > 0) { |
| if (mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET) == -1) |
| return AVIERR_FILEREAD; |
| if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != (LONG)lpck->cksize) |
| return AVIERR_FILEREAD; |
| } |
| |
| return AVIERR_OK; |
| } |
| |
| /* reads all non-junk chunks into the extrachunk-structure until it finds |
| * the given chunk or the optional parent-chunk is at the end */ |
| HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck, |
| MMCKINFO *lpckParent,UINT flags) |
| { |
| FOURCC ckid; |
| FOURCC fccType; |
| MMRESULT mmr; |
| |
| /* pre-conditions */ |
| assert(extra != NULL); |
| assert(hmmio != NULL); |
| assert(lpck != NULL); |
| |
| TRACE("({%p,%u},%p,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck, |
| lpckParent, flags); |
| |
| /* what chunk id and form/list type should we search? */ |
| if (flags & MMIO_FINDCHUNK) { |
| ckid = lpck->ckid; |
| fccType = 0; |
| } else if (flags & MMIO_FINDLIST) { |
| ckid = FOURCC_LIST; |
| fccType = lpck->fccType; |
| } else if (flags & MMIO_FINDRIFF) { |
| ckid = FOURCC_RIFF; |
| fccType = lpck->fccType; |
| } else |
| ckid = fccType = (FOURCC)-1; /* collect everything into extra! */ |
| |
| TRACE(": find ckid=0x%08X fccType=0x%08X\n", ckid, fccType); |
| |
| for (;;) { |
| mmr = mmioDescend(hmmio, lpck, lpckParent, 0); |
| if (mmr != MMSYSERR_NOERROR) { |
| /* No extra chunks in front of desired chunk? */ |
| if (flags == 0 && mmr == MMIOERR_CHUNKNOTFOUND) |
| return AVIERR_OK; |
| else |
| return AVIERR_FILEREAD; |
| } |
| |
| /* Have we found what we search for? */ |
| if ((lpck->ckid == ckid) && |
| (fccType == 0 || lpck->fccType == fccType)) |
| return AVIERR_OK; |
| |
| /* Skip padding chunks, the others put into the extrachunk-structure */ |
| if (lpck->ckid == ckidAVIPADDING || |
| lpck->ckid == mmioFOURCC('p','a','d','d')) |
| { |
| mmr = mmioAscend(hmmio, lpck, 0); |
| if (mmr != MMSYSERR_NOERROR) return AVIERR_FILEREAD; |
| } |
| else |
| { |
| HRESULT hr = ReadChunkIntoExtra(extra, hmmio, lpck); |
| if (FAILED(hr)) |
| return hr; |
| } |
| } |
| } |