From 6165d87fc5d1a2147deba22e802ed41885e48635 Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
Date: Tue, 15 Apr 2008 20:39:36 -0700
Subject: [PATCH] quartz: Add a Disconnect function to the parser and use it to
 clean up allocated memory in avisplitter.

---
 dlls/quartz/avisplit.c   | 141 +++++++++++++++++++++++++--------------
 dlls/quartz/mpegsplit.c  |   8 ++-
 dlls/quartz/parser.c     |  10 +--
 dlls/quartz/parser.h     |   5 +-
 dlls/quartz/waveparser.c |   8 ++-
 5 files changed, 114 insertions(+), 58 deletions(-)

diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c
index 0d15c759bee..24f487c61df 100644
--- a/dlls/quartz/avisplit.c
+++ b/dlls/quartz/avisplit.c
@@ -22,6 +22,7 @@
 /* FIXME:
  * - we don't do anything with indices yet (we could use them when seeking)
  * - we don't support multiple RIFF sections (i.e. large AVI files > 2Gb)
+ * - Memory leaks, and lots of them
  */
 
 #include "quartz_private.h"
@@ -55,6 +56,10 @@ typedef struct StreamData
     DWORD dwSampleSize;
     FLOAT fSamplesPerSec;
     DWORD dwLength;
+
+    AVISUPERINDEX *superindex;
+    DWORD entries;
+    AVISTDINDEX **stdindex;
 } StreamData;
 
 typedef struct AVISplitterImpl
@@ -65,6 +70,11 @@ typedef struct AVISplitterImpl
     LONGLONG CurrentChunkOffset; /* in media time */
     LONGLONG EndOfFile;
     AVIMAINHEADER AviHeader;
+    AVIEXTHEADER ExtHeader;
+
+    /* TODO: Handle old style index, probably by creating an opendml style new index from it for within StreamData */
+    AVIOLDINDEX *oldindex;
+
     StreamData *streams;
 } AVISplitterImpl;
 
@@ -404,6 +414,61 @@ static HRESULT AVISplitter_ProcessIndex(AVISplitterImpl *This, LONGLONG qwOffset
     return S_OK;
 }
 
