extrachunk.c 5.17 KB
Newer Older
1
/*
2
 * Copyright 2002 Michael Günnewig
3 4 5 6 7 8 9 10 11 12 13 14 15
 *
 * 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
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 18 19 20 21 22
 */

#include <assert.h>

#include "extrachunk.h"
#include "winbase.h"
23
#include "wingdi.h"
24
#include "winuser.h"
25 26 27 28 29 30 31
#include "vfw.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(avifile);

/* reads a chunk outof the extrachunk-structure */
32
HRESULT ReadExtraChunk(const EXTRACHUNKS *extra,FOURCC ckid,LPVOID lpData,LPLONG size)
33 34
{
  LPBYTE lp;
35
  DWORD  cb;
36 37 38 39 40 41 42 43 44 45 46 47 48

  /* 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)
49 50
	  memcpy(lpData, lp + 2 * sizeof(DWORD),
		 min(((LPDWORD)lp)[1], *(LPDWORD)size));
51

52
	*(LPDWORD)size = ((LPDWORD)lp)[1];
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

	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 */
70
HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPCVOID lpData, LONG size)
71 72 73 74 75 76 77 78 79
{
  LPDWORD lp;

  /* pre-conditions */
  assert(extra != NULL);
  assert(lpData != NULL);
  assert(size > 0);

  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 85 86 87

  if (lp == NULL)
    return AVIERR_MEMORY;

  extra->lp  = lp;
88
  lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
89 90 91 92 93 94 95 96 97 98 99 100 101
  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 */
102
HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,const MMCKINFO *lpck)
103 104
{
  LPDWORD lp;
105
  DWORD   cb;
106 107 108

  /* pre-conditions */
  assert(extra != NULL);
109
  assert(hmmio != NULL);
110 111 112 113 114
  assert(lpck  != NULL);

  cb  = lpck->cksize + 2 * sizeof(DWORD);
  cb += (cb & 1);

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 121 122 123

  if (lp == NULL)
    return AVIERR_MEMORY;

  extra->lp  = lp;
124
  lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
125 126 127 128 129 130 131 132 133
  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;
134
    if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != (LONG)lpck->cksize)
135 136 137 138 139 140
      return AVIERR_FILEREAD;
  }

  return AVIERR_OK;
}

Francois Gouget's avatar
Francois Gouget committed
141
/* reads all non-junk chunks into the extrachunk-structure until it finds
142 143 144 145 146 147
 * 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;
148
  MMRESULT mmr;
149 150 151

  /* pre-conditions */
  assert(extra != NULL);
152
  assert(hmmio != NULL);
153 154
  assert(lpck  != NULL);

155
  TRACE("({%p,%u},%p,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck,
156 157
	lpckParent, flags);

158
  /* what chunk id and form/list type should we search? */
159 160 161 162 163 164 165 166 167 168 169 170
  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! */

171
  TRACE(": find ckid=0x%08X fccType=0x%08X\n", ckid, fccType);
172 173

  for (;;) {
174 175
    mmr = mmioDescend(hmmio, lpck, lpckParent, 0);
    if (mmr != MMSYSERR_NOERROR) {
176
      /* No extra chunks in front of desired chunk? */
177 178 179 180
      if (flags == 0 && mmr == MMIOERR_CHUNKNOTFOUND)
	return AVIERR_OK;
      else
        return AVIERR_FILEREAD;
181 182 183 184
    }

    /* Have we found what we search for? */
    if ((lpck->ckid == ckid) &&
185
	(fccType == 0 || lpck->fccType == fccType))
186 187 188 189 190
      return AVIERR_OK;

    /* Skip padding chunks, the others put into the extrachunk-structure */
    if (lpck->ckid == ckidAVIPADDING ||
	lpck->ckid == mmioFOURCC('p','a','d','d'))
191 192 193 194
    {
      mmr = mmioAscend(hmmio, lpck, 0);
      if (mmr != MMSYSERR_NOERROR) return AVIERR_FILEREAD;
    }
195
    else
196 197 198 199 200
    {
      HRESULT hr = ReadChunkIntoExtra(extra, hmmio, lpck);
      if (FAILED(hr))
        return hr;
    }
201 202
  }
}