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