+static HRESULT AVISplitter_ProcessOldIndex(AVISplitterImpl *This)
+{
+    AVIOLDINDEX *pAviOldIndex = This->oldindex;
+    int relative = -1;
+    int x;
+
+    for (x = 0; x < pAviOldIndex->cb / sizeof(pAviOldIndex->aIndex[0]); ++x)
+    {
+        DWORD temp, temp2 = 0, offset, chunkid;
+        ULONGLONG mov_pos = BYTES_FROM_MEDIATIME(This->CurrentChunkOffset) - sizeof(DWORD);
+        PullPin *pin = This->Parser.pInputPin;
+
+        offset = pAviOldIndex->aIndex[x].dwOffset;
+        chunkid = pAviOldIndex->aIndex[x].dwChunkId;
+
+        /* Only scan once, or else this will take too long */
+        if (relative == -1)
+        {
+            IAsyncReader_SyncRead(pin->pReader, offset, sizeof(DWORD), (BYTE *)&temp);
+            relative = (chunkid != temp);
+
+            if (chunkid == mmioFOURCC('7','F','x','x')
+                && ((char *)&temp)[0] == 'i' && ((char *)&temp)[1] == 'x')
+                relative = FALSE;
+
+            if (relative)
+            {
+                if (offset + mov_pos < BYTES_FROM_MEDIATIME(This->EndOfFile))
+                    IAsyncReader_SyncRead(pin->pReader, offset + mov_pos, sizeof(DWORD), (BYTE *)&temp2);
+
+                if (chunkid == mmioFOURCC('7','F','x','x')
+                    && ((char *)&temp2)[0] == 'i' && ((char *)&temp2)[1] == 'x')
+                {
+                    /* Do nothing, all is great */
+                }
+                else if (temp2 != chunkid)
+                {
+                    ERR("Faulty index or bug in handling: Wanted FCC: %s, Abs FCC: %s (@ %x), Rel FCC: %s (@ %.0x%08x)\n",
+                        debugstr_an((char *)&chunkid, 4), debugstr_an((char *)&temp, 4), offset,
+                        debugstr_an((char *)&temp2, 4), (DWORD)((mov_pos + offset) >> 32), (DWORD)(mov_pos + offset));
+                    relative = -1;
+                }
+            }
+        }
+
+        TRACE("Scanned dwChunkId: %s\n", debugstr_an((char *)&temp, 4));
+        TRACE("dwChunkId: %.4s\n", (char *)&chunkid);
+        TRACE("dwFlags: %08x\n", pAviOldIndex->aIndex[x].dwFlags);
+        TRACE("dwOffset (%s): %08x\n", relative ? "relative" : "absolute", offset);
+        TRACE("dwSize: %08x\n", pAviOldIndex->aIndex[x].dwSize);
+    }
+
+    return S_OK;
+}
+
 static HRESULT AVISplitter_ProcessStreamList(AVISplitterImpl * This, const BYTE * pData, DWORD cb)
 {
     PIN_INFO piOutput;
@@ -585,6 +650,7 @@ static HRESULT AVISplitter_ProcessStreamList(AVISplitterImpl * This, const BYTE
     stream->dwLength = dwLength; /* TODO: Use this for mediaseeking */
 
     hr = Parser_AddPin(&(This->Parser), &piOutput, &props, &amt);
+    CoTaskMemFree(amt.pbFormat);
 
     return hr;
 }
@@ -615,6 +681,7 @@ static HRESULT AVISplitter_ProcessODML(AVISplitterImpl * This, const BYTE * pDat
                 for (x = 0; x < 61; ++x)
                     if (pExtHdr->dwFuture[x])
                         FIXME("dwFuture[%i] = %u (0x%08x)\n", x, pExtHdr->dwFuture[x], pExtHdr->dwFuture[x]);
+                This->ExtHeader = *pExtHdr;
                 break;
             }
         default:
@@ -753,60 +820,20 @@ static HRESULT AVISplitter_InputPin_PreConnect(IPin * iface, IPin * pConnectPin)
         hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
         if (list.fcc == ckidAVIOLDINDEX)
         {
-            int x = 0;
-            AVIOLDINDEX * pAviOldIndex = CoTaskMemAlloc(list.cb + sizeof(RIFFCHUNK));
-            if (!pAviOldIndex)
+            pAviSplit->oldindex = CoTaskMemRealloc(pAviSplit->oldindex, list.cb + sizeof(RIFFCHUNK));
+            if (!pAviSplit->oldindex)
                 return E_OUTOFMEMORY;
-            hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(RIFFCHUNK) + list.cb, (BYTE *)pAviOldIndex);
+
+            hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(RIFFCHUNK) + list.cb, (BYTE *)pAviSplit->oldindex);
             if (hr == S_OK)
             {
-                for (x = 0; x < list.cb / sizeof(pAviOldIndex->aIndex[0]); ++x)
-                {
-                    DWORD temp, temp2, offset, chunkid;
-                    ULONGLONG mov_pos = BYTES_FROM_MEDIATIME(pAviSplit->CurrentChunkOffset) - sizeof(DWORD);
-                    BOOL relative;
-
-                    offset = pAviOldIndex->aIndex[x].dwOffset;
-                    chunkid = pAviOldIndex->aIndex[x].dwChunkId;
-
-                    IAsyncReader_SyncRead(This->pReader, offset, sizeof(DWORD), (BYTE *)&temp);
-                    relative = (chunkid != temp);
-
-                    if (chunkid == mmioFOURCC('7','F','x','x')
-                        && ((char *)&temp)[0] == 'i' && ((char *)&temp)[1] == 'x')
-                        relative = FALSE;
-
-                    if (relative)
-                    {
-                        if (offset + mov_pos < BYTES_FROM_MEDIATIME(pAviSplit->EndOfFile))
-                            hr = IAsyncReader_SyncRead(This->pReader, offset + mov_pos, sizeof(DWORD), (BYTE *)&temp2);
-                        else hr = S_FALSE;
-
-                        if (hr == S_OK && chunkid == mmioFOURCC('7','F','x','x')
-                            && ((char *)&temp2)[0] == 'i' && ((char *)&temp2)[1] == 'x')
-                        {
-                            /* Do nothing, all is great */
-                        }
-                        else if (hr == S_OK && temp2 != chunkid)
-                        {
-                            ERR("Faulty index or bug in handling: Wanted FOURCC: %s, Absolute FOURCC: %s (@ %u), Relative FOURCC: %s (@ %lld)\n",
-                                debugstr_an((char *)&chunkid, 4), debugstr_an((char *)&temp, 4), offset, debugstr_an((char *)&temp2, 4), mov_pos + offset);
-                        }
-                        else if (hr != S_OK)
-                        {
-                            TRACE("hr: %08x\n", hr);
-                        }
-                    }
-
-                    TRACE("Scanned dwChunkId: %s\n", debugstr_an((char *)&temp, 4));
-                    TRACE("dwChunkId: %.4s\n", (char *)&chunkid);
-                    TRACE("dwFlags: %08x\n", pAviOldIndex->aIndex[x].dwFlags);
-                    TRACE("dwOffset (%s): %08x\n", relative ? "relative" : "absolute", offset);
-                    TRACE("dwSize: %08x\n", pAviOldIndex->aIndex[x].dwSize);
-                }
+                AVISplitter_ProcessOldIndex(pAviSplit);
+            }
+            else
+            {
+                CoTaskMemFree(pAviSplit->oldindex);
+                pAviSplit->oldindex = NULL;
             }
