197 lines
5.0 KiB
C
197 lines
5.0 KiB
C
/*
|
|
* 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 LPEXTRACHUNKS 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,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;
|
|
HRESULT hr;
|
|
|
|
/* 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 (;;) {
|
|
hr = mmioDescend(hmmio, lpck, lpckParent, 0);
|
|
if (hr != S_OK) {
|
|
/* No extra chunks in front of desired chunk? */
|
|
if (flags == 0 && hr == MMIOERR_CHUNKNOTFOUND)
|
|
hr = AVIERR_OK;
|
|
return hr;
|
|
}
|
|
|
|
/* Have we found what we search for? */
|
|
if ((lpck->ckid == ckid) &&
|
|
(fccType == (FOURCC)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'))
|
|
hr = mmioAscend(hmmio, lpck, 0);
|
|
else
|
|
hr = ReadChunkIntoExtra(extra, hmmio, lpck);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
}
|