|  | /* | 
|  | * 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 outof 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 fomr 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; | 
|  | } | 
|  | } | 
|  | } |