-
-            CoTaskMemFree(pAviOldIndex);
         }
         hr = S_OK;
     }
@@ -832,6 +859,17 @@ static HRESULT AVISplitter_Cleanup(LPVOID iface)
     return S_OK;
 }
 
+static HRESULT AVISplitter_Disconnect(LPVOID iface)
+{
+    AVISplitterImpl *This = iface;
+
+    /* TODO: Remove other memory that's allocated during connect */
+    CoTaskMemFree(This->oldindex);
+    This->oldindex = NULL;
+
+    return S_OK;
+}
+
 HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
 {
     HRESULT hr;
@@ -849,8 +887,9 @@ HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
 
     This->pCurrentSample = NULL;
     This->streams = NULL;
+    This->oldindex = NULL;
 
-    hr = Parser_Create(&(This->Parser), &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect, AVISplitter_Cleanup, NULL, NULL, NULL);
+    hr = Parser_Create(&(This->Parser), &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect, AVISplitter_Cleanup, AVISplitter_Disconnect, NULL, NULL, NULL);
 
     if (FAILED(hr))
         return hr;
diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c
index 757717474a9..8daafea8a2c 100644
--- a/dlls/quartz/mpegsplit.c
+++ b/dlls/quartz/mpegsplit.c
@@ -865,6 +865,12 @@ static HRESULT MPEGSplitter_seek(IBaseFilter *iface)
     return hr;
 }
 
+static HRESULT MPEGSplitter_destroy(LPVOID iface)
+{
+    /* TODO: Find memory leaks etc */
+    return S_OK;
+}
+
 HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
 {
     MPEGSplitterImpl *This;
@@ -890,7 +896,7 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
     }
     This->seek_entries = 64;
 
-    hr = Parser_Create(&(This->Parser), &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, NULL, MPEGSplitter_seek, NULL);
+    hr = Parser_Create(&(This->Parser), &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_destroy, NULL, MPEGSplitter_seek, NULL);
     if (FAILED(hr))
     {
         CoTaskMemFree(This);
diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c
index 37cf8eebb47..a0e14f167bf 100644
--- a/dlls/quartz/parser.c
+++ b/dlls/quartz/parser.c
@@ -53,7 +53,7 @@ static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
 }
 
 
-HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
+HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
 {
     HRESULT hr;
     PIN_INFO piInput;
@@ -68,6 +68,7 @@ HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMP
     pParser->state = State_Stopped;
     pParser->pClock = NULL;
     pParser->fnCleanup = fnCleanup;
+    pParser->fnDisconnect = fnDisconnect;
     ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
 
     pParser->cStreams = 0;
@@ -680,7 +681,7 @@ static const IPinVtbl Parser_OutputPin_Vtbl =
     OutputPin_NewSegment
 };
 
-static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
+static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
 {
     HRESULT hr;
     IPinImpl *This = (IPinImpl *)iface;
@@ -692,10 +693,11 @@ static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
         if (This->pConnectedTo)
         {
             FILTER_STATE state;
+            ParserImpl *Parser = (ParserImpl *)This->pinInfo.pFilter;
 
             hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
 
-            if (SUCCEEDED(hr) && (state == State_Stopped))
+            if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
             {
                 IPin_Release(This->pConnectedTo);
                 This->pConnectedTo = NULL;
@@ -738,7 +740,7 @@ static const IPinVtbl Parser_InputPin_Vtbl =
     PullPin_Release,
     OutputPin_Connect,
     Parser_PullPin_ReceiveConnection,
-    Parser_InputPin_Disconnect,
+    Parser_PullPin_Disconnect,
     IPinImpl_ConnectedTo,
     IPinImpl_ConnectionMediaType,
     IPinImpl_QueryPinInfo,
diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h
index 0bba06262bc..3ca342e108e 100644
--- a/dlls/quartz/parser.h
+++ b/dlls/quartz/parser.h
@@ -24,6 +24,7 @@ typedef HRESULT (*PFN_PROCESS_SAMPLE) (LPVOID iface, IMediaSample * pSample);
 typedef HRESULT (*PFN_QUERY_ACCEPT) (LPVOID iface, const AM_MEDIA_TYPE * pmt);
 typedef HRESULT (*PFN_PRE_CONNECT) (IPin * iface, IPin * pConnectPin);
 typedef HRESULT (*PFN_CLEANUP) (LPVOID iface);
+typedef HRESULT (*PFN_DISCONNECT) (LPVOID iface);
 
 struct ParserImpl
 {
@@ -35,6 +36,7 @@ struct ParserImpl
     REFERENCE_TIME rtStreamStart;
     IReferenceClock * pClock;
     PFN_CLEANUP fnCleanup;
+    PFN_DISCONNECT fnDisconnect;
     FILTER_INFO filterInfo;
     CLSID clsid;
 
@@ -54,4 +56,5 @@ typedef struct Parser_OutputPin
 
 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt);
 
-HRESULT Parser_Create(ParserImpl*, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT, PFN_CLEANUP, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate);
+HRESULT Parser_Create(ParserImpl*, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT,
+                      PFN_CLEANUP, PFN_DISCONNECT, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate);
diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c
index 965db5c31f7..544fa4c4970 100644
--- a/dlls/quartz/waveparser.c
+++ b/dlls/quartz/waveparser.c
@@ -418,6 +418,12 @@ static HRESULT WAVEParser_Cleanup(LPVOID iface)
     return S_OK;
 }
 
+static HRESULT WAVEParser_disconnect(LPVOID iface)
+{
+    /* TODO: Find and plug memory leaks */
+    return S_OK;
+}
+
 HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv)
 {
     HRESULT hr;
@@ -435,7 +441,7 @@ HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv)
 
     This->pCurrentSample = NULL;
 
-    hr = Parser_Create(&(This->Parser), &CLSID_WAVEParser, WAVEParser_Sample, WAVEParser_QueryAccept, WAVEParser_InputPin_PreConnect, WAVEParser_Cleanup, NULL, WAVEParserImpl_seek, NULL);
+    hr = Parser_Create(&(This->Parser), &CLSID_WAVEParser, WAVEParser_Sample, WAVEParser_QueryAccept, WAVEParser_InputPin_PreConnect, WAVEParser_Cleanup, WAVEParser_disconnect, NULL, WAVEParserImpl_seek, NULL);
 
     if (FAILED(hr))
         return hr;
-- 
2.24.1