[matroska] r1118 - in trunk/MatroskaUtils/GDC: . GDCMatroska GDCMatroska-Setup common

[email protected]
Newsgroups gmane.comp.multimedia.matroska.cvs
Message-ID <[email protected]>
Author: jcsston
Date: 2005-04-09 22:52:52 +0400 (Sat, 09 Apr 2005)
New Revision: 1118

Added:
   trunk/MatroskaUtils/GDC/GDCMatroska-Setup/
   trunk/MatroskaUtils/GDC/GDCMatroska-Setup/GDCMatroska-Setup.vdproj
   trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.c
   trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.h
   trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.c
   trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.h
Modified:
   trunk/MatroskaUtils/GDC/GDCMatroska/GDCMatroska.vcproj
   trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.cpp
   trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.h
   trunk/MatroskaUtils/GDC/GoogleDesktopComponent.sln
   trunk/MatroskaUtils/GDC/common/GoogleDesktopComponentCommon.vcproj
Log:
New Version of GDCMatroska
Submitted to Google

Modified: trunk/MatroskaUtils/GDC/GDCMatroska/GDCMatroska.vcproj
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/GDCMatroska.vcproj	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/GDCMatroska.vcproj	2005-04-09 18:52:52 UTC (rev 1118)
@@ -75,7 +75,7 @@
 				AdditionalIncludeDirectories=".\;..\;..\..\;..\..\..\libebml;..\..\..\libebml\src\platform\win32;..\..\..\libmatroska"
 				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;GDCMATROSKA_EXPORTS"
 				StringPooling="TRUE"
-				RuntimeLibrary="2"
+				RuntimeLibrary="0"
 				UsePrecompiledHeader="3"
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
@@ -84,7 +84,6 @@
 				Name="VCCustomBuildTool"/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="Unicows.lib"
 				OutputFile="$(OutDir)/GDCMatroska.dll"
 				LinkIncremental="1"
 				ModuleDefinitionFile="GDCMatroska.def"
@@ -149,6 +148,21 @@
 				RelativePath=".\IndexMatroska.cpp">
 			</File>
 			<File
+				RelativePath=".\MatroskaParser.c">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"/>
+				</FileConfiguration>
+			</File>
+			<File
 				RelativePath=".\stdafx.cpp">
 				<FileConfiguration
 					Name="Debug|Win32">
@@ -163,6 +177,21 @@
 						UsePrecompiledHeader="1"/>
 				</FileConfiguration>
 			</File>
+			<File
+				RelativePath=".\Win32Stream.c">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"/>
+				</FileConfiguration>
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"
@@ -172,8 +201,14 @@
 				RelativePath=".\IndexMatroska.h">
 			</File>
 			<File
+				RelativePath=".\MatroskaParser.h">
+			</File>
+			<File
 				RelativePath=".\stdafx.h">
 			</File>
+			<File
+				RelativePath=".\Win32Stream.h">
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"

Modified: trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.cpp
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.cpp	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.cpp	2005-04-09 18:52:52 UTC (rev 1118)
@@ -17,7 +17,7 @@
 
 CIndexMatroska::CIndexMatroska() 
 {
-  m_hMatroskaPropDLL = NULL;
+  
 }
 
 CString CIndexMatroska::GetRegistryValue(HKEY hBaseKey, TCHAR *reg_key, TCHAR *value_key, TCHAR *default_value)
@@ -38,42 +38,6 @@
   return ret_value;
 }
 
-HRESULT CIndexMatroska::LoadMatroskaPropLibrary()
-{
-  m_hMatroskaPropDLL = LoadLibrary(_T("MatroskaProp"));
-  if (m_hMatroskaPropDLL == NULL) {
-    CString filename = GetRegistryValue(HKEY_CLASSES_ROOT, _T("CLSID\\") _T("{780BCB64-0CAF-473c-A9FC-E08C03D75515}") _T("\\InProcServer32\\"), _T(""), _T(""));
-    if (filename.GetLength() > 0) {
-      m_hMatroskaPropDLL = LoadLibrary(filename);
-    }
-  }
-  if (m_hMatroskaPropDLL == NULL)
-    return E_FAIL;
-
-  fnCreateParserObject = (CreateParserObject_def)GetProcAddress(m_hMatroskaPropDLL, "CreateParserObject");
-  if (fnCreateParserObject == NULL)
-    return E_FAIL;
-
-  fnDeleteParserObject = (DeleteParserObject_def)GetProcAddress(m_hMatroskaPropDLL, "DeleteParserObject");    
-  if (fnDeleteParserObject == NULL)
-    return E_FAIL;
-
-  /*
-  fnFillParserObject = (FillParserObject_def)GetProcAddress(m_hMatroskaPropDLL, "FillParserObject");    
-  fnGetTrackCount = (GetTrackCount_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackCount");
-  fnGetTrackUID = (GetTrackUID_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackUID");
-  fnGetTrackType = (GetTrackType_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackType");
-  fnGetTrackTypeLen = (GetTrackTypeLen_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackTypeLen");
-  fnGetTrackTypeStr = (GetTrackTypeStr_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackTypeStr");
-  fnGetTrackCodecIDLen = (GetTrackCodecIDLen_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackCodecIDLen");
-  fnGetTrackCodecIDStr = (GetTrackCodecIDStr_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackCodecIDStr");
-  fnGetTrackLength = (GetTrackLength_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackLength");
-  fnGetTrackVideoInfo = (GetTrackVideoInfo_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackVideoInfo");
-  fnGetTrackAudioInfo = (GetTrackAudioInfo_def)GetProcAddress(m_hMatroskaPropDLL, "GetTrackAudioInfo");
-  */
-  return S_OK;
-}
-
 STDMETHODIMP CIndexMatroska::InterfaceSupportsErrorInfo(REFIID riid)
 {
   static const IID* arr[] = 
@@ -134,72 +98,187 @@
     
     CStringW content;
     
-    MatroskaUtilsNamespace::MatroskaInfoParser *pParser = new MatroskaUtilsNamespace::MatroskaInfoParser(strOriginal);
-    //hr = fnCreateParserObject((void **)&pParser, W2A(strOriginal));
-    pParser->ParseFile();
-    MatroskaUtilsNamespace::MatroskaTrackInfo *pVideoTrack = pParser->GetFirstVideoTrack();
-    MatroskaUtilsNamespace::MatroskaTrackInfo *pAudioTrack = pParser->GetFirstAudioTrack();
-    MatroskaUtilsNamespace::MatroskaTrackInfo *pSubtitleTrack = pParser->GetFirstSubtitleTrack();
-
-    content = A2W(pParser->GetTextReport().c_str());
+    Win32Stream	st;
+    MatroskaFile *mf;
+    char err_msg[256];
+    unsigned int i;
+
+    Win32Stream_Init(&st);  
+    Win32Stream_OpenW(&st, strOriginal);
+
+    /* initialize matroska parser */
+    mf = mkv_OpenEx(&st.base, /* pointer to I/O object */
+      0, /* starting position in the file */
+      0, /* flags, you can set MKVF_AVOID_SEEKS if this is a non-seekable stream */
+      err_msg, sizeof(err_msg)); /* error message is returned here */
+    if (mf == NULL) {
+      Win32Stream_Close(&st);
+      //fprintf(stderr,"Can't parse Matroska file: %s\n", err_msg);
+      return E_FAIL;
+    }
+
+    int audio_Channels = -1;
+    int video_Height = -1;
+    int video_Width = -1;
+    double duration = 0.0;
+    CStringA s;
+
+    SegmentInfo *segInfo = mkv_GetFileInfo(mf);
+    if (segInfo != NULL) {
+      duration = (double)segInfo->Duration;
+
+      char szBuffer[256];
+      szBuffer[0] = 0;
+      for (int i = 0; i < sizeof(segInfo->UID); i++) {
+        size_t len = strlen(szBuffer);
+        _snprintf(&szBuffer[len], 255-len, " 0x%02x", (unsigned char)segInfo->UID[i]);
+      }
+
+      s.Format("<ul>"
+        "<li><b>Segment Info</b></li>"
+        "<ul>"
+        "<li>Segment UID:%s</li>"
+        "<li>Muxing App: %s</li>"
+        "<li>Writing App: %s</li>"
+        "<li>Title: %s</li>"
+        "<li>Filename: %s</li>"
+        "</ul>"
+        "</ul>", 
+        szBuffer, 
+        segInfo->MuxingApp,
+        segInfo->WritingApp,
+        segInfo->Title != NULL ? segInfo->Title : "(null)",
+        segInfo->Filename != NULL ? segInfo->Filename : "(null)");
+      content += CA2W(s);
+    }
+    s.Format("<ul>"
+      "<li><b>Track Info (Count: %u)</b></li>", mkv_GetNumTracks(mf));
+    content += CA2W(s);  
+    /* if track_num was not specified, then list tracks */
+    for (i = 0; i < mkv_GetNumTracks(mf); ++i) {      
+      TrackInfo	*ti = mkv_GetTrackInfo(mf, i);
+      if (ti->Type == TT_VIDEO) {
+        if (video_Width == -1) {
+          video_Height = ti->Video.PixelHeight;
+          video_Width = ti->Video.PixelWidth;
+        }
+        s.Format("<ul>"
+          "<li><b>Track %u</b></li>"
+          "<ul>"
+          "<li>Type: Video</li>"
+          "<li>CodecID: %s</li>"
+          "<li>Language: %s</li>"
+          "<li>Pixel Size: %ix%i</li>"
+          "<li>Display Size: %ix%i</li>"
+          "<li>Enabled: %s</li>"
+          "<li>Default: %s</li>"
+          "<li>Default Duration: %.2fms (%.3f fps)</li>"        
+          "</ul>"
+          "</ul>", 
+          ti->Number, 
+          (ti->CodecID != NULL) ? ti->CodecID : "(null)", 
+          (ti->Language != NULL) ? ti->Language : "(null)", 
+          ti->Video.PixelWidth, ti->Video.PixelHeight, 
+          ti->Video.DisplayWidth, ti->Video.DisplayHeight,
+          ti->Enabled ? "True" : "False",
+          ti->Default ? "True" : "False",
+          (double)ti->DefaultDuration / 1000000.0, 1000000000.0 / (double)ti->DefaultDuration);
+        content += CA2W(s);
+
+      } else if (ti->Type == TT_AUDIO) {
+        if (audio_Channels == -1) {
+          audio_Channels = ti->Audio.Channels;
+        }
+        s.Format("<ul>"
+          "<li><b>Track %u</b></li>"
+          "<ul>"
+          "<li>Type: Audio</li>"
+          "<li>CodecID: %s</li>"
+          "<li>Language: %s</li>"
+          "<li>Channels: %i</li>"
+          "<li>Sampling Rate: %.2f</li>"
+          "<li>Enabled: %s</li>"
+          "<li>Default: %s</li>"
+          "<li>Default Duration: %.2fms (%.3f fps)</li>"    
+          "</ul>"
+          "</ul>", ti->Number, 
+          (ti->CodecID != NULL) ? ti->CodecID : "(null)", 
+          (ti->Language != NULL) ? ti->Language : "(null)", 
+          ti->Audio.Channels, 
+          ti->Audio.SamplingFreq,
+          ti->Enabled ? "True" : "False",
+          ti->Default ? "True" : "False",
+          (double)ti->DefaultDuration / 1000000.0, 1000000000.0 / (double)ti->DefaultDuration);
+        content += CA2W(s);
+
+      } else if (ti->Type == TT_SUB) {
+        s.Format("<ul>"
+          "<li><b>Track %u</b></li>"
+          "<ul>"
+          "<li>Type: Subtitle</li>"
+          "<li>CodecID: %s</li>"
+          "<li>Language: %s</li>"
+          "<li>Enabled: %s</li>"
+          "<li>Default: %s</li>"
+          "<li>Default Duration: %.2fms (%.3f fps)</li>"    
+          "</ul>"
+          "</ul>", 
+          ti->Number, 
+          (ti->CodecID != NULL) ? ti->CodecID : "(null)", 
+          (ti->Language != NULL) ? ti->Language : "(null)",
+          ti->Enabled ? "True" : "False",
+          ti->Default ? "True" : "False",
+          (double)ti->DefaultDuration / 1000000.0, 1000000000.0 / (double)ti->DefaultDuration);
+        content += CA2W(s);
+
+      } else {
+        s.Format("<ul>"
+          "<li><b>Track %u</b></li>"
+          "<ul>"
+          "<li>Type: %i</li>"
+          "<li>CodecID: %s</li>"
+          "<li>Language: %s</li>"
+          "<li>Enabled: %s</li>"
+          "<li>Default: %s</li>"
+          "<li>Default Duration: %.2fms (%.3f fps)</li>"    
+          "</ul>"
+          "</ul>", 
+          ti->Number, 
+          (ti->CodecID != NULL) ? ti->CodecID : "(null)", 
+          ti->Type, (ti->Language != NULL) ? ti->Language : "(null)",
+          ti->Enabled ? "True" : "False",
+          ti->Default ? "True" : "False",
+          (double)ti->DefaultDuration / 1000000.0, 1000000000.0 / (double)ti->DefaultDuration);
+        content += CA2W(s);
+      }
+    }
+    s.Format("</ul>");
+    content += CA2W(s);
+    
     hr = spEvent->AddProperty(CComBSTR(L"content"), CComVariant(content));
-    hr = spEvent->AddProperty(CComBSTR(L"format"), CComVariant("text/plain"));      
+    hr = spEvent->AddProperty(CComBSTR(L"format"), CComVariant("text/html"));      
 
-    double duration = pParser->GetSegmentInfo()->GetDuration();
     duration = duration * 1000.0 * 1000.0;
     CComVariant llDuration;
     llDuration = (ULONG)duration;
     llDuration.ChangeType(VT_UI8);
     hr = spEvent->AddProperty(CComBSTR(L"length"), llDuration);
 
-    if (pVideoTrack != NULL && pVideoTrack->GetVideoInfo() != NULL) {
-      MatroskaUtilsNamespace::MatroskaVideoTrackInfo *info = pVideoTrack->GetVideoInfo();
-      hr = spEvent->AddProperty(CComBSTR(L"width"), CComVariant((unsigned int)info->video_Width, VT_UI4));
-      hr = spEvent->AddProperty(CComBSTR(L"height"), CComVariant((unsigned int)info->video_Height, VT_UI4));
+    if (video_Width != -1) {
+      hr = spEvent->AddProperty(CComBSTR(L"width"), CComVariant((unsigned int)video_Width, VT_UI4));
+      hr = spEvent->AddProperty(CComBSTR(L"height"), CComVariant((unsigned int)video_Height, VT_UI4));
     }
 
-    if (pAudioTrack != NULL && pAudioTrack->GetAudioInfo() != NULL) {
-      MatroskaUtilsNamespace::MatroskaAudioTrackInfo *info = pAudioTrack->GetAudioInfo();
-      hr = spEvent->AddProperty(CComBSTR(L"channels"), CComVariant((unsigned int)info->audio_Channels, VT_UI4));
+    if (audio_Channels != -1) {
+      hr = spEvent->AddProperty(CComBSTR(L"channels"), CComVariant((unsigned int)audio_Channels, VT_UI4));
     }
 
-    UTFstring s;
-    std::string s2;
-    int t;
+    /* close matroska parser */
+    mkv_Close(mf);
+
+    /* close file */
+    Win32Stream_Close(&st);
 
-    s = pParser->GetTagComment();
-    if (s.length() > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"comments"), CComVariant(s.c_str()));
-    }
-
-    s = pParser->GetTagAlbum();
-    if (s.length() > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"album_title"), CComVariant(s.c_str()));
-    }
-
-    s = pParser->GetTagArtist();
-    if (s.length() > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"artist"), CComVariant(s.c_str()));
-    }
-
-    t = pParser->GetTagDiscTrack();
-    if (t > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"track_number"), CComVariant((unsigned int)t, VT_UI4));
-    }
-
-    t = pParser->GetTagYear();
-    if (t > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"year_published"), CComVariant((unsigned int)t, VT_UI4));
-    }
-
-    s2 = pParser->GetTagGenre();
-    if (s2.length() > 0) {
-      hr = spEvent->AddProperty(CComBSTR(L"genre"), CComVariant(s2.c_str()));
-    }
-
-    //hr = fnDeleteParserObject((void **)&pParser);
-    delete pParser;
-
     if (FAILED(hr))
       return Error(L"AddProperty failed", IID_IIndexMatroska, hr);
 

Modified: trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.h
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.h	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/IndexMatroska.h	2005-04-09 18:52:52 UTC (rev 1118)
@@ -4,23 +4,9 @@
 #include "resource.h"       // main symbols
 
 #include "GDCMatroska_h.h"
-#include "MatroskaUtils.h"
+#include "MatroskaParser.h"
+#include "Win32Stream.h"
 
-typedef LONG (WINAPI *CreateParserObject_def)(void **, char *);
-typedef LONG (WINAPI *FillParserObject_def)(void **, bool parseTags, bool parseWholeFile);
-typedef LONG (WINAPI *DeleteParserObject_def)(void **);
-typedef LONG (WINAPI *GetTrackCount_def)(void **);
-typedef LONG (WINAPI *GetTrackUID_def)(void **, int);
-typedef LONG (WINAPI *GetTrackType_def)(void **, int);
-typedef LONG (WINAPI *GetTrackTypeLen_def)(void **, int);
-typedef LONG (WINAPI *GetTrackTypeStr_def)(void **, int, char *);
-typedef LONG (WINAPI *GetTrackCodecIDLen_def)(void **, int);
-typedef LONG (WINAPI *GetTrackCodecIDStr_def)(void **, int, char *);
-typedef LONG (WINAPI *GetTrackLength_def)(void **, int);
-typedef LONG (WINAPI *GetTrackVideoInfo_def)(void **, int, void *);
-typedef LONG (WINAPI *GetTrackAudioInfo_def)(void **, int, void *);
-typedef LONG (WINAPI *SetAR_def)(void **, int, int, int);
-
 // CIndexShortcut
 
 class ATL_NO_VTABLE CIndexMatroska : 
@@ -45,31 +31,14 @@
   DECLARE_PROTECT_FINAL_CONSTRUCT()
 
   CString GetRegistryValue(HKEY hBaseKey, TCHAR *reg_key, TCHAR *value_key, TCHAR *default_value);
-  HRESULT LoadMatroskaPropLibrary();
 
   HRESULT FinalConstruct() {
-    LoadMatroskaPropLibrary();
     return S_OK;
   }
   
   void FinalRelease() {
-    FreeLibrary(m_hMatroskaPropDLL);
   }
   
-  CreateParserObject_def fnCreateParserObject;
-  FillParserObject_def fnFillParserObject;
-  DeleteParserObject_def fnDeleteParserObject;
-  GetTrackCount_def fnGetTrackCount;
-  GetTrackUID_def fnGetTrackUID;
-  GetTrackType_def fnGetTrackType;
-  GetTrackTypeLen_def fnGetTrackTypeLen;
-  GetTrackTypeStr_def fnGetTrackTypeStr;
-  GetTrackCodecIDLen_def fnGetTrackCodecIDLen;
-  GetTrackCodecIDStr_def fnGetTrackCodecIDStr;
-  GetTrackLength_def fnGetTrackLength;
-  GetTrackVideoInfo_def fnGetTrackVideoInfo;
-  GetTrackAudioInfo_def fnGetTrackAudioInfo;
-  HMODULE m_hMatroskaPropDLL;
 public:
   // IIndexShortcut implementation
   STDMETHOD(HandleFile)(BSTR full_path_to_file, IDispatch *event_factory);

Added: trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.c
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.c	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.c	2005-04-09 18:52:52 UTC (rev 1118)
@@ -0,0 +1,3099 @@
+/*
+ * Copyright (c) 2004-2005 Mike Matsnev.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice immediately at the beginning of the file, without modification,
+ *    this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author
+ *    Mike Matsnev.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * $Id: MatroskaParser.c,v 1.31 2005/03/07 11:22:16 mike Exp $
+ * 
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+
+#ifdef _WIN32
+// MS names some functions differently
+#define	alloca	  _alloca
+#define	inline	  __inline
+
+#include <tchar.h>
+#endif
+
+#ifndef EVCBUG
+#define	EVCBUG
+#endif
+
+#include "MatroskaParser.h"
+
+#ifdef MATROSKA_COMPRESSION_SUPPORT
+#include <zlib.h>
+#endif
+
+#define	EBML_VERSION	      1
+#define	EBML_MAX_ID_LENGTH    4
+#define	EBML_MAX_SIZE_LENGTH  8
+#define	MATROSKA_VERSION      1
+#define	MATROSKA_DOCTYPE      "matroska"
+
+#define	MAX_STRING_LEN	      1023
+#define	QSEGSIZE	      512
+#define	MAX_TRACKS	      32
+#define	MAX_READAHEAD	      (512*1024)
+
+#define	DEFAULT_PAGE_SIZE     65536
+#define	MIN_PAGE_SIZE	      4096
+#define	MIN_PAGES	      2
+#define	MAXCLUSTER	      (64*1048576)
+#define	MAXFRAME	      (4*1048576)
+
+#ifdef WIN32
+#define	LL(x)	x##i64
+#define	ULL(x)	x##ui64
+#else
+#define	LL(x)	x##ll
+#define	ULL(x)	x##ull
+#endif
+
+#define	MAXU64		      ULL(0xffffffffffffffff)
+#define	ONE		      ULL(1)
+
+// compatibility
+static char  *mystrdup(struct InputStream *is,const char *src) {
+  size_t  len;
+  char	  *dst;
+
+  if (src==NULL)
+    return NULL;
+
+  len = strlen(src);
+  dst = is->memalloc(is,len+1);
+  if (dst==NULL)
+    return NULL;
+
+  memcpy(dst,src,len+1);
+
+  return dst;
+}
+
+#ifdef _WIN32
+static void  strlcpy(char *dst,const char *src,unsigned size) {
+  unsigned  i;
+
+  for (i=0;i+1<size && src[i];++i)
+    dst[i] = src[i];
+  if (i<size)
+    dst[i] = 0;
+}
+#endif
+
+struct Cue {
+  ulonglong	Time;
+  ulonglong	Position;
+  ulonglong	Block;
+  unsigned char	Track;
+};
+
+struct QueueEntry {
+  struct QueueEntry *next;
+  unsigned int	    Length;
+
+  ulonglong	    Start;
+  ulonglong	    End;
+  ulonglong	    Position;
+
+  unsigned int	    flags;
+};
+
+struct Queue {
+  struct QueueEntry *head;
+  struct QueueEntry *tail;
+};
+
+#define	MPF_ERROR 0x10000
+#define	IBSZ	  1024
+
+#define	RBRESYNC  1
+
+struct MatroskaFile {
+  // parser config
+  unsigned    flags;
+
+  // input
+  InputStream *cache;
+
+  // internal buffering
+  char	      inbuf[IBSZ];
+  ulonglong   bufbase; // file offset of the first byte in buffer
+  int	      bufpos; // current read position in buffer
+  int	      buflen; // valid bytes in buffer
+
+  // error reporting
+  char	      errmsg[128];
+  jmp_buf     jb;
+
+  // pointers to key elements
+  ulonglong   pSegment;
+  ulonglong   pSeekHead;
+  ulonglong   pSegmentInfo;
+  ulonglong   pCluster;
+  ulonglong   pTracks;
+  ulonglong   pCues;
+  ulonglong   pAttachments;
+  ulonglong   pChapters;
+  ulonglong   pTags;
+
+  // flags for key elements
+  struct {
+    unsigned int  SegmentInfo:1;
+    unsigned int  Cluster:1;
+    unsigned int  Tracks:1;
+    unsigned int  Cues:1;
+    unsigned int  Attachments:1;
+    unsigned int  Chapters:1;
+    unsigned int  Tags:1;
+  } seen;
+
+  // file info
+  ulonglong   firstTimecode;
+
+  // SegmentInfo
+  struct SegmentInfo  Seg;
+
+  // Tracks
+  unsigned int	    nTracks,nTracksSize;
+  struct TrackInfo  **Tracks;
+
+  // Queues
+  struct QueueEntry *QFreeList;
+  unsigned int	    nQBlocks,nQBlocksSize;
+  struct QueueEntry **QBlocks;
+  struct Queue	    *Queues;
+  ulonglong	    readPosition;
+  unsigned int	    trackMask;
+  ulonglong	    pSegmentTop;  // offset of next byte after the segment
+  ulonglong	    tcCluster;    // current cluster timecode
+
+  // Cues
+  unsigned int	    nCues,nCuesSize;
+  struct Cue	    *Cues;
+
+  // Attachments
+  unsigned int	    nAttachments,nAttachmentsSize;
+  struct Attachment *Attachments;
+
+  // Chapters
+  unsigned int	    nChapters,nChaptersSize;
+  struct Chapter    *Chapters;
+
+  // Tags
+  unsigned int	    nTags,nTagsSize;
+  struct Tag	    *Tags;
+};
+
+///////////////////////////////////////////////////////////////////////////
+// error reporting
+static void   myvsnprintf_string(char **pdest,char *de,const char *str) {
+  char	*dest = *pdest;
+
+  while (dest < de && *str)
+    *dest++ = *str++;
+
+  *pdest = dest;
+}
+
+static void   myvsnprintf_uint_impl(char **pdest,char *de,int width,int zero,
+				    int neg,unsigned base,int letter,
+				    int ms,ulonglong val)
+{
+  char	*dest = *pdest;
+  char	tmp[21]; /* enough for 64 bit ints */
+  char	*np = tmp + sizeof(tmp);
+  int	rw,pad,trail;
+  char	pc = zero ? '0' : ' ';
+
+  *--np = '\0';
+  while (val != 0) {
+    int	  rem = (int)(val % base);
+    val = val / base;
+
+    *--np = rem < 10 ? rem + '0' : rem - 10 + letter;
+  }
+
+  rw = (int)(tmp - np + sizeof(tmp) - 1);
+  if (ms)
+    ++rw;
+
+  pad = trail = 0;
+
+  if (rw < width)
+    pad = width - rw;
+
+  if (neg)
+    trail = pad, pad = 0;
+
+  if (dest < de && ms)
+    *dest++ = '-';
+
+  while (dest < de && pad--)
+    *dest++ = pc;
+
+  while (dest < de && *np)
+    *dest++ = *np++;
+
+  while (dest < de && trail--)
+    *dest++ = ' ';
+
+  *pdest = dest;
+}
+
+static void   myvsnprintf_uint(char **pdest,char *de,int width,int zero,
+			       int neg,unsigned base,int letter,
+			       ulonglong val)
+{
+  myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
+}
+
+static void   myvsnprintf_int(char **pdest,char *de,int width,int zero,
+			      int neg,unsigned base,int letter,
+			      longlong val)
+{
+  if (val < 0)
+    myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,1,-val);
+  else
+    myvsnprintf_uint_impl(pdest,de,width,zero,neg,base,letter,0,val);
+}
+
+static void   myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
+  // s,d,x,u,ll
+  char	    *de = dest + dsize - 1;
+  int	    state = 0, width, zero, neg, ll;
+
+  if (dsize <= 1) {
+    if (dsize > 0)
+      *dest = '\0';
+    return;
+  }
+
+  while (*fmt && dest < de)
+    switch (state) {
+      case 0:
+	if (*fmt == '%') {
+	  ++fmt;
+	  state = 1;
+	  width = zero = neg = ll = 0;
+	} else
+	  *dest++ = *fmt++;
+	break;
+      case 1:
+	if (*fmt == '-') {
+	  neg = 1;
+	  ++fmt;
+	  state = 2;
+	  break;
+	}
+	state = 2;
+      case 2:
+	if (*fmt >= '0' && *fmt <= '9') {
+	  width = width * 10 + *fmt++ - '0';
+	  break;
+	}
+	state = 3;
+      case 3:
+	if (*fmt == 'l') {
+	  ++ll;
+	  ++fmt;
+	  break;
+	}
+	state = 4;
+      case 4:
+	switch (*fmt) {
+	  case 's':
+	    myvsnprintf_string(&dest,de,va_arg(ap,const char *));
+	    break;
+	  case 'd':
+	    switch (ll) {
+	      case 0:
+		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,int));
+		break;
+	      case 1:
+		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,long));
+		break;
+	      case 2:
+		myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,longlong));
+		break;
+	    }
+	    break;
+	  case 'u':
+	    switch (ll) {
+	      case 0:
+		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned int));
+		break;
+	      case 1:
+		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned long));
+		break;
+	      case 2:
+		myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,ulonglong));
+		break;
+	    }
+	    break;
+	  case 'x':
+	    switch (ll) {
+	      case 0:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned int));
+		break;
+	      case 1:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned long));
+		break;
+	      case 2:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,ulonglong));
+		break;
+	    }
+	    break;
+	  case 'X':
+	    switch (ll) {
+	      case 0:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned int));
+		break;
+	      case 1:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned long));
+		break;
+	      case 2:
+		myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,ulonglong));
+		break;
+	    }
+	    break;
+	  default:
+	    break;
+	}
+	++fmt;
+	state = 0;
+	break;
+      default:
+	state = 0;
+	break;
+    }
+  *dest = '\0';
+}
+
+static void   errorjmp(MatroskaFile *mf,const char *fmt, ...) {
+  va_list   ap;
+
+  va_start(ap, fmt);
+  myvsnprintf(mf->errmsg,sizeof(mf->errmsg),fmt,ap);
+  va_end(ap);
+
+  mf->flags |= MPF_ERROR;
+
+  longjmp(mf->jb,1);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// arrays
+static void *ArrayAlloc(MatroskaFile *mf,void **base,
+			unsigned *cur,unsigned *max,unsigned elem_size)
+{
+  if (*cur>=*max) {
+    void      *np;
+    unsigned  newsize = *max * 2;
+    if (newsize==0)
+      newsize = 1;
+
+    np = mf->cache->memrealloc(mf->cache,*base,newsize*elem_size);
+    if (np==NULL)
+      errorjmp(mf,"Out of memory in ArrayAlloc");
+
+    *base = np;
+    *max = newsize;
+  }
+
+  return (char*)*base + elem_size * (*cur)++;
+}
+
+static void ArrayReleaseMemory(MatroskaFile *mf,void **base,
+			       unsigned cur,unsigned *max,unsigned elem_size)
+{
+  if (cur<*max) {
+    void  *np = mf->cache->memrealloc(mf->cache,*base,cur*elem_size);
+    *base = np;
+    *max = cur;
+  }
+}
+
+
+#define	ASGET(f,s,name)	  ArrayAlloc((f),(void**)&(s)->name,&(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
+#define	AGET(f,name)	  ArrayAlloc((f),(void**)&(f)->name,&(f)->n##name,&(f)->n##name##Size,sizeof(*((f)->name)))
+#define	ARELEASE(f,s,name)  ArrayReleaseMemory((f),(void**)&(s)->name,(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name)))
+
+///////////////////////////////////////////////////////////////////////////
+// queues
+static struct QueueEntry *QPut(struct Queue *q,struct QueueEntry *qe) {
+  if (q->tail)
+    q->tail->next = qe;
+  qe->next = NULL;
+  q->tail = qe;
+  if (q->head==NULL)
+    q->head = qe;
+
+  return qe;
+}
+
+static struct QueueEntry  *QGet(struct Queue *q) {
+  struct QueueEntry   *qe = q->head;
+  if (qe == NULL)
+    return NULL;
+  q->head = qe->next;
+  if (q->tail == qe)
+    q->tail = NULL;
+  return qe;
+}
+
+static struct QueueEntry  *QAlloc(MatroskaFile *mf) {
+  struct QueueEntry   *qe,**qep;
+  if (mf->QFreeList == NULL) {
+    unsigned	      i;
+
+    qep = AGET(mf,QBlocks);
+
+    *qep = mf->cache->memalloc(mf->cache,QSEGSIZE * sizeof(*qe));
+    if (*qep == NULL)
+      errorjmp(mf,"Ouf of memory");
+
+    qe = *qep;
+
+    for (i=0;i<QSEGSIZE-1;++i)
+      qe[i].next = qe+i+1;
+    qe[QSEGSIZE-1].next = NULL;
+
+    mf->QFreeList = qe;
+  }
+
+  qe = mf->QFreeList;
+  mf->QFreeList = qe->next;
+
+  return qe;
+}
+
+static inline void QFree(MatroskaFile *mf,struct QueueEntry *qe) {
+  qe->next = mf->QFreeList;
+  mf->QFreeList = qe;
+}
+
+// fill the buffer at current position
+static void fillbuf(MatroskaFile *mf) {
+  int	    rd;
+
+  // advance buffer pointers
+  mf->bufbase += mf->buflen;
+  mf->buflen = mf->bufpos = 0;
+
+  // get the relevant page
+  rd = mf->cache->read(mf->cache, mf->bufbase, mf->inbuf, IBSZ);
+  if (rd<0)
+    errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
+
+  mf->buflen = rd;
+}
+
+// fill the buffer and return next char
+static int  nextbuf(MatroskaFile *mf) {
+  fillbuf(mf);
+
+  if (mf->bufpos < mf->buflen)
+    return (unsigned char)(mf->inbuf[mf->bufpos++]);
+
+  return EOF;
+}
+
+static inline int readch(MatroskaFile *mf) {
+  return mf->bufpos < mf->buflen ? (unsigned char)(mf->inbuf[mf->bufpos++]) : nextbuf(mf);
+}
+
+static inline ulonglong	filepos(MatroskaFile *mf) {
+  return mf->bufbase + mf->bufpos;
+}
+
+static void   readbytes(MatroskaFile *mf,void *buffer,int len) {
+  char	*cp = buffer;
+  int	nb = mf->buflen - mf->bufpos;
+
+  if (nb > len)
+    nb = len;
+
+  memcpy(cp, mf->inbuf + mf->bufpos, nb);
+  mf->bufpos += nb;
+  len -= nb;
+  cp += nb;
+
+  if (len>0) {
+    mf->bufbase += mf->buflen;
+    mf->bufpos = mf->buflen = 0;
+
+    nb = mf->cache->read(mf->cache, mf->bufbase, cp, len);
+    if (nb<0)
+      errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache));
+    if (nb != len)
+      errorjmp(mf,"Short read: got %d bytes of %d",nb,len);
+    mf->bufbase += len;
+  }
+}
+
+static void   skipbytes(MatroskaFile *mf,ulonglong len) {
+  int	    nb = mf->buflen - mf->bufpos;
+
+  if (nb > len)
+    nb = (int)len;
+
+  mf->bufpos += nb;
+  len -= nb;
+
+  if (len>0) {
+    mf->bufbase += mf->buflen;
+    mf->bufpos = mf->buflen = 0;
+
+    mf->bufbase += len;
+  }
+}
+
+static void seek(MatroskaFile *mf,ulonglong pos) {
+  // see if pos is inside buffer
+  if (pos>=mf->bufbase && pos<mf->bufbase+mf->buflen)
+    mf->bufpos = (unsigned)(pos - mf->bufbase);
+  else {
+    // invalidate buffer and set pointer
+    mf->bufbase = pos;
+    mf->buflen = mf->bufpos = 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// floating point
+static inline MKFLOAT	mkfi(int i) {
+#ifdef MATROSKA_INTEGER_ONLY
+  MKFLOAT  f;
+  f.v = (longlong)i << 32;
+  return f;
+#else
+  return i;
+#endif
+}
+
+static inline longlong mul3(MKFLOAT scale,longlong tc) {
+#ifdef MATROSKA_INTEGER_ONLY
+  //             x1 x0
+  //             y1 y0
+  //    --------------
+  //             x0*y0
+  //          x1*y0
+  //          x0*y1
+  //       x1*y1
+  //    --------------
+  //       .. r1 r0 ..
+  //
+  //    r = ((x0*y0) >> 32) + (x1*y0) + (x0*y1) + ((x1*y1) << 32)
+  unsigned    x0,x1,y0,y1;
+  ulonglong   p;
+  char	      sign = 0;
+
+  if (scale.v < 0)
+    sign = !sign, scale.v = -scale.v;
+  if (tc < 0)
+    sign = !sign, tc = -tc;
+
+  x0 = (unsigned)scale.v;
+  x1 = (unsigned)((ulonglong)scale.v >> 32);
+  y0 = (unsigned)tc;
+  y1 = (unsigned)((ulonglong)tc >> 32);
+
+  p = (ulonglong)x0*y0 >> 32;
+  p += (ulonglong)x0*y1;
+  p += (ulonglong)x1*y0;
+  p += (ulonglong)(x1*y1) << 32;
+
+  return p;
+#else
+  return (longlong)(scale * tc);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////
+// EBML support
+static int   readID(MatroskaFile *mf) {
+  int	c1,c2,c3,c4;
+
+  c1 = readch(mf);
+  if (c1 == EOF)
+    return EOF;
+
+  if (c1 & 0x80)
+    return c1;
+
+  if ((c1 & 0xf0) == 0)
+    errorjmp(mf,"Invalid first byte of EBML ID: %02X",c1);
+
+  c2 = readch(mf);
+  if (c2 == EOF)
+fail:
+    errorjmp(mf,"Got EOF while reading EBML ID");
+
+  if ((c1 & 0xc0) == 0x40)
+    return (c1<<8) | c2;
+
+  c3 = readch(mf);
+  if (c3 == EOF)
+    goto fail;
+
+  if ((c1 & 0xe0) == 0x20)
+    return (c1<<16) | (c2<<8) | c3;
+
+  c4 = readch(mf);
+  if (c4 == EOF)
+    goto fail;
+
+  if ((c1 & 0xf0) == 0x10)
+    return (c1<<24) | (c2<<16) | (c3<<8) | c4;
+
+  return 0; // NOT REACHED
+}
+
+static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) {
+  int		c,d,m;
+  ulonglong	v = 0;
+
+  c = readch(mf);
+  if (c == EOF)
+    return EOF;
+
+  if (c == 0)
+    errorjmp(mf,"Invalid first byte of EBML integer: 0");
+
+  for (m=0;;++m) {
+    if (c & (0x80 >> m)) {
+      c &= 0x7f >> m;
+      if (mask)
+	*mask = m;
+      return v | ((ulonglong)c << m*8);
+    }
+    d = readch(mf);
+    if (d == EOF)
+      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
+    v = (v<<8) | d;
+  }
+  // NOT REACHED
+}
+
+static inline ulonglong	readVLUInt(MatroskaFile *mf) {
+  return readVLUIntImp(mf,NULL);
+}
+
+static ulonglong	readSize(MatroskaFile *mf) {
+  int	    m;
+  ulonglong v = readVLUIntImp(mf,&m);
+
+  // see if it's unspecified
+  if (v == (MAXU64 >> (57-m*7)))
+    errorjmp(mf,"Unspecified element size is not supported here.");
+
+  return v;
+}
+
+static inline longlong	readVLSInt(MatroskaFile *mf) {
+  static longlong bias[8] = { (ONE<<6)-1, (ONE<<13)-1, (ONE<<20)-1, (ONE<<27)-1,
+			      (ONE<<34)-1, (ONE<<41)-1, (ONE<<48)-1, (ONE<<55)-1 };
+
+  int	    m;
+  longlong  v = readVLUIntImp(mf,&m);
+
+  return v - bias[m];
+}
+
+static ulonglong  readUInt(MatroskaFile *mf,unsigned int len) {
+  int		c;
+  unsigned int	m = len;
+  ulonglong	v = 0;
+
+  if (len==0)
+    return v;
+  if (len>8)
+    errorjmp(mf,"Unsupported integer size in readUInt: %u",len);
+
+  do {
+    c = readch(mf);
+    if (c == EOF)
+      errorjmp(mf,"Got EOF while reading EBML unsigned integer");
+    v = (v<<8) | c;
+  } while (--m);
+
+  return v;
+}
+
+static inline longlong	readSInt(MatroskaFile *mf,unsigned int len) {
+  longlong	v = readUInt(mf,(unsigned)len);
+  int		s = 64 - (len<<3);
+  return (v << s) >> s;
+}
+
+static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
+#ifdef MATROSKA_INTEGER_ONLY
+  MKFLOAT	  f;
+  int		  shift;
+#else
+  union {
+    unsigned int  ui;
+    ulonglong	  ull;
+    float	  f;
+    double	  d;
+  } u;
+#endif
+
+  if (len!=4 && len!=8)
+    errorjmp(mf,"Invalid float size in readFloat: %u",len);
+
+#ifdef MATROSKA_INTEGER_ONLY
+  if (len == 4) {
+    unsigned  ui = (unsigned)readUInt(mf,(unsigned)len);
+    f.v = (ui & 0x7fffff) | 0x800000;
+    if (ui & 0x80000000)
+      f.v = -f.v;
+    shift = (ui >> 23) & 0xff;
+    if (shift == 0) // assume 0
+zero:
+      shift = 0, f.v = 0;
+    else if (shift == 255)
+inf:
+      if (ui & 0x80000000)
+	f.v = LL(0x8000000000000000);
+      else
+	f.v = LL(0x7fffffffffffffff);
+    else {
+      shift += -127 + 9;
+      if (shift > 39)
+	goto inf;
+shift:
+      if (shift < 0)
+	f.v = f.v >> -shift;
+      else if (shift > 0)
+	f.v = f.v << shift;
+    }
+  } else if (len == 8) {
+    ulonglong  ui = readUInt(mf,(unsigned)len);
+    f.v = (ui & LL(0xfffffffffffff)) | LL(0x10000000000000);
+    if (ui & 0x80000000)
+      f.v = -f.v;
+    shift = (int)((ui >> 52) & 0x7ff);
+    if (shift == 0) // assume 0
+      goto zero;
+    else if (shift == 2047)
+      goto inf;
+    else {
+      shift += -1023 - 20;
+      if (shift > 10)
+	goto inf;
+      goto shift;
+    }
+  }
+
+  return f;
+#else
+  if (len==4) {
+    u.ui = (unsigned int)readUInt(mf,(unsigned)len);
+    return u.f;
+  }
+
+  if (len==8) {
+    u.ull = readUInt(mf,(unsigned)len);
+    return u.d;
+  }
+
+  return 0;
+#endif
+}
+
+static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
+  int	  nread;
+
+  if (buflen<1)
+    errorjmp(mf,"Invalid buffer size in readString: %d",buflen);
+
+  nread = buflen - 1;
+
+  if (nread > len)
+    nread = (int)len;
+
+  readbytes(mf,buffer,nread);
+  len -= nread;
+
+  if (len>0)
+    skipbytes(mf,len);
+
+  buffer[nread] = '\0';
+}
+
+///////////////////////////////////////////////////////////////////////////
+// file parser
+#define	FOREACH(f,tl) \
+  { \
+    ulonglong	tmplen = (tl); \
+    { \
+      ulonglong   start = filepos(f); \
+      ulonglong   cur,len; \
+      int	      id; \
+      for (;;) { \
+	cur = filepos(mf); \
+	if (cur == start + tmplen) \
+	  break; \
+	id = readID(f); \
+	if (id==EOF) \
+	  errorjmp(mf,"Unexpected EOF while reading EBML container"); \
+	len = readSize(mf); \
+	switch (id) {
+
+#define	ENDFOR1(f) \
+	default: \
+	  skipbytes(f,len); \
+	  break; \
+	}
+#define	ENDFOR2() \
+      } \
+    } \
+  }
+
+#define	ENDFOR(f) ENDFOR1(f) ENDFOR2()
+
+#define	myalloca(f,c) alloca(c)
+#define	STRGETF(f,v,len,func) \
+  { \
+    char *TmpVal; \
+    unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \
+    TmpVal = func(f->cache,TmpLen+1); \
+    if (TmpVal == NULL) \
+      errorjmp(mf,"Out of memory"); \
+    readString(f,len,TmpVal,TmpLen+1); \
+    (v) = TmpVal; \
+  }
+
+#define	STRGETA(f,v,len)  STRGETF(f,v,len,myalloca)
+#define	STRGETM(f,v,len)  STRGETF(f,v,len,f->cache->memalloc)
+
+static int  IsWritingApp(MatroskaFile *mf,const char *str) {
+  const char  *cp = mf->Seg.WritingApp;
+  if (!cp)
+    return 0;
+
+  while (*str && *str++==*cp++) ;
+
+  return !*str;
+}
+
+static void parseEBML(MatroskaFile *mf,ulonglong toplen) {
+  ulonglong v;
+  char	    buf[32];
+
+  FOREACH(mf,toplen)
+    case 0x4286: // Version
+      v = readUInt(mf,(unsigned)len);
+      break;
+    case 0x42f7: // ReadVersion
+      v = readUInt(mf,(unsigned)len);
+      if (v > EBML_VERSION)
+	errorjmp(mf,"File requires version %d EBML parser",(int)v);
+      break;
+    case 0x42f2: // MaxIDLength
+      v = readUInt(mf,(unsigned)len);
+      if (v > EBML_MAX_ID_LENGTH)
+	errorjmp(mf,"File has identifiers longer than %d",(int)v);
+      break;
+    case 0x42f3: // MaxSizeLength
+      v = readUInt(mf,(unsigned)len);
+      if (v > EBML_MAX_SIZE_LENGTH)
+	errorjmp(mf,"File has integers longer than %d",(int)v);
+      break;
+    case 0x4282: // DocType
+      readString(mf,len,buf,sizeof(buf));
+      if (strcmp(buf,MATROSKA_DOCTYPE))
+	errorjmp(mf,"Unsupported DocType: %s",buf);
+      break;
+    case 0x4287: // DocTypeVersion
+      v = readUInt(mf,(unsigned)len);
+      break;
+    case 0x4285: // DocTypeReadVersion
+      v = readUInt(mf,(unsigned)len);
+      if (v > MATROSKA_VERSION)
+	errorjmp(mf,"File requires version %d Matroska parser",(int)v);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseSeekEntry(MatroskaFile *mf,ulonglong toplen) {
+  int	    seekid = 0;
+  ulonglong pos = (ulonglong)-1;
+
+  FOREACH(mf,toplen)
+    case 0x53ab: // SeekID
+      if (len>EBML_MAX_ID_LENGTH)
+	errorjmp(mf,"Invalid ID size in parseSeekEntry: %d\n",(int)len);
+      seekid = (int)readUInt(mf,(unsigned)len);
+      break;
+    case 0x53ac: // SeekPos
+      pos = readUInt(mf,(unsigned)len);
+      break;
+  ENDFOR(mf);
+
+  if (pos == (ulonglong)-1)
+    errorjmp(mf,"Invalid element position in parseSeekEntry");
+
+  pos += mf->pSegment;
+  switch (seekid) {
+    case 0x114d9b74: // next SeekHead
+      if (mf->pSeekHead)
+	errorjmp(mf,"SeekHead contains more than one SeekHead pointer");
+      mf->pSeekHead = pos;
+      break;
+    case 0x1549a966: // SegmentInfo
+      mf->pSegmentInfo = pos;
+      break;
+    case 0x1f43b675: // Cluster
+      if (!mf->pCluster)
+	mf->pCluster = pos;
+      break;
+    case 0x1654ae6b: // Tracks
+      mf->pTracks = pos;
+      break;
+    case 0x1c53bb6b: // Cues
+      mf->pCues = pos;
+      break;
+    case 0x1941a469: // Attachments
+      mf->pAttachments = pos;
+      break;
+    case 0x1043a770: // Chapters
+      mf->pChapters = pos;
+      break;
+    case 0x1254c367: // tags
+      mf->pTags = pos;
+      break;
+  }
+}
+
+static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) {
+  FOREACH(mf,toplen)
+    case 0x4dbb:
+      parseSeekEntry(mf,len);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
+  MKFLOAT     duration;
+
+  if (mf->seen.SegmentInfo) {
+    skipbytes(mf,toplen);
+    return;
+  }
+
+  mf->seen.SegmentInfo = 1;
+  mf->Seg.TimecodeScale = 1000000; // Default value
+
+  FOREACH(mf,toplen)
+    case 0x73a4: // SegmentUID
+      if (len!=sizeof(mf->Seg.UID))
+	errorjmp(mf,"SegmentUID size is not %d bytes",mf->Seg.UID);
+      readbytes(mf,mf->Seg.UID,sizeof(mf->Seg.UID));
+      break;
+    case 0x7384: // SegmentFilename
+      STRGETM(mf,mf->Seg.Filename,len);
+      break;
+    case 0x3cb923: // PrevUID
+      if (len!=sizeof(mf->Seg.PrevUID))
+	errorjmp(mf,"PrevUID size is not %d bytes",mf->Seg.PrevUID);
+      readbytes(mf,mf->Seg.PrevUID,sizeof(mf->Seg.PrevUID));
+      break;
+    case 0x3c83ab: // PrevFilename
+      STRGETM(mf,mf->Seg.PrevFilename,len);
+      break;
+    case 0x3eb923: // NextUID
+      if (len!=sizeof(mf->Seg.NextUID))
+	errorjmp(mf,"NextUID size is not %d bytes",mf->Seg.NextUID);
+      readbytes(mf,mf->Seg.NextUID,sizeof(mf->Seg.NextUID));
+      break;
+    case 0x3e83bb: // NextFilename
+      STRGETM(mf,mf->Seg.NextFilename,len);
+      break;
+    case 0x2ad7b1: // TimecodeScale
+      mf->Seg.TimecodeScale = readUInt(mf,(unsigned)len);
+      if (mf->Seg.TimecodeScale == 0)
+	errorjmp(mf,"Segment timecode scale is zero");
+      break;
+    case 0x4489: // Duration
+      duration = readFloat(mf,(unsigned)len);
+      break;
+    case 0x4461: // DateUTC
+      mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
+      break;
+    case 0x7ba9: // Title
+      STRGETM(mf,mf->Seg.Title,len);
+      break;
+    case 0x4d80: // MuxingApp
+      STRGETM(mf,mf->Seg.MuxingApp,len);
+      break;
+    case 0x5741: // WritingApp
+      STRGETM(mf,mf->Seg.WritingApp,len);
+      break;
+  ENDFOR(mf);
+
+  mf->Seg.Duration = mul3(duration,mf->Seg.TimecodeScale);
+}
+
+static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
+  mf->seen.Cluster = 1;
+  mf->firstTimecode = 0;
+
+  FOREACH(mf,toplen)
+    case 0xe7: // Timecode
+      mf->firstTimecode += readUInt(mf,(unsigned)len);
+      break;
+    case 0xa0: // BlockGroup
+      FOREACH(mf,len)
+	case 0xa1: // Block
+	  readVLUInt(mf); // track number
+	  mf->firstTimecode += readSInt(mf,2); 
+
+	  skipbytes(mf,start + toplen - filepos(mf));
+	  return;
+      ENDFOR(mf);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseVideoInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
+  ulonglong v;
+  char	    dW = 0, dH = 0;
+
+  FOREACH(mf,toplen)
+    case 0x9a: // FlagInterlaced
+      ti->Video.Interlaced = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x53b8: // StereoMode
+      v = readUInt(mf,(unsigned)len);
+      if (v>3)
+	errorjmp(mf,"Invalid stereo mode");
+      ti->Video.StereoMode = (unsigned char)v;
+      break;
+    case 0xb0: // PixelWidth
+      v = readUInt(mf,(unsigned)len);
+      if (v>0xffffffff)
+	errorjmp(mf,"PixelWidth is too large");
+      ti->Video.PixelWidth = (unsigned)v;
+      if (!dW)
+	ti->Video.DisplayWidth = ti->Video.PixelWidth;
+      break;
+    case 0xba: // PixelHeight
+      v = readUInt(mf,(unsigned)len);
+      if (v>0xffffffff)
+	errorjmp(mf,"PixelHeight is too large");
+      ti->Video.PixelHeight = (unsigned)v;
+      if (!dH)
+	ti->Video.DisplayHeight = ti->Video.PixelHeight;
+      break;
+    case 0x54b0: // DisplayWidth
+      v = readUInt(mf,(unsigned)len);
+      if (v>0xffffffff)
+	errorjmp(mf,"DisplayWidth is too large");
+      ti->Video.DisplayWidth = (unsigned)v;
+      dW = 1;
+      break;
+    case 0x54ba: // DisplayHeight
+      v = readUInt(mf,(unsigned)len);
+      if (v>0xffffffff)
+	errorjmp(mf,"DisplayHeight is too large");
+      ti->Video.DisplayHeight = (unsigned)v;
+      dH = 1;
+      break;
+    case 0x54b2: // DisplayUnit
+      v = readUInt(mf,(unsigned)len);
+      if (v>2)
+	errorjmp(mf,"Invalid DisplayUnit: %d",(int)v);
+      ti->Video.DisplayUnit = (unsigned char)v;
+      break;
+    case 0x54b3: // AspectRatioType
+      v = readUInt(mf,(unsigned)len);
+      if (v>2)
+	errorjmp(mf,"Invalid AspectRatioType: %d",(int)v);
+      ti->Video.AspectRatioType = (unsigned char)v;
+      break;
+    case 0x2eb524: // ColourSpace
+      ti->Video.ColourSpace = (unsigned)readUInt(mf,4);
+      break;
+    case 0x2fb523: // GammaValue
+      ti->Video.GammaValue = readFloat(mf,(unsigned)len);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseAudioInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) {
+  ulonglong   v;
+
+  FOREACH(mf,toplen)
+    case 0xb5: // SamplingFrequency
+      ti->Audio.SamplingFreq = readFloat(mf,(unsigned)len);
+      break;
+    case 0x78b5: // OutputSamplingFrequency
+      ti->Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len);
+      break;
+    case 0x9f: // Channels
+      v = readUInt(mf,(unsigned)len);
+      if (v<1 || v>255)
+	errorjmp(mf,"Invalid Channels value");
+      ti->Audio.Channels = (unsigned char)v;
+      break;
+    case 0x7d7b: // ChannelPositions
+      skipbytes(mf,len);
+      break;
+    case 0x6264: // BitDepth
+      v = readUInt(mf,(unsigned)len);
+      if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI"))
+	errorjmp(mf,"Invalid BitDepth: %d",(int)v);
+      ti->Audio.BitDepth = (unsigned char)v;
+      break;
+  ENDFOR(mf);
+
+  if (mkv_TruncFloat(ti->Audio.OutputSamplingFreq)==0)
+    ti->Audio.OutputSamplingFreq = ti->Audio.SamplingFreq;
+}
+
+static void CopyStr(char **src,char **dst) {
+  size_t l;
+
+  if (!*src)
+    return;
+
+  l = strlen(*src)+1;
+  memcpy(*dst,*src,l);
+  *src = *dst;
+  *dst += l;
+}
+
+static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
+  struct TrackInfo  t,*tp,**tpp;
+  ulonglong	    v;
+  char		    *cp = NULL;
+  size_t	    cplen = 0, cpadd = 0;
+
+  if (mf->nTracks >= MAX_TRACKS)
+    errorjmp(mf,"Too many tracks.");
+
+  // clear track info
+  memset(&t,0,sizeof(t));
+
+  // fill default values
+  t.Enabled = 1;
+  t.Default = 1;
+  t.Lacing = 1;
+  t.TimecodeScale = mkfi(1);
+  t.DecodeAll = 1;
+
+  FOREACH(mf,toplen)
+    case 0xd7: // TrackNumber
+      v = readUInt(mf,(unsigned)len);
+      if (v>255)
+	errorjmp(mf,"Track number is >255 (%d)",(int)v);
+      t.Number = (unsigned char)v;
+      break;
+    case 0x73c5: // TrackUID
+      t.UID = readUInt(mf,(unsigned)len);
+      break;
+    case 0x83: // TrackType
+      v = readUInt(mf,(unsigned)len);
+      if (v<1 || v>254)
+	errorjmp(mf,"Invalid track type: %d",(int)v);
+      t.Type = (unsigned char)v;
+      if (t.Type == 2) { // fill defaults for audio tracks
+	t.Audio.Channels = 1;
+	t.Audio.SamplingFreq = mkfi(8000);
+      }
+      break;
+    case 0xb9: // Enabled
+      t.Enabled = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x88: // Default
+      t.Default = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x9c: // Lacing
+      t.Lacing = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x6de7: // MinCache
+      v = readUInt(mf,(unsigned)len);
+      if (v > 0xffffffff)
+	errorjmp(mf,"MinCache is too large");
+      t.MinCache = (unsigned)v;
+      break;
+    case 0x6df8: // MaxCache
+      v = readUInt(mf,(unsigned)len);
+      if (v > 0xffffffff)
+	errorjmp(mf,"MaxCache is too large");
+      t.MaxCache = (unsigned)v;
+      break;
+    case 0x23e383: // DefaultDuration
+      t.DefaultDuration = readUInt(mf,(unsigned)len);
+      break;
+    case 0x23314f: // TrackTimecodeScale
+      t.TimecodeScale = readFloat(mf,(unsigned)len);
+      break;
+    case 0x536e: // Name
+      if (t.Name)
+	errorjmp(mf,"Duplicate Track Name");
+      STRGETA(mf,t.Name,len);
+      break;
+    case 0x22b59c: // Language
+      if (t.Language)
+	errorjmp(mf,"Duplicate Track Language");
+      STRGETA(mf,t.Language,len);
+      break;
+    case 0x86: // CodecID
+      if (t.CodecID)
+	errorjmp(mf,"Duplicate CodecID");
+      STRGETA(mf,t.CodecID,len);
+      break;
+    case 0x63a2: // CodecPrivate
+      if (cp)
+	errorjmp(mf,"Duplicate CodecPrivate");
+      if (len>262144) // 256KB
+	errorjmp(mf,"CodecPrivate is too large: %d",(int)len);
+      cplen = (unsigned)len;
+      cp = alloca(cplen);
+      readbytes(mf,cp,(int)cplen);
+      break;
+    case 0x258688: // CodecName
+      skipbytes(mf,len);
+      break;
+    case 0x3a9697: // CodecSettings
+      skipbytes(mf,len);
+      break;
+    case 0x3b4040: // CodecInfoURL
+      skipbytes(mf,len);
+      break;
+    case 0x26b240: // CodecDownloadURL
+      skipbytes(mf,len);
+      break;
+    case 0xaa: // CodecDecodeAll
+      t.DecodeAll = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x6fab: // TrackOverlay
+      v = readUInt(mf,(unsigned)len);
+      if (v>255)
+	errorjmp(mf,"Track number in TrackOverlay is too large: %d",(int)v);
+      t.TrackOverlay = (unsigned char)v;
+      break;
+    case 0xe0: // VideoInfo
+      parseVideoInfo(mf,len,&t);
+      break;
+    case 0xe1: // AudioInfo
+      parseAudioInfo(mf,len,&t);
+      break;
+    case 0x6d80: // ContentEncodings
+      FOREACH(mf,len)
+	case 0x6240: // ContentEncoding
+	  FOREACH(mf,len)
+	    case 0x5031: // ContentEncodingOrder
+	      readUInt(mf,(unsigned)len);
+	      break;
+	    case 0x5032: // ContentEncodingScope
+	      readUInt(mf,(unsigned)len);
+	      break;
+	    case 0x5033: // ContentEncodingType
+	      readUInt(mf,(unsigned)len);
+	      break;
+	    case 0x5034: // ContentCompression
+	      // fill in defaults
+	      t.CompEnabled = 1;
+	      t.CompMethod = COMP_ZLIB;
+	      FOREACH(mf,len)
+		case 0x4254: // ContentCompAlgo
+		  v = readUInt(mf,(unsigned)len);
+		  if (v != 0)
+		    errorjmp(mf,"Unsupported compression algorithm: %d",(int)v);
+		  t.CompEnabled = 1;
+		  t.CompMethod = COMP_ZLIB;
+		  break;
+		case 0x4255: // ContentCompSettings
+		  skipbytes(mf,len);
+		  break;
+	      ENDFOR(mf);
+	      break;
+	      // TODO Implement Encryption/Signatures
+	  ENDFOR(mf);
+	  break;
+      ENDFOR(mf);
+      break;
+  ENDFOR(mf);
+
+  // validate track info
+  if (!t.CodecID)
+    errorjmp(mf,"Track has no Codec ID");
+
+  // allocate new track
+  tpp = AGET(mf,Tracks);
+
+  // copy strings
+  if (t.Name)
+    cpadd += strlen(t.Name)+1;
+  if (t.Language)
+    cpadd += strlen(t.Language)+1;
+  if (t.CodecID)
+    cpadd += strlen(t.CodecID)+1;
+
+  tp = mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cpadd);
+  if (tp == NULL)
+    errorjmp(mf,"Out of memory");
+
+  memcpy(tp,&t,sizeof(*tp));
+  memcpy(tp+1,cp,cplen);
+  if (cplen) {
+    tp->CodecPrivate = tp+1;
+    tp->CodecPrivateSize = (unsigned)cplen;
+  }
+
+  cp = (char*)(tp+1) + cplen;
+  CopyStr(&tp->Name,&cp);
+  CopyStr(&tp->Language,&cp);
+  CopyStr(&tp->CodecID,&cp);
+
+  // set default language
+  if (!tp->Language)
+    tp->Language="eng";
+
+  *tpp = tp;
+}
+
+static void parseTracks(MatroskaFile *mf,ulonglong toplen) {
+  mf->seen.Tracks = 1;
+  FOREACH(mf,toplen)
+    case 0xae: // TrackEntry
+      parseTrackEntry(mf,len);
+      break;
+  ENDFOR(mf);
+}
+
+static void addCue(MatroskaFile *mf,ulonglong pos,ulonglong timecode) {
+  struct Cue  *cc = AGET(mf,Cues);
+  cc->Time = timecode;
+  cc->Position = pos;
+  cc->Track = 0;
+  cc->Block = 0;
+}
+
+static void fixupCues(MatroskaFile *mf) {
+  // adjust cues, shift cues if file does not start at 0
+  unsigned  i;
+  longlong  adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
+
+  for (i=0;i<mf->nCues;++i) {
+    mf->Cues[i].Time *= mf->Seg.TimecodeScale;
+    mf->Cues[i].Time -= adjust;
+  }
+}
+
+static void parseCues(MatroskaFile *mf,ulonglong toplen) {
+  jmp_buf     jb;
+  ulonglong   v;
+  struct Cue  cc;
+  unsigned    i,j,k;
+
+  mf->seen.Cues = 1;
+  mf->nCues = 0;
+  cc.Block = 0;
+
+  memcpy(&jb,&mf->jb,sizeof(jb));
+
+  if (setjmp(mf->jb)) {
+    memcpy(&mf->jb,&jb,sizeof(jb));
+    mf->nCues = 0;
+    mf->seen.Cues = 0;
+    return;
+  }
+
+  FOREACH(mf,toplen)
+    case 0xbb: // CuePoint
+      FOREACH(mf,len)
+	case 0xb3: // CueTime
+	  cc.Time = readUInt(mf,(unsigned)len);
+	  break;
+	case 0xb7: // CueTrackPositions
+	  FOREACH(mf,len)
+	    case 0xf7: // CueTrack
+	      v = readUInt(mf,(unsigned)len);
+	      if (v>255)
+		errorjmp(mf,"CueTrack points to an invalid track: %d",(int)v);
+	      cc.Track = (unsigned char)v;
+	      break;
+	    case 0xf1: // CueClusterPosition
+	      cc.Position = readUInt(mf,(unsigned)len);
+	      break;
+	    case 0x5378: // CueBlockNumber
+	      cc.Block = readUInt(mf,(unsigned)len);
+	      break;
+	    case 0xea: // CodecState
+	      readUInt(mf,(unsigned)len);
+	      break;
+	    case 0xdb: // CueReference
+	      FOREACH(mf,len)
+		case 0x96: // CueRefTime
+		  readUInt(mf,(unsigned)len);
+		  break;
+		case 0x97: // CueRefCluster
+		  readUInt(mf,(unsigned)len);
+		  break;
+		case 0x535f: // CueRefNumber
+		  readUInt(mf,(unsigned)len);
+		  break;
+		case 0xeb: // CueRefCodecState
+		  readUInt(mf,(unsigned)len);
+		  break;
+	      ENDFOR(mf);
+	      break;
+	  ENDFOR(mf);
+	  break;
+      ENDFOR(mf);
+
+      if (mf->nCues == 0 && mf->pCluster - mf->pSegment != cc.Position)
+	addCue(mf,mf->pCluster - mf->pSegment,mf->firstTimecode);
+
+      memcpy(AGET(mf,Cues),&cc,sizeof(cc));
+      break;
+  ENDFOR(mf);
+
+  memcpy(&mf->jb,&jb,sizeof(jb));
+
+  ARELEASE(mf,mf,Cues);
+
+  // bubble sort the cues and fuck the losers that write unordered cues
+  if (mf->nCues > 0)
+    for (i = mf->nCues - 1, k = 1; i > 0 && k > 0; --i)
+      for (j = k = 0; j < i; ++j)
+	if (mf->Cues[j].Time > mf->Cues[j+1].Time) {
+	  struct Cue tmp = mf->Cues[j+1];
+	  mf->Cues[j+1] = mf->Cues[j];
+	  mf->Cues[j] = tmp;
+	  ++k;
+	}
+
+  fixupCues(mf);
+}
+
+static void parseAttachment(MatroskaFile *mf,ulonglong toplen) {
+  struct Attachment a,*pa;
+
+  memset(&a,0,sizeof(a));
+  FOREACH(mf,toplen)
+    case 0x467e: // Description
+      STRGETA(mf,a.Description,len);
+      break;
+    case 0x466e: // Name
+      STRGETA(mf,a.Name,len);
+      break;
+    case 0x4660: // MimeType
+      STRGETA(mf,a.MimeType,len);
+      break;
+    case 0x46ae: // UID
+      a.UID = readUInt(mf,(unsigned)len);
+      break;
+    case 0x465c: // Data
+      a.Position = filepos(mf);
+      a.Length = len;
+      skipbytes(mf,len);
+      break;
+  ENDFOR(mf);
+
+  if (!a.Position)
+    return;
+
+  pa = AGET(mf,Attachments);
+  memcpy(pa,&a,sizeof(a));
+
+  if (a.Description)
+    pa->Description = mystrdup(mf->cache,a.Description);
+  if (a.Name)
+    pa->Name = mystrdup(mf->cache,a.Name);
+  if (a.MimeType)
+    pa->MimeType = mystrdup(mf->cache,a.MimeType);
+}
+
+static void parseAttachments(MatroskaFile *mf,ulonglong toplen) {
+  mf->seen.Attachments = 1;
+
+  FOREACH(mf,toplen)
+    case 0x61a7: // AttachedFile
+      parseAttachment(mf,len);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *parent) {
+  struct ChapterDisplay	*disp;
+  struct ChapterProcess	*proc;
+  struct ChapterCommand	*cmd;
+  struct Chapter	*ch = ASGET(mf,parent,Children);
+
+  memset(ch,0,sizeof(*ch));
+
+  ch->Enabled = 1;
+
+  FOREACH(mf,toplen)
+    case 0x73c4: // ChapterUID
+      ch->UID = readUInt(mf,(unsigned)len);
+      break;
+    case 0x91: // ChapterTimeStart
+      ch->Start = readUInt(mf,(unsigned)len);
+      break;
+    case 0x92: // ChapterTimeEnd
+      ch->End = readUInt(mf,(unsigned)len);
+      break;
+    case 0x98: // ChapterFlagHidden
+      ch->Hidden = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x4598: // ChapterFlagEnabled
+      ch->Enabled = readUInt(mf,(unsigned)len)!=0;
+      break;
+    case 0x8f: // ChapterTrack
+      FOREACH(mf,len)
+	case 0x89: // ChapterTrackNumber
+	  *(ulonglong*)(ASGET(mf,ch,Tracks)) = readUInt(mf,(unsigned)len);
+	  break;
+      ENDFOR(mf);
+      break;
+    case 0x80: // ChapterDisplay
+      disp = NULL;
+
+      FOREACH(mf,len)
+	case 0x85: // ChapterString
+	  if (disp==NULL) {
+	    disp = ASGET(mf,ch,Display);
+	    memset(disp, 0, sizeof(*disp));
+	  }
+	  if (disp->String)
+	    skipbytes(mf,len); // Ignore duplicate string
+	  else
+	    STRGETM(mf,disp->String,len);
+	  break;
+	case 0x437c: // ChapterLanguage
+	  if (disp==NULL) {
+	    disp = ASGET(mf,ch,Display);
+	    memset(disp, 0, sizeof(*disp));
+	  }
+	  if (disp->Language)
+	    skipbytes(mf,len);
+	  else
+	    STRGETM(mf,disp->Language,len);
+	  break;
+	case 0x437e: // ChapterCountry
+	  if (disp==NULL) {
+	    disp = ASGET(mf,ch,Display);
+	    memset(disp, 0, sizeof(*disp));
+	  }
+	  if (disp->Country)
+	    skipbytes(mf,len);
+	  else
+	    STRGETM(mf,disp->Country,len);
+	  break;
+      ENDFOR(mf);
+
+      if (disp && !disp->String) {
+	mf->cache->memfree(mf->cache,disp->Language);
+	mf->cache->memfree(mf->cache,disp->Country);
+	--ch->nDisplay;
+      }
+      break;
+    case 0x6944: // ChapProcess
+      proc = NULL;
+
+      FOREACH(mf,len)
+	case 0x6955: // ChapProcessCodecID
+	  if (proc == NULL) {
+	    proc = ASGET(mf, ch, Process);
+	    memset(proc, 0, sizeof(*proc));
+	  }
+	  proc->CodecID = (unsigned)readUInt(mf,(unsigned)len);
+	  break;
+	case 0x450d: // ChapProcessPrivate
+	  if (proc == NULL) {
+	    proc = ASGET(mf, ch, Process);
+	    memset(proc, 0, sizeof(*proc));
+	  }
+	  if (proc->CodecPrivate)
+	    skipbytes(mf, len);
+	  else {
+	    proc->CodecPrivateLength = (unsigned)len;
+	    STRGETM(mf,proc->CodecPrivate,len);
+	  }
+	  break;
+	case 0x6911: // ChapProcessCommand
+	  if (proc == NULL) {
+	    proc = ASGET(mf, ch, Process);
+	    memset(proc, 0, sizeof(*proc));
+	  }
+
+	  cmd = NULL;
+
+	  FOREACH(mf,len)
+	    case 0x6922: // ChapterCommandTime
+	      if (cmd == NULL) {
+		cmd = ASGET(mf,proc,Commands);
+		memset(cmd, 0, sizeof(*cmd));
+	      }
+	      cmd->Time = (unsigned)readUInt(mf,(unsigned)len);
+	      break;
+	    case 0x6933: // ChapterCommandString
+	      if (cmd == NULL) {
+		cmd = ASGET(mf,proc,Commands);
+		memset(cmd, 0, sizeof(*cmd));
+	      }
+	      if (cmd->Command)
+		skipbytes(mf,len);
+	      else {
+		cmd->CommandLength = (unsigned)len;
+		STRGETM(mf,cmd->Command,len);
+	      }
+	      break;
+	  ENDFOR(mf);
+
+	  if (cmd && !cmd->Command)
+	    --proc->nCommands;
+	  break;
+      ENDFOR(mf);
+
+      if (proc && !proc->nCommands)
+	--ch->nProcess;
+      break;
+    case 0xb6: // Nested ChapterAtom
+      parseChapter(mf,len,ch);
+      break;
+  ENDFOR(mf);
+
+  ARELEASE(mf,ch,Tracks);
+  ARELEASE(mf,ch,Display);
+  ARELEASE(mf,ch,Children);
+}
+
+static void parseChapters(MatroskaFile *mf,ulonglong toplen) {
+  struct Chapter  *ch;
+
+  mf->seen.Chapters = 1;
+
+  FOREACH(mf,toplen)
+    case 0x45b9: // EditionEntry
+	ch = AGET(mf,Chapters);
+	memset(ch, 0, sizeof(*ch));
+ 	FOREACH(mf,len)
+	  case 0x45bc: // EditionUID
+	    ch->UID = readUInt(mf,(unsigned)len);
+	    break;
+	  case 0x45bd: // EditionFlagHidden
+	    ch->Hidden = readUInt(mf,(unsigned)len)!=0;
+	    break;
+	  case 0x45db: // EditionFlagDefault
+	    ch->Default = readUInt(mf,(unsigned)len)!=0;
+	    break;
+	  case 0x45dd: // EditionFlagOrdered
+	    ch->Ordered = readUInt(mf,(unsigned)len)!=0;
+	    break;
+	  case 0xb6: // ChapterAtom
+	    parseChapter(mf,len,ch);
+	    break;
+	ENDFOR(mf);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseTags(MatroskaFile *mf,ulonglong toplen) {
+  struct Tag  *tag;
+  struct Target *target;
+  struct SimpleTag *st;
+
+  mf->seen.Tags = 1;
+
+  FOREACH(mf,toplen)
+    case 0x7373: // Tag
+      tag = AGET(mf,Tags);
+      memset(tag,0,sizeof(*tag));
+
+      FOREACH(mf,len)
+	case 0x63c0: // Targets
+	  FOREACH(mf,len)
+	    case 0x63c5: // TrackUID
+	      target = ASGET(mf,tag,Targets);
+	      target->UID = readUInt(mf,(unsigned)len);
+	      target->Type = TARGET_TRACK;
+	      break;
+	    case 0x63c4: // ChapterUID
+	      target = ASGET(mf,tag,Targets);
+	      target->UID = readUInt(mf,(unsigned)len);
+	      target->Type = TARGET_CHAPTER;
+	      break;
+	    case 0x63c6: // AttachmentUID
+	      target = ASGET(mf,tag,Targets);
+	      target->UID = readUInt(mf,(unsigned)len);
+	      target->Type = TARGET_ATTACHMENT;
+	      break;
+	    case 0x63c9: // EditionUID
+	      target = ASGET(mf,tag,Targets);
+	      target->UID = readUInt(mf,(unsigned)len);
+	      target->Type = TARGET_EDITION;
+	      break;
+	  ENDFOR(mf);
+	  break;
+	case 0x67c8: // SimpleTag
+	  st = ASGET(mf,tag,SimpleTags);
+	  memset(st,0,sizeof(*st));
+
+	  FOREACH(mf,len)
+	    case 0x45a3: // TagName
+	      if (st->Name)
+		skipbytes(mf,len);
+	      else
+		STRGETM(mf,st->Name,len);
+	      break;
+	    case 0x4487: // TagString
+	      if (st->Value)
+		skipbytes(mf,len);
+	      else
+		STRGETM(mf,st->Value,len);
+	      break;
+	    case 0x447a: // TagLanguage
+	      if (st->Language)
+		skipbytes(mf,len);
+	      else
+		STRGETM(mf,st->Language,len);
+	      break;
+	    case 0x4484: // TagDefault
+	      st->Default = readUInt(mf,(unsigned)len)!=0;
+	      break;
+	  ENDFOR(mf);
+
+	  if (!st->Name || !st->Value) {
+	    mf->cache->memfree(mf->cache,st->Name);
+	    mf->cache->memfree(mf->cache,st->Value);
+	    --tag->nSimpleTags;
+	  }
+	  break;
+      ENDFOR(mf);
+      break;
+  ENDFOR(mf);
+}
+
+static void parseContainer(MatroskaFile *mf) {
+  ulonglong len;
+  int	    id = readID(mf);
+  if (id==EOF)
+    errorjmp(mf,"Unexpected EOF in parseContainer");
+
+  len = readSize(mf);
+
+  switch (id) {
+    case 0x1549a966: // SegmentInfo
+      parseSegmentInfo(mf,len);
+      break;
+    case 0x1f43b675: // Cluster
+      parseFirstCluster(mf,len);
+      break;
+    case 0x1654ae6b: // Tracks
+      parseTracks(mf,len);
+      break;
+    case 0x1c53bb6b: // Cues
+      parseCues(mf,len);
+      break;
+    case 0x1941a469: // Attachments
+      parseAttachments(mf,len);
+      break;
+    case 0x1043a770: // Chapters
+      parseChapters(mf,len);
+      break;
+    case 0x1254c367: // Tags
+      parseTags(mf,len);
+      break;
+  }
+}
+
+static void parseContainerPos(MatroskaFile *mf,ulonglong pos) {
+  seek(mf,pos);
+  parseContainer(mf);
+}
+
+static void parsePointers(MatroskaFile *mf) {
+  if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
+    parseContainerPos(mf,mf->pSegmentInfo);
+  if (mf->pCluster && !mf->seen.Cluster)
+    parseContainerPos(mf,mf->pCluster);
+  if (mf->pTracks && !mf->seen.Tracks)
+    parseContainerPos(mf,mf->pTracks);
+  if (mf->pCues && !mf->seen.Cues) {
+    parseContainerPos(mf,mf->pCues);
+
+    // ignore errors
+    mf->flags &= ~MPF_ERROR;
+  }
+  if (mf->pAttachments && !mf->seen.Attachments)
+    parseContainerPos(mf,mf->pAttachments);
+  if (mf->pChapters && !mf->seen.Chapters)
+    parseContainerPos(mf,mf->pChapters);
+  if (mf->pTags && !mf->seen.Tags)
+    parseContainerPos(mf,mf->pTags);
+}
+
+static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
+  ulonglong   nextpos;
+  unsigned    nSeekHeads = 0, dontstop = 0;
+
+  // we want to read data until we find a seekhead or a trackinfo
+  FOREACH(mf,toplen)
+    case 0x114d9b74: // SeekHead
+      if (mf->flags & MKVF_AVOID_SEEKS) {
+	skipbytes(mf,len);
+	break;
+      }
+
+      nextpos = filepos(mf) + len;
+      do {
+	mf->pSeekHead = 0;
+	parseSeekHead(mf,len);
+	++nSeekHeads;
+	if (mf->pSeekHead) { // this is possibly a chained SeekHead
+	  seek(mf,mf->pSeekHead);
+	  id = readID(mf);
+	  if (id==EOF) // chained SeekHead points to EOF?
+	    goto resume;
+	  if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
+	    goto resume;
+	  len = readSize(mf);
+	} else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements
+	  // XXX EVIL HACK
+	  // Some software doesnt index tags via SeekHead, so we continue
+	  // reading the segment after the second SeekHead
+	  if (mf->pTags || nSeekHeads<2 || filepos(mf)>=start+toplen) {
+	    parsePointers(mf);
+	    return;
+	  }
+	  // reset nextpos pointer to current position
+	  nextpos = filepos(mf);
+	  dontstop = 1;
+	}
+      } while (mf->pSeekHead);
+resume:
+      // XXX workaround for AVI-Mux GUI
+      if (mf->pSegmentInfo && !mf->seen.SegmentInfo)
+	parseContainerPos(mf,mf->pSegmentInfo);
+      seek(mf,nextpos); // resume reading segment
+      break;
+    case 0x1549a966: // SegmentInfo
+      mf->pSegmentInfo = cur;
+      parseSegmentInfo(mf,len);
+      break;
+    case 0x1f43b675: // Cluster
+      if (!mf->pCluster)
+	mf->pCluster = cur;
+      if (mf->seen.Cluster)
+	skipbytes(mf,len);
+      else
+	parseFirstCluster(mf,len);
+      break;
+    case 0x1654ae6b: // Tracks
+      mf->pTracks = cur;
+      parseTracks(mf,len);
+      break;
+    case 0x1c53bb6b: // Cues
+      mf->pCues = cur;
+      parseCues(mf,len);
+      break;
+    case 0x1941a469: // Attachments
+      mf->pAttachments = cur;
+      parseAttachments(mf,len);
+      break;
+    case 0x1043a770: // Chapters
+      mf->pChapters = cur;
+      parseChapters(mf,len);
+      break;
+    case 0x1254c367: // Tags
+      mf->pTags = cur;
+      parseTags(mf,len);
+      break;
+  ENDFOR1(mf);
+    // if we have pointers to all key elements
+    if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster)
+      break;
+  ENDFOR2();
+  parsePointers(mf);
+}
+
+static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode) {
+  ulonglong	v;
+  ulonglong	duration = 0;
+  ulonglong	dpos;
+  struct QueueEntry *qe,*qf = NULL;
+  unsigned char	have_duration = 0, have_block = 0;
+  unsigned char	gap = 0;
+  unsigned char	lacing = 0;
+  unsigned char	ref = 0;
+  unsigned char	trackid;
+  unsigned	tracknum = 0;
+  int		c;
+  unsigned	nframes = 0,i;
+  unsigned	*sizes;
+  signed short	block_timecode;
+
+  FOREACH(mf,toplen)
+    case 0xfb: // ReferenceBlock
+      readSInt(mf,(unsigned)len);
+      ref = 1;
+      break;
+    case 0xa1: // Block
+      have_block = 1;
+
+      dpos = filepos(mf);
+
+      v = readVLUInt(mf);
+      if (v>255)
+	errorjmp(mf,"Invalid track number in Block: %d",(int)v);
+      trackid = (unsigned char)v;
+
+      for (tracknum=0;tracknum<mf->nTracks;++tracknum)
+	if (mf->Tracks[tracknum]->Number == trackid)
+	  goto found;
+      errorjmp(mf,"Invalid track number in Block: %u",trackid);
+found:
+
+      if (mf->trackMask & (1<<tracknum)) { // ignore this block
+	skipbytes(mf,start + tmplen - filepos(mf)); // shortcut
+	return;
+      }
+
+      block_timecode = (signed short)readSInt(mf,2);
+
+      // recalculate this block's timecode to final timecode in ns
+      timecode = mul3(mf->Tracks[tracknum]->TimecodeScale,
+	(timecode - mf->firstTimecode + block_timecode) * mf->Seg.TimecodeScale);
+
+      c = readch(mf);
+      if (c==EOF)
+	errorjmp(mf,"Unexpected EOF while reading Block flags");
+
+      gap = c & 0x1;
+      lacing = (c >> 1) & 3;
+
+      if (lacing) {
+	c = readch(mf);
+	if (c == EOF)
+	  errorjmp(mf,"Unexpected EOF while reading lacing data");
+	nframes = c+1;
+      } else
+	nframes = 1;
+      sizes = alloca(nframes*sizeof(*sizes));
+ 
+      switch (lacing) {
+	case 0: // No lacing
+	  sizes[0] = (unsigned)(len - filepos(mf) + dpos);
+	  break;
+	case 1: // Xiph lacing
+	  sizes[nframes-1] = 0;
+	  for (i=0;i<nframes-1;++i) {
+	    sizes[i] = 0;
+	    do {
+	      c = readch(mf);
+	      if (c==EOF)
+		errorjmp(mf,"Unexpected EOF while reading lacing data");
+	      sizes[i] += c;
+	    } while (c==255);
+	    sizes[nframes-1] += sizes[i];
+	  }
+	  sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[nframes-1];
+	  break;
+	case 3: // EBML lacing
+	  sizes[nframes-1] = 0;
+	  sizes[0] = (unsigned)readVLUInt(mf);
+	  for (i=1;i<nframes-1;++i) {
+	    sizes[i] = sizes[i-1] + (int)readVLSInt(mf);
+	    sizes[nframes-1] += sizes[i];
+	  }
+	  if (nframes>1)
+	    sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[0] - sizes[nframes-1];
+	  break;
+	case 2: // Fixed lacing
+	  sizes[0] = (unsigned)(len - filepos(mf) + dpos)/nframes;
+	  for (i=1;i<nframes;++i)
+	    sizes[i] = sizes[0];
+	  break;
+      }
+
+      v = filepos(mf);
+      qf = NULL;
+      for (i=0;i<nframes;++i) {
+	qe = QAlloc(mf);
+	if (!qf)
+	  qf = qe;
+
+	qe->Start = timecode;
+	qe->End = timecode;
+	qe->Position = v;
+	qe->Length = sizes[i];
+	qe->flags = FRAME_UNKNOWN_END | FRAME_KF;
+	if (i == nframes-1 && gap)
+	  qe->flags |= FRAME_GAP;
+	if (i > 0)
+	  qe->flags |= FRAME_UNKNOWN_START;
+
+	QPut(&mf->Queues[tracknum],qe);
+
+	v += sizes[i];
+      }
+
+      // we want to still load these bytes into cache
+      for (v = filepos(mf) & ~0x3fff; v < len + dpos; v += 0x4000)
+	mf->cache->read(mf->cache,v,NULL,0); // touch page
+
+      skipbytes(mf,len - filepos(mf) + dpos);
+      break;
+    case 0x9b: // BlockDuration
+      duration = readUInt(mf,(unsigned)len);
+      have_duration = 1;
+      break;
+  ENDFOR(mf);
+
+  if (!have_block)
+    errorjmp(mf,"Found a BlockGroup without Block");
+
+  if (nframes > 1) {
+    if (have_duration) {
+      duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
+	duration * mf->Seg.TimecodeScale);
+      dpos = duration / nframes;
+
+      v = qf->Start;
+      for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
+	qe->Start = v;
+	v += dpos;
+	duration -= dpos;
+	qe->End = v;
+	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
+      }
+      qe->Start = v;
+      qe->End = v + duration;
+      qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
+    } else if (mf->Tracks[tracknum]->DefaultDuration) {
+      dpos = mf->Tracks[tracknum]->DefaultDuration;
+      v = qf->Start;
+      for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
+	qe->Start = v;
+	v += dpos;
+	qe->End = v;
+	qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
+      }
+    }
+  } else if (nframes == 1) {
+    if (have_duration) {
+      qf->End = qf->Start + mul3(mf->Tracks[tracknum]->TimecodeScale,
+	duration * mf->Seg.TimecodeScale);
+      qf->flags &= ~FRAME_UNKNOWN_END;
+    } else if (mf->Tracks[tracknum]->DefaultDuration) {
+      qf->End = qf->Start + mf->Tracks[tracknum]->DefaultDuration;
+      qf->flags &= ~FRAME_UNKNOWN_END;
+    }
+  }
+
+  if (ref)
+    while (qf) {
+      qf->flags &= ~FRAME_KF;
+      qf = qf->next;
+    }
+}
+
+static void ClearQueue(MatroskaFile *mf,struct Queue *q) {
+  struct QueueEntry *qe,*qn;
+
+  for (qe=q->head;qe;qe=qn) {
+    qn = qe->next;
+    qe->next = mf->QFreeList;
+    mf->QFreeList = qe;
+  }
+
+  q->head = NULL;
+  q->tail = NULL;
+}
+
+static void EmptyQueues(MatroskaFile *mf) {
+  unsigned	    i;
+
+  for (i=0;i<mf->nTracks;++i)
+    ClearQueue(mf,&mf->Queues[i]);
+}
+
+static int  readMoreBlocks(MatroskaFile *mf) {
+  ulonglong		toplen, cstop;
+  longlong		cp;
+  int			cid, ret = 0;
+  jmp_buf		jb;
+  volatile unsigned	retries = 0;
+
+  if (mf->readPosition >= mf->pSegmentTop)
+    return EOF;
+
+  memcpy(&jb,&mf->jb,sizeof(jb));
+
+  if (setjmp(mf->jb)) { // something evil happened here, try to resync
+    ret = EOF;
+
+    if (++retries > 3) // don't try too hard
+      goto ex;
+
+    for (;;) {
+      if (filepos(mf) >= mf->pSegmentTop) {
+	mf->readPosition = filepos(mf);
+	goto ex;
+      }
+
+      cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster
+
+      if (cp < 0 || (ulonglong)cp >= mf->pSegmentTop)
+	goto ex;
+
+      seek(mf,cp);
+
+      cid = readID(mf);
+      if (cid == EOF)
+	goto ex;
+      if (cid == 0x1f43b675) {
+	toplen = readSize(mf);
+	if (toplen < MAXCLUSTER) {
+	  // reset error flags
+	  mf->flags &= ~MPF_ERROR;
+	  ret = RBRESYNC;
+	  break;
+	}
+      }
+    }
+
+    mf->readPosition = cp;
+  }
+
+  cstop = mf->cache->getsize(mf->cache)>>1;
+  if (cstop > MAX_READAHEAD)
+    cstop = MAX_READAHEAD;
+  cstop += mf->readPosition;
+
+  seek(mf,mf->readPosition);
+
+  while (filepos(mf) < mf->pSegmentTop) {
+    cid = readID(mf);
+    if (cid == EOF) {
+      ret = EOF;
+      break;
+    }
+    toplen = readSize(mf);
+
+    if (cid == 0x1f43b675) { // Cluster
+      unsigned char	have_timecode = 0;
+
+      FOREACH(mf,toplen)
+	case 0xe7: // Timecode
+	  mf->tcCluster = readUInt(mf,(unsigned)len);
+	  have_timecode = 1;
+	  break;
+	case 0xa7: // Position
+	  readUInt(mf,(unsigned)len);
+	  break;
+	case 0xab: // PrevSize
+	  readUInt(mf,(unsigned)len);
+	  break;
+	case 0xa0: // BlockGroup
+	  if (!have_timecode)
+	    errorjmp(mf,"Found BlockGroup before cluster TimeCode");
+	  parseBlockGroup(mf,len,mf->tcCluster);
+	  goto out;
+      ENDFOR(mf);
+out:;
+    } else {
+      if (toplen > MAXFRAME)
+	errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen);
+      if (cid == 0xa0) // BlockGroup
+	parseBlockGroup(mf,toplen,mf->tcCluster);
+      else
+	skipbytes(mf,toplen);
+    }
+
+    if ((mf->readPosition = filepos(mf)) > cstop)
+      break;
+  }
+
+  mf->readPosition = filepos(mf);
+
+ex:
+  memcpy(&mf->jb,&jb,sizeof(jb));
+
+  return ret;
+}
+
+// this is almost the same as readMoreBlocks, except it ensures
+// there are no partial frames queued, however empty queues are ok
+static int  fillQueues(MatroskaFile *mf,unsigned int mask) {
+  unsigned    i,j;
+  int	      ret = 0;
+
+  for (;;) {
+    j = 0;
+
+    for (i=0;i<mf->nTracks;++i)
+      if (mf->Queues[i].head && !(mask & (1<<i)))
+	++j;
+
+    if (j>0) // have at least some frames
+      return ret;
+
+    if ((ret = readMoreBlocks(mf)) < 0) {
+      j = 0;
+      for (i=0;i<mf->nTracks;++i)
+	if (mf->Queues[i].head && !(mask & (1<<i)))
+	  ++j;
+      if (j) // we adjusted some blocks
+	return 0;
+      return EOF;
+    }
+  }
+}
+
+static void reindex(MatroskaFile *mf) {
+  jmp_buf     jb;
+  ulonglong   pos = mf->pCluster;
+  ulonglong   step = 10*1024*1024;
+  ulonglong   size, tc, isize;
+  longlong    next_cluster;
+  int	      id, have_tc, bad;
+  struct Cue  *cue;
+
+  if (pos >= mf->pSegmentTop)
+    return;
+
+  if (pos + step * 10 > mf->pSegmentTop)
+    step = (mf->pSegmentTop - pos) / 10;
+  if (step == 0)
+    step = 1;
+
+  memcpy(&jb,&mf->jb,sizeof(jb));
+
+  // remove all cues
+  mf->nCues = 0;
+
+  bad = 0;
+
+  while (pos < mf->pSegmentTop) {
+    if (!mf->cache->progress(mf->cache,pos,mf->pSegmentTop))
+      break;
+
+    if (++bad > 50) {
+      pos += step;
+      bad = 0;
+      continue;
+    }
+
+    // find next cluster header
+    next_cluster = mf->cache->scan(mf->cache,pos,0x1f43b675); // cluster
+    if (next_cluster < 0 || (ulonglong)next_cluster >= mf->pSegmentTop)
+      break;
+
+    pos = next_cluster + 4; // prevent endless loops
+
+    if (setjmp(mf->jb)) // something evil happened while reindexing
+      continue;
+
+    seek(mf,next_cluster);
+
+    id = readID(mf);
+    if (id == EOF)
+      break;
+    if (id != 0x1f43b675) // shouldn't happen
+      continue;
+
+    size = readVLUInt(mf);
+    if (size >= MAXCLUSTER || size < 1024)
+      continue;
+
+    have_tc = 0;
+    size += filepos(mf);
+
+    while (filepos(mf) < (ulonglong)next_cluster + 1024) {
+      id = readID(mf);
+      if (id == EOF)
+	break;
+
+      isize = readVLUInt(mf);
+
+      if (id == 0xe7) { // cluster timecode
+	tc = readUInt(mf,(unsigned)isize);
+	have_tc = 1;
+	break;
+      }
+
+      skipbytes(mf,isize);
+    }
+
+    if (!have_tc)
+      continue;
+
+    seek(mf,size);
+    id = readID(mf);
+
+    if (id == EOF)
+      break;
+
+    if (id != 0x1f43b675) // cluster
+      continue;
+
+    // good cluster, remember it
+    cue = AGET(mf,Cues);
+    cue->Time = tc;
+    cue->Position = next_cluster - mf->pSegment;
+    cue->Block = 0;
+    cue->Track = 0;
+
+    // advance to the next point
+    pos = next_cluster + step;
+    if (pos < size)
+      pos = size;
+
+    bad = 0;
+  }
+
+  fixupCues(mf);
+
+  if (mf->nCues == 0) {
+    cue = AGET(mf,Cues);
+    cue->Time = mf->firstTimecode;
+    cue->Position = mf->pCluster - mf->pSegment;
+    cue->Block = 0;
+    cue->Track = 0;
+  }
+
+  mf->cache->progress(mf->cache,0,0);
+
+  memcpy(&mf->jb,&jb,sizeof(jb));
+}
+
+static void fixupChapter(ulonglong adj, struct Chapter *ch) {
+  unsigned i;
+
+  if (ch->Start != 0)
+    ch->Start -= adj;
+  if (ch->End != 0)
+    ch->End -= adj;
+
+  for (i=0;i<ch->nChildren;++i)
+    fixupChapter(adj,&ch->Children[i]);
+}
+
+static longlong	findLastTimecode(MatroskaFile *mf) {
+  ulonglong   nd = 0;
+  unsigned    n,vtrack;
+
+  if (mf->nCues == 0 || mf->nTracks == 0)
+    return -1;
+
+  for (n=vtrack=0;n<mf->nTracks;++n)
+    if (mf->Tracks[n]->Type == TT_VIDEO) {
+      vtrack = n;
+      goto ok;
+    }
+
+  return -1;
+ok:
+
+  mf->trackMask = ~(1 << vtrack);
+  mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegment;
+  mf->tcCluster = mf->Cues[mf->nCues - 1].Time / mf->Seg.TimecodeScale;
+
+  do
+    while (mf->Queues[vtrack].head)
+    {
+      ulonglong   tc = mf->Queues[vtrack].head->flags & FRAME_UNKNOWN_END ?
+			  mf->Queues[vtrack].head->Start : mf->Queues[vtrack].head->End;
+      if (nd < tc)
+	nd = tc;
+      QFree(mf,QGet(&mf->Queues[vtrack]));
+    }
+  while (readMoreBlocks(mf) != EOF);
+
+  mf->trackMask = 0;
+
+  return nd;
+}
+
+static void parseFile(MatroskaFile *mf) {
+  ulonglong len = filepos(mf), adjust;
+  unsigned  i;
+  int	    id = readID(mf);
+  int	    m;
+
+  if (id==EOF)
+    errorjmp(mf,"Unexpected EOF at start of file");
+
+  // files with multiple concatenated segments can have only
+  // one EBML prolog
+  if (len > 0 && id == 0x18538067)
+    goto segment;
+
+  if (id!=0x1a45dfa3)
+    errorjmp(mf,"First element in file is not EBML");
+
+  parseEBML(mf,readSize(mf));
+
+  // next we need to find the first segment
+  for (;;) {
+    id = readID(mf);
+    if (id==EOF)
+      errorjmp(mf,"No segments found in the file");
+segment:
+    len = readVLUIntImp(mf,&m);
+    // see if it's unspecified
+    if (len == (MAXU64 >> (57-m*7)))
+      len = MAXU64;
+    if (id == 0x18538067) // Segment
+      break;
+    skipbytes(mf,len);
+  }
+
+  // found it
+  mf->pSegment = filepos(mf);
+  mf->pSegmentTop = len == MAXU64 ? MAXU64 : mf->pSegment + len;
+  parseSegment(mf,len);
+
+  // check if we got all data
+  if (!mf->seen.SegmentInfo)
+    errorjmp(mf,"Couldn't find SegmentInfo");
+  if (!mf->seen.Tracks)
+    errorjmp(mf,"Couldn't find Tracks");
+  if (!mf->seen.Cluster)
+    errorjmp(mf,"Couldn't find any Clusters");
+
+  adjust = mf->firstTimecode * mf->Seg.TimecodeScale;
+
+  for (i=0;i<mf->nChapters;++i)
+    fixupChapter(adjust, &mf->Chapters[i]);
+
+  // release extra memory
+  ARELEASE(mf,mf,Tracks);
+
+  // initialize reader
+  mf->Queues = mf->cache->memalloc(mf->cache,mf->nTracks * sizeof(*mf->Queues));
+  if (mf->Queues == NULL)
+    errorjmp(mf, "Ouf of memory");
+  memset(mf->Queues, 0, mf->nTracks * sizeof(*mf->Queues));
+
+  // try to detect real duration
+  if (!(mf->flags & MKVF_AVOID_SEEKS)) {
+    longlong nd = findLastTimecode(mf);
+    if (nd > 0)
+      mf->Seg.Duration = nd;
+  }
+
+  // move to first frame
+  mf->readPosition = mf->pCluster;
+  mf->tcCluster = mf->firstTimecode;
+}
+
+static void DeleteChapter(MatroskaFile *mf,struct Chapter *ch) {
+  unsigned i,j;
+
+  for (i=0;i<ch->nDisplay;++i) {
+    mf->cache->memfree(mf->cache,ch->Display[i].String);
+    mf->cache->memfree(mf->cache,ch->Display[i].Language);
+    mf->cache->memfree(mf->cache,ch->Display[i].Country);
+  }
+  mf->cache->memfree(mf->cache,ch->Display);
+  mf->cache->memfree(mf->cache,ch->Tracks);
+
+  for (i=0;i<ch->nProcess;++i) {
+    for (j=0;j<ch->Process[i].nCommands;++j)
+      mf->cache->memfree(mf->cache,ch->Process[i].Commands[j].Command);
+    mf->cache->memfree(mf->cache,ch->Process[i].Commands);
+    mf->cache->memfree(mf->cache,ch->Process[i].CodecPrivate);
+  }
+  mf->cache->memfree(mf->cache,ch->Process);
+
+  for (i=0;i<ch->nChildren;++i)
+    DeleteChapter(mf,&ch->Children[i]);
+  mf->cache->memfree(mf->cache,ch->Children);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// public interface
+MatroskaFile  *mkv_OpenEx(InputStream *io,
+			  ulonglong base,
+			  unsigned flags,
+			  char *err_msg,unsigned msgsize)
+{
+  MatroskaFile	*mf = io->memalloc(io,sizeof(*mf));
+  if (mf == NULL) {
+    strlcpy(err_msg,"Out of memory",msgsize);
+    return NULL;
+  }
+
+  memset(mf,0,sizeof(*mf));
+
+  mf->cache = io;
+  mf->flags = flags;
+  io->progress(io,0,0);
+
+  if (setjmp(mf->jb)==0) {
+    seek(mf,base);
+    parseFile(mf);
+  } else { // parser error
+    strlcpy(err_msg,mf->errmsg,msgsize);
+    mkv_Close(mf);
+    return NULL;
+  }
+
+  return mf;
+}
+
+MatroskaFile  *mkv_Open(InputStream *io,
+			char *err_msg,unsigned msgsize)
+{
+  return mkv_OpenEx(io,0,0,err_msg,msgsize);
+}
+
+void	      mkv_Close(MatroskaFile *mf) {
+  unsigned  i,j;
+
+  if (mf==NULL)
+    return;
+
+  for (i=0;i<mf->nTracks;++i)
+    mf->cache->memfree(mf->cache,mf->Tracks[i]);
+  mf->cache->memfree(mf->cache,mf->Tracks);
+
+  for (i=0;i<mf->nQBlocks;++i)
+    mf->cache->memfree(mf->cache,mf->QBlocks[i]);
+  mf->cache->memfree(mf->cache,mf->QBlocks);
+
+  mf->cache->memfree(mf->cache,mf->Queues);
+
+  mf->cache->memfree(mf->cache,mf->Seg.Title);
+  mf->cache->memfree(mf->cache,mf->Seg.MuxingApp);
+  mf->cache->memfree(mf->cache,mf->Seg.WritingApp);
+  mf->cache->memfree(mf->cache,mf->Seg.Filename);
+  mf->cache->memfree(mf->cache,mf->Seg.NextFilename);
+  mf->cache->memfree(mf->cache,mf->Seg.PrevFilename);
+
+  mf->cache->memfree(mf->cache,mf->Cues);
+
+  for (i=0;i<mf->nAttachments;++i) {
+    mf->cache->memfree(mf->cache,mf->Attachments[i].Description);
+    mf->cache->memfree(mf->cache,mf->Attachments[i].Name);
+    mf->cache->memfree(mf->cache,mf->Attachments[i].MimeType);
+  }
+  mf->cache->memfree(mf->cache,mf->Attachments);
+
+  for (i=0;i<mf->nChapters;++i)
+    DeleteChapter(mf,&mf->Chapters[i]);
+  mf->cache->memfree(mf->cache,mf->Chapters);
+
+  for (i=0;i<mf->nTags;++i) {
+    for (j=0;j<mf->Tags[i].nSimpleTags;++j) {
+      mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Name);
+      mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Value);
+    }
+    mf->cache->memfree(mf->cache,mf->Tags[i].Targets);
+    mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags);
+  }
+  mf->cache->memfree(mf->cache,mf->Tags);
+
+  mf->cache->memfree(mf->cache,mf);
+}
+
+const char    *mkv_GetLastError(MatroskaFile *mf) {
+  return mf->errmsg[0] ? mf->errmsg : NULL;
+}
+
+SegmentInfo   *mkv_GetFileInfo(MatroskaFile *mf) {
+  return &mf->Seg;
+}
+
+unsigned int  mkv_GetNumTracks(MatroskaFile *mf) {
+  return mf->nTracks;
+}
+
+TrackInfo     *mkv_GetTrackInfo(MatroskaFile *mf,unsigned track) {
+  if (track>mf->nTracks)
+    return NULL;
+
+  return mf->Tracks[track];
+}
+
+void	      mkv_GetAttachments(MatroskaFile *mf,Attachment **at,unsigned *count) {
+  *at = mf->Attachments;
+  *count = mf->nAttachments;
+}
+
+void	      mkv_GetChapters(MatroskaFile *mf,Chapter **ch,unsigned *count) {
+  *ch = mf->Chapters;
+  *count = mf->nChapters;
+}
+
+void	      mkv_GetTags(MatroskaFile *mf,Tag **tag,unsigned *count) {
+  *tag = mf->Tags;
+  *count = mf->nTags;
+}
+
+ulonglong     mkv_GetSegmentTop(MatroskaFile *mf) {
+  return mf->pSegmentTop;
+}
+
+#define	IS_DELTA(f) (!((f)->flags & FRAME_KF) || ((f)->flags & FRAME_UNKNOWN_START))
+
+void  mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
+  int		i,j,m,ret;
+  unsigned	n,z,mask;
+  ulonglong	m_kftime[MAX_TRACKS];
+  unsigned char	m_seendf[MAX_TRACKS];
+
+  if (mf->flags & MKVF_AVOID_SEEKS)
+    return;
+
+  if (timecode == 0) {
+    EmptyQueues(mf);
+    mf->readPosition = mf->pCluster;
+    mf->tcCluster = mf->firstTimecode;
+    mf->flags &= ~MPF_ERROR;
+
+    return;
+  }
+
+  if (mf->nCues==0)
+    reindex(mf);
+
+  if (mf->nCues==0)
+    return;
+
+  mf->flags &= ~MPF_ERROR;
+
+  i = 0;
+  j = mf->nCues - 1;
+
+  for (;;) {
+    if (i>j) {
+      j = j>=0 ? j : 0;
+
+      if (setjmp(mf->jb)!=0)
+	return;
+
+      mkv_SetTrackMask(mf,mf->trackMask);
+
+      if (flags & MKVF_SEEK_TO_PREV_KEYFRAME) {
+	// we do this in two stages
+	// a. find the last keyframes before the require position
+	// b. seek to them
+
+	// pass 1
+	for (;;) {
+	  for (n=0;n<mf->nTracks;++n) {
+	    m_kftime[n] = MAXU64;
+	    m_seendf[n] = 0;
+	  }
+
+	  EmptyQueues(mf);
+
+	  mf->readPosition = mf->Cues[j].Position + mf->pSegment;
+	  mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale;
+
+	  for (;;) {
+	    if ((ret = fillQueues(mf,0)) < 0 || ret == RBRESYNC)
+	      return;
+
+	    // drain queues until we get to the required timecode
+	    for (n=0;n<mf->nTracks;++n) {
+	      if (mf->Queues[n].head && mf->Queues[n].head->Start<timecode) {
+		if (IS_DELTA(mf->Queues[n].head))
+		  m_seendf[n] = 1;
+		else
+		  m_kftime[n] = mf->Queues[n].head->Start;
+	      }
+
+	      while (mf->Queues[n].head && mf->Queues[n].head->Start<timecode)
+	      {
+		if (IS_DELTA(mf->Queues[n].head))
+		  m_seendf[n] = 1;
+		else
+		  m_kftime[n] = mf->Queues[n].head->Start;
+		QFree(mf,QGet(&mf->Queues[n]));
+	      }
+
+	      if (mf->Queues[n].head)
+		if (!IS_DELTA(mf->Queues[n].head))
+		  m_kftime[n] = mf->Queues[n].head->Start;
+	    }
+
+	    for (n=0;n<mf->nTracks;++n)
+	      if (mf->Queues[n].head && mf->Queues[n].head->Start>=timecode)
+		goto found;
+	  }
+found:
+  
+	  for (n=0;n<mf->nTracks;++n)
+	    if (!(mf->trackMask & (1<<n)) && m_kftime[n]==MAXU64 &&
+		m_seendf[n] && j>0)
+	    {
+	      // we need to restart the search from prev cue
+	      --j;
+	      goto again;
+	    }
+
+	  break;
+again:;
+	}
+      } else
+	for (n=0;n<mf->nTracks;++n)
+	  m_kftime[n] = timecode;
+
+      // now seek to this timecode
+      EmptyQueues(mf);
+
+      mf->readPosition = mf->Cues[j].Position + mf->pSegment;
+      mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale;
+
+      for (mask=0;;) {
+	if ((ret = fillQueues(mf,mask)) < 0 || ret == RBRESYNC)
+	  return;
+
+	// drain queues until we get to the required timecode
+	for (n=0;n<mf->nTracks;++n) {
+	  struct QueueEntry *qe;
+	  for (qe = mf->Queues[n].head;qe && qe->Start<m_kftime[n];qe = mf->Queues[n].head)
+	    QFree(mf,QGet(&mf->Queues[n]));
+	}
+
+	for (n=z=0;n<mf->nTracks;++n)
+	  if (m_kftime[n]==MAXU64 || (mf->Queues[n].head && mf->Queues[n].head->Start>=m_kftime[n])) {
+	    ++z;
+	    mask |= 1<<n;
+	  }
+
+	if (z==mf->nTracks)
+	  return;
+      }
+    }
+
+    m = (i+j)>>1;
+
+    if (timecode < mf->Cues[m].Time)
+      j = m-1;
+    else
+      i = m+1;
+  }
+}
+
+void  mkv_SkipToKeyframe(MatroskaFile *mf) {
+  unsigned  n,wait;
+  ulonglong ht;
+
+  if (setjmp(mf->jb)!=0)
+    return;
+
+  // remove delta frames from queues
+  do {
+    wait = 0;
+
+    if (fillQueues(mf,0)<0)
+      return;
+
+    for (n=0;n<mf->nTracks;++n)
+      if (mf->Queues[n].head && !(mf->Queues[n].head->flags & FRAME_KF)) {
+	++wait;
+	QFree(mf,QGet(&mf->Queues[n]));
+      }
+  } while (wait);
+
+  // find highest queued time
+  for (n=0,ht=0;n<mf->nTracks;++n)
+    if (mf->Queues[n].head && ht<mf->Queues[n].head->Start)
+      ht = mf->Queues[n].head->Start;
+
+  // ensure the time difference is less than 100ms
+  do {
+    wait = 0;
+
+    if (fillQueues(mf,0)<0)
+      return;
+
+    for (n=0;n<mf->nTracks;++n)
+      while (mf->Queues[n].head && mf->Queues[n].head->next &&
+	  (mf->Queues[n].head->next->flags & FRAME_KF) &&
+	  ht - mf->Queues[n].head->Start > 100000000)
+      {
+	++wait;
+	QFree(mf,QGet(&mf->Queues[n]));
+      }
+
+  } while (wait);
+}
+
+ulonglong mkv_GetLowestQTimecode(MatroskaFile *mf) {
+  unsigned  n,seen;
+  ulonglong t;
+
+  // find the lowest queued timecode
+  for (n=seen=0,t=0;n<mf->nTracks;++n)
+    if (mf->Queues[n].head && (!seen || t > mf->Queues[n].head->Start))
+      t = mf->Queues[n].head->Start, seen=1;
+
+  return seen ? t : (ulonglong)LL(-1);
+}
+
+int	      mkv_TruncFloat(MKFLOAT f) {
+#ifdef MATROSKA_INTEGER_ONLY
+  return (int)(f.v >> 32);
+#else
+  return (int)f;
+#endif
+}
+
+#define	FTRACK	0xffffffff
+
+void	      mkv_SetTrackMask(MatroskaFile *mf,unsigned int mask) {
+  unsigned int	  i;
+
+  if (mf->flags & MPF_ERROR)
+    return;
+
+  mf->trackMask = mask;
+
+  for (i=0;i<mf->nTracks;++i)
+    if (mask & (1<<i))
+      ClearQueue(mf,&mf->Queues[i]);
+}
+
+int	      mkv_ReadFrame(MatroskaFile *mf,
+			    unsigned int mask,unsigned int *track,
+			    ulonglong *StartTime,ulonglong *EndTime,
+			    ulonglong *FilePos,unsigned int *FrameSize,
+			    unsigned int *FrameFlags)
+{
+  unsigned int	    i,j;
+  struct QueueEntry *qe;
+
+  if (setjmp(mf->jb)!=0)
+    return -1;
+
+  do {
+    // extract required frame, use block with the lowest timecode
+    for (j=FTRACK,i=0;i<mf->nTracks;++i)
+      if (!(mask & (1<<i)) && mf->Queues[i].head) {
+	j = i;
+	++i;
+	break;
+      }
+
+    for (;i<mf->nTracks;++i)
+      if (!(mask & (1<<i)) && mf->Queues[i].head &&
+	  mf->Queues[j].head->Start > mf->Queues[i].head->Start)
+	j = i;
+
+    if (j != FTRACK) {
+      qe = QGet(&mf->Queues[j]);
+
+      *track = j;
+      *StartTime = qe->Start;
+      *EndTime = qe->End;
+      *FilePos = qe->Position;
+      *FrameSize = qe->Length;
+      *FrameFlags = qe->flags;
+
+      QFree(mf,qe);
+
+      return 0;
+    }
+
+    if (mf->flags & MPF_ERROR)
+      return -1;
+
+  } while (fillQueues(mf,mask)>=0);
+
+  return EOF;
+}
+
+#ifdef MATROSKA_COMPRESSION_SUPPORT
+/*************************************************************************
+ * Compressed streams support
+ ************************************************************************/
+struct CompressedStream {
+  MatroskaFile	  *mf;
+  z_stream	  zs;
+
+  /* current compressed frame */
+  ulonglong	  frame_pos;
+  unsigned	  frame_size;
+  char		  frame_buffer[2048];
+
+  /* decoded data buffer */
+  char		  decoded_buffer[2048];
+  unsigned	  decoded_ptr;
+  unsigned	  decoded_size;
+
+  /* error handling */
+  char		  errmsg[128];
+};
+
+CompressedStream  *cs_Create(/* in */	MatroskaFile *mf,
+			     /* in */	unsigned tracknum,
+			     /* out */	char *errormsg,
+			     /* in */	unsigned msgsize)
+{
+  CompressedStream  *cs;
+  TrackInfo	    *ti;
+  int		    code;
+
+  ti = mkv_GetTrackInfo(mf, tracknum);
+  if (ti == NULL) {
+    strlcpy(errormsg, "No such track.", msgsize);
+    return NULL;
+  }
+
+  if (!ti->CompEnabled) {
+    strlcpy(errormsg, "Track is not compressed.", msgsize);
+    return NULL;
+  }
+
+  if (ti->CompMethod != COMP_ZLIB) {
+    strlcpy(errormsg, "Unsupported compression method.", msgsize);
+    return NULL;
+  }
+
+  cs = mf->cache->memalloc(mf->cache,sizeof(*cs));
+  if (cs == NULL) {
+    strlcpy(errormsg, "Ouf of memory.", msgsize);
+    return NULL;
+  }
+
+  memset(&cs->zs,0,sizeof(cs->zs));
+  code = inflateInit(&cs->zs);
+  if (code != Z_OK) {
+    strlcpy(errormsg, "ZLib error.", msgsize);
+    mf->cache->memfree(mf->cache,cs);
+    return NULL;
+  }
+
+  cs->frame_size = 0;
+  cs->decoded_ptr = cs->decoded_size = 0;
+  cs->mf = mf;
+
+  return cs;
+}
+
+void		  cs_Destroy(/* in */ CompressedStream *cs) {
+  if (cs == NULL)
+    return;
+
+  inflateEnd(&cs->zs);
+  cs->mf->cache->memfree(cs->mf->cache,cs);
+}
+
+/* advance to the next frame in matroska stream, you need to pass values returned
+ * by mkv_ReadFrame */
+void		  cs_NextFrame(/* in */ CompressedStream *cs,
+			       /* in */ ulonglong pos,
+			       /* in */ unsigned size)
+{
+  cs->zs.avail_in = 0;
+  inflateReset(&cs->zs);
+  cs->frame_pos = pos;
+  cs->frame_size = size;
+  cs->decoded_ptr = cs->decoded_size = 0;
+}
+
+/* read and decode more data from current frame, return number of bytes decoded,
+ * 0 on end of frame, or -1 on error */
+int		  cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
+{
+  char	    *cp = buffer;
+  unsigned  rd = 0;
+  unsigned  todo;
+  int	    code;
+  
+  do {
+    /* try to copy data from decoded buffer */
+    if (cs->decoded_ptr < cs->decoded_size) {
+      todo = cs->decoded_size - cs->decoded_ptr;;
+      if (todo > bufsize - rd)
+	todo = bufsize - rd;
+
+      memcpy(cp, cs->decoded_buffer + cs->decoded_ptr, todo);
+
+      rd += todo;
+      cp += todo;
+      cs->decoded_ptr += todo;
+    } else {
+      /* setup output buffer */
+      cs->zs.next_out = cs->decoded_buffer;
+      cs->zs.avail_out = sizeof(cs->decoded_buffer);
+
+      /* try to read more data */
+      if (cs->zs.avail_in == 0 && cs->frame_size > 0) {
+	todo = cs->frame_size;
+	if (todo > sizeof(cs->frame_buffer))
+	  todo = sizeof(cs->frame_buffer);
+
+	if (cs->mf->cache->read(cs->mf->cache, cs->frame_pos, cs->frame_buffer, todo) != (int)todo) {
+	  strlcpy(cs->errmsg, "File read failed", sizeof(cs->errmsg));
+	  return -1;
+	}
+
+	cs->zs.next_in = cs->frame_buffer;
+	cs->zs.avail_in = todo;
+
+	cs->frame_pos += todo;
+	cs->frame_size -= todo;
+      }
+
+      /* try to decode more data */
+      code = inflate(&cs->zs,Z_NO_FLUSH);
+      if (code != Z_OK && code != Z_STREAM_END) {
+	strlcpy(cs->errmsg, "ZLib error.", sizeof(cs->errmsg));
+	return -1;
+      }
+
+      /* handle decoded data */
+      if (cs->zs.avail_out == sizeof(cs->decoded_buffer)) /* EOF */
+	break;
+
+      cs->decoded_ptr = 0;
+      cs->decoded_size = sizeof(cs->decoded_buffer) - cs->zs.avail_out;
+    }
+  } while (rd < bufsize);
+
+  return rd;
+}
+
+/* return error message for the last error */
+const char	  *cs_GetLastError(CompressedStream *cs)
+{
+  if (!cs->errmsg[0])
+    return NULL;
+  return cs->errmsg;
+}
+#endif

Added: trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.h
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.h	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/MatroskaParser.h	2005-04-09 18:52:52 UTC (rev 1118)
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2004-2005 Mike Matsnev.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice immediately at the beginning of the file, without modification,
+ *    this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author
+ *    Mike Matsnev.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * $Id: MatroskaParser.h,v 1.10 2005/01/10 04:52:34 mike Exp $
+ * 
+ */
+
+#ifndef MATROSKA_PARSER_H
+#define	MATROSKA_PARSER_H
+
+/* Random notes:
+ *
+ * The parser does not process frame data in any way and does not read it into
+ * the queue. The app should read it via mkv_ReadData if it is interested.
+ *
+ * The code here is 64-bit clean and was tested on FreeBSD/sparc 64-bit big endian
+ * system
+ */
+
+#ifdef MPDLLBUILD
+#define	X __declspec(dllexport)
+#else
+#ifdef MPDLL
+#define X __declspec(dllimport)
+#pragma comment(lib,"MatroskaParser")
+#else
+#define X
+#endif
+#endif
+
+//#define MATROSKA_COMPRESSION_SUPPORT
+//#define	MATROSKA_INTEGER_ONLY
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 64-bit integers */
+#ifdef _WIN32_WCE
+typedef signed __int64	    longlong;
+typedef unsigned __int64    ulonglong;
+#else
+typedef signed long long    longlong;
+typedef unsigned long long  ulonglong;
+#endif
+
+/* MKFLOATing point */
+#ifdef MATROSKA_INTEGER_ONLY
+typedef struct {
+  longlong	v;
+} MKFLOAT;
+#else
+typedef	double	MKFLOAT;
+#endif
+
+/* generic I/O */
+struct InputStream {
+  /* read bytes from stream */
+  int	      (*read)(struct InputStream *cc,ulonglong pos,void *buffer,int count);
+  /* scan for a four byte signature, bytes must be nonzero */
+  longlong    (*scan)(struct InputStream *cc,ulonglong start,unsigned signature);
+  /* get cache size, this is used to cap readahead */
+  unsigned    (*getsize)(struct InputStream *cc);
+  /* fetch last error message */
+  const char *(*geterror)(struct InputStream *cc);
+  /* memory allocation */
+  void	      *(*memalloc)(struct InputStream *cc,size_t size);
+  void	      *(*memrealloc)(struct InputStream *cc,void *mem,size_t newsize);
+  void	      (*memfree)(struct InputStream *cc,void *mem);
+  // zero return causes parser to abort open
+  int	      (*progress)(struct InputStream *cc,ulonglong cur,ulonglong max);
+};
+
+typedef struct InputStream InputStream;
+
+/* matroska file */
+struct MatroskaFile; /* opaque */
+
+typedef struct MatroskaFile MatroskaFile;
+
+#define	COMP_ZLIB   0
+
+#define	TT_VIDEO    1
+#define	TT_AUDIO    2
+#define	TT_SUB	    17
+
+struct TrackInfo {
+  unsigned char	  Number;
+  unsigned char	  Type;
+  unsigned char	  TrackOverlay;
+  ulonglong	  UID;
+  ulonglong	  MinCache;
+  ulonglong	  MaxCache;
+  ulonglong	  DefaultDuration;
+  MKFLOAT	  TimecodeScale;
+  void		  *CodecPrivate;
+  unsigned	  CodecPrivateSize;
+  unsigned	  CompMethod;
+  struct {
+    unsigned int  Enabled:1;
+    unsigned int  Default:1;
+    unsigned int  Lacing:1;
+    unsigned int  DecodeAll:1;
+    unsigned int  CompEnabled:1;
+  };
+
+  union {
+    struct {
+      unsigned char   StereoMode;
+      unsigned char   DisplayUnit;
+      unsigned char   AspectRatioType;
+      unsigned int    PixelWidth;
+      unsigned int    PixelHeight;
+      unsigned int    DisplayWidth;
+      unsigned int    DisplayHeight;
+      unsigned int    ColourSpace;
+      MKFLOAT	      GammaValue;
+      struct {
+	unsigned int  Interlaced:1;
+      };
+    } Video;
+    struct {
+      MKFLOAT	      SamplingFreq;
+      MKFLOAT	      OutputSamplingFreq;
+      unsigned char   Channels;
+      unsigned char   BitDepth;
+    } Audio;
+  };
+
+  /* various strings */
+  char			*Name;
+  char			*Language;
+  char			*CodecID;
+};
+
+typedef struct TrackInfo  TrackInfo;
+
+struct SegmentInfo {
+  char			UID[16];
+  char			PrevUID[16];
+  char			NextUID[16];
+  char			*Filename;
+  char			*PrevFilename;
+  char			*NextFilename;
+  char			*Title;
+  char			*MuxingApp;
+  char			*WritingApp;
+  ulonglong		TimecodeScale;
+  ulonglong		Duration;
+  ulonglong		DateUTC;
+};
+
+typedef struct SegmentInfo SegmentInfo;
+
+struct Attachment {
+  ulonglong		Position;
+  ulonglong		Length;
+  ulonglong		UID;
+  char			*Name;
+  char			*Description;
+  char			*MimeType;
+};
+
+typedef struct Attachment Attachment;
+
+struct ChapterDisplay {
+  char			*String;
+  char			*Language;
+  char			*Country;
+};
+
+struct ChapterCommand {
+  unsigned		Time;
+  unsigned		CommandLength;
+  char			*Command;
+};
+
+struct ChapterProcess {
+  unsigned		CodecID;
+  unsigned		CodecPrivateLength;
+  char			*CodecPrivate;
+  unsigned		nCommands,nCommandsSize;
+  struct ChapterCommand	*Commands;
+};
+
+struct Chapter {
+  ulonglong		UID;
+  ulonglong		Start;
+  ulonglong		End;
+
+  unsigned		nTracks,nTracksSize;
+  ulonglong		*Tracks;
+  unsigned		nDisplay,nDisplaySize;
+  struct ChapterDisplay	*Display;
+  unsigned		nChildren,nChildrenSize;
+  struct Chapter	*Children;
+  unsigned		nProcess,nProcessSize;
+  struct ChapterProcess	*Process;
+
+  struct {
+    unsigned int	Hidden:1;
+    unsigned int	Enabled:1;
+
+    // Editions
+    unsigned int	Default:1;
+    unsigned int	Ordered:1;
+  };
+};
+
+typedef struct Chapter	Chapter;
+
+#define	TARGET_TRACK	  0
+#define	TARGET_CHAPTER	  1
+#define	TARGET_ATTACHMENT 2
+#define	TARGET_EDITION	  3
+struct Target {
+  ulonglong	    UID;
+  unsigned	    Type;
+};
+
+struct SimpleTag {
+  char		    *Name;
+  char		    *Value;
+  char		    *Language;
+  unsigned	    Default:1;
+};
+
+struct Tag {
+  unsigned	    nTargets,nTargetsSize;
+  struct Target	    *Targets;
+
+  unsigned	    nSimpleTags,nSimpleTagsSize;
+  struct SimpleTag  *SimpleTags;
+};
+
+typedef struct Tag  Tag;
+
+/* Open a matroska file
+ * io pointer is recorded inside MatroskaFile
+ */
+X MatroskaFile  *mkv_Open(/* in */ InputStream *io,
+			/* out */ char *err_msg,
+			/* in */  unsigned msgsize);
+
+#define	MKVF_AVOID_SEEKS    1 /* use sequential reading only */
+
+X MatroskaFile  *mkv_OpenEx(/* in */  InputStream *io,
+			  /* in */  ulonglong base,
+			  /* in */  unsigned flags,
+			  /* out */ char *err_msg,
+			  /* in */  unsigned msgsize);
+
+/* Close and deallocate mf
+ * NULL pointer is ok and is simply ignored
+ */
+X void		mkv_Close(/* in */ MatroskaFile *mf);
+
+/* Fetch the error message of the last failed operation */
+X const char    *mkv_GetLastError(/* in */ MatroskaFile *mf);
+
+/* Get file information */
+X SegmentInfo   *mkv_GetFileInfo(/* in */ MatroskaFile *mf);
+
+/* Get track information */
+X unsigned int  mkv_GetNumTracks(/* in */ MatroskaFile *mf);
+X TrackInfo     *mkv_GetTrackInfo(/* in */ MatroskaFile *mf,/* in */ unsigned track);
+
+/* chapters, tags and attachments */
+X void	      mkv_GetAttachments(/* in */   MatroskaFile *mf,
+				 /* out */  Attachment **at,
+				 /* out */  unsigned *count);
+X void	      mkv_GetChapters(/* in */	MatroskaFile *mf,
+			      /* out */	Chapter **ch,
+			      /* out */ unsigned *count);
+X void	      mkv_GetTags(/* in */  MatroskaFile *mf,
+			  /* out */ Tag **tag,
+			  /* out */ unsigned *count);
+
+X ulonglong   mkv_GetSegmentTop(MatroskaFile *mf);
+
+/* Seek to specified timecode,
+ * if timecode is past end of file,
+ * all tracks are set to return EOF
+ * on next read
+ */
+#define	MKVF_SEEK_TO_PREV_KEYFRAME  1
+
+X void	      mkv_Seek(/* in */ MatroskaFile *mf,
+		       /* in */	ulonglong timecode /* in ns */,
+		       /* in */ unsigned flags);
+
+X void	      mkv_SkipToKeyframe(MatroskaFile *mf);
+
+X ulonglong   mkv_GetLowestQTimecode(MatroskaFile *mf);
+
+X int	      mkv_TruncFloat(MKFLOAT f);
+
+/*************************************************************************
+ * reading data, pull model
+ */
+
+/* frame flags */
+#define	FRAME_KF	      0x00000001
+#define	FRAME_UNKNOWN_START   0x00000002
+#define	FRAME_UNKNOWN_END     0x00000004
+#define	FRAME_GAP	      0x00000008
+
+/* This sets the masking flags for the parser,
+ *  masked tracks [with 1s in their bit positions]
+ *  will be ignored when reading file data.
+ * This call discards all parsed and queued frames
+ */
+X void	      mkv_SetTrackMask(/* in */ MatroskaFile *mf,/* in */ unsigned int mask);
+
+/* Read one frame from the queue.
+ * mask specifies what tracks to ignore.
+ * Returns -1 if there are no more frames in the specified
+ * set of tracks, 0 on success
+ */
+X int	      mkv_ReadFrame(/* in */  MatroskaFile *mf,
+			    /* in */  unsigned int mask,
+			    /* out */ unsigned int *track,
+			    /* out */ ulonglong *StartTime /* in ns */,
+			    /* out */ ulonglong *EndTime /* in ns */,
+			    /* out */ ulonglong *FilePos /* in bytes from start of file */,
+			    /* out */ unsigned int *FrameSize /* in bytes */,
+			    /* out */ unsigned int *FrameFlags);
+
+/* Read raw frame data, invokes underlying io methods,
+ * but keeps track of the file pointer for internal buffering.
+ * Returns the -1 if error occurred, or 0 on success
+ */
+X int	      mkv_ReadData(/* in */   MatroskaFile *mf,
+			   /* in */   ulonglong FilePos,
+			   /* out */  void *Buffer,
+			   /* in */   unsigned int Count);
+
+#ifdef MATROSKA_COMPRESSION_SUPPORT
+/* Compressed streams support */
+struct CompressedStream;
+
+typedef struct CompressedStream CompressedStream;
+
+X CompressedStream  *cs_Create(/* in */	MatroskaFile *mf,
+			     /* in */	unsigned tracknum,
+			     /* out */	char *errormsg,
+			     /* in */	unsigned msgsize);
+X void		  cs_Destroy(/* in */ CompressedStream *cs);
+
+/* advance to the next frame in matroska stream, you need to pass values returned
+ * by mkv_ReadFrame */
+X void		  cs_NextFrame(/* in */ CompressedStream *cs,
+			       /* in */ ulonglong pos,
+			       /* in */ unsigned size);
+
+/* read and decode more data from current frame, return number of bytes decoded,
+ * 0 on end of frame, or -1 on error */
+X int		  cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize);
+
+/* return error message for the last error */
+X const char	  *cs_GetLastError(CompressedStream *cs);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef X
+
+#endif

Added: trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.c
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.c	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.c	2005-04-09 18:52:52 UTC (rev 1118)
@@ -0,0 +1,133 @@
+#include "Win32Stream.h"
+
+#define	CACHESIZE     65536
+
+/* Win32Stream methods */
+
+/* read count bytes into buffer starting at file position pos
+* return the number of bytes read, -1 on error or 0 on EOF
+*/
+static int Win32Read(Win32Stream *st, ulonglong pos, void *buffer, int count) {
+  DWORD BytesRead;
+  LONG High = (LONG)(pos>>32);
+  SetFilePointer(st->fp, (LONG)(pos & 0xffffffff), &High, FILE_BEGIN);
+  
+  if (!ReadFile(st->fp, buffer, count, &BytesRead, NULL)) {
+    return 0;
+  }
+  return (int)BytesRead;
+}
+
+/* scan for a signature sig(big-endian) starting at file position pos
+* return position of the first byte of signature or -1 if error/not found
+*/
+static longlong Win32Scan(Win32Stream *st, ulonglong start, unsigned signature) {
+  char c;
+  unsigned cmp = 0;
+  ulonglong pos = start;
+  LONG High = (LONG)(start>>32);
+
+  SetFilePointer(st->fp, (LONG)(start & 0xffffffff), &High, FILE_BEGIN);
+
+  while (Win32Read(st, pos, &c, 1) != 0) {
+    cmp = ((cmp << 8) | c) & 0xffffffff;
+    if (cmp == signature)
+      return pos - 4;
+    pos++;
+  }
+
+  return -1;
+}
+
+/* return cache size, this is used to limit readahead */
+static unsigned Win32GetCacheSize(Win32Stream *st) {
+  return CACHESIZE;
+}
+
+/* return last error message */
+static const char *Win32GetLastError(Win32Stream *st) {
+  return strerror(st->error);
+}
+
+/* memory allocation, this is done via stdlib */
+static void  *Win32Malloc(Win32Stream *st, size_t size) {
+  return malloc(size);
+}
+
+static void  *Win32Realloc(Win32Stream *st, void *mem, size_t size) {
+  return realloc(mem,size);
+}
+
+static void Win32Free(Win32Stream *st, void *mem) {
+  free(mem);
+}
+
+/* progress report handler for lengthy operations
+* returns 0 to abort operation, nonzero to continue
+*/
+static int Win32Progress(Win32Stream *st, ulonglong cur, ulonglong max) {
+  return 1;
+}
+
+void Win32Stream_Init(Win32Stream *st)
+{
+  /* fill in I/O object */
+  memset(st, 0, sizeof(Win32Stream));
+  st->base.read = Win32Read;
+  st->base.scan = Win32Scan;
+  st->base.getsize = Win32GetCacheSize;
+  st->base.geterror = Win32GetLastError;
+  st->base.memalloc = Win32Malloc;
+  st->base.memrealloc = Win32Realloc;
+  st->base.memfree = Win32Free;
+  st->base.progress = Win32Progress;
+}
+
+int Win32Stream_Open(Win32Stream *st, const char *filename)
+{
+  return Win32Stream_OpenA(st, filename);
+}
+
+int Win32Stream_OpenA(Win32Stream *st, const char *filename)
+{
+  DWORD AccessMode, ShareMode, Disposition;
+  DWORD dwFlags = 0;
+
+  AccessMode = GENERIC_READ;
+  ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+  Disposition = OPEN_EXISTING;
+
+  st->fp = CreateFileA(filename, AccessMode, ShareMode, NULL, Disposition, dwFlags, NULL);
+  if ((st->fp == INVALID_HANDLE_VALUE) || ((long)st->fp == 0xffffffff))
+  {
+    // File was not opened
+    return (int)GetLastError();
+  }
+
+  return 0;
+}
+
+int Win32Stream_OpenW(Win32Stream *st, const wchar_t *filename)
+{
+  DWORD AccessMode, ShareMode, Disposition;
+  DWORD dwFlags = 0;
+
+  AccessMode = GENERIC_READ;
+  ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+  Disposition = OPEN_EXISTING;
+
+  st->fp = CreateFileW(filename, AccessMode, ShareMode, NULL, Disposition, dwFlags, NULL);
+  if ((st->fp == INVALID_HANDLE_VALUE) || ((long)st->fp == 0xffffffff))
+  {
+    // File was not opened
+    return (int)GetLastError();
+  }
+
+  return 0;
+}
+
+void Win32Stream_Close(Win32Stream *st)
+{
+  CloseHandle(st->fp);
+  st->fp = NULL;
+}

Added: trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.h
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.h	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska/Win32Stream.h	2005-04-09 18:52:52 UTC (rev 1118)
@@ -0,0 +1,29 @@
+#ifndef _WIN32_STREAM_H_
+#define _WIN32_STREAM_H_
+
+#include <windows.h>
+#include "MatroskaParser.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Win32Stream {
+  struct InputStream  base;
+  HANDLE fp;
+  int error;
+};
+typedef struct Win32Stream Win32Stream;
+
+// Helper methods
+void Win32Stream_Init(Win32Stream *st);
+int Win32Stream_Open(Win32Stream *st, const char *filename);
+int Win32Stream_OpenA(Win32Stream *st, const char *filename);
+int Win32Stream_OpenW(Win32Stream *st, const wchar_t *filename);
+void Win32Stream_Close(Win32Stream *st);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _WIN32_STREAM_H_
\ No newline at end of file

Added: trunk/MatroskaUtils/GDC/GDCMatroska-Setup/GDCMatroska-Setup.vdproj
===================================================================
--- trunk/MatroskaUtils/GDC/GDCMatroska-Setup/GDCMatroska-Setup.vdproj	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GDCMatroska-Setup/GDCMatroska-Setup.vdproj	2005-04-09 18:52:52 UTC (rev 1118)
@@ -0,0 +1,689 @@
+"DeployProject"
+{
+"VSVersion" = "3:701"
+"ProjectType" = "8:{2C2AF0D9-9B47-4FE5-BEF2-169778172667}"
+"IsWebType" = "8:FALSE"
+"ProjectName" = "8:GDCMatroska-Setup"
+"LanguageId" = "3:1033"
+"CodePage" = "3:1252"
+"UILanguageId" = "3:1033"
+"SccProjectName" = "8:"
+"SccLocalPath" = "8:"
+"SccAuxPath" = "8:"
+"SccProvider" = "8:"
+    "Hierarchy"
+    {
+        "Entry"
+        {
+        "MsmKey" = "8:_66C3065023A74F609C625313053DA8F8"
+        "OwnerKey" = "8:_E4F05E1860E8454A9F39C151AA3D3A86"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_E4F05E1860E8454A9F39C151AA3D3A86"
+        "OwnerKey" = "8:_UNDEFINED"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+    }
+    "Configurations"
+    {
+        "Debug"
+        {
+        "DisplayName" = "8:Debug"
+        "IsDebugOnly" = "11:TRUE"
+        "IsReleaseOnly" = "11:FALSE"
+        "OutputFilename" = "8:Debug\\GDCMatroska-Setup.msi"
+        "PackageFilesAs" = "3:2"
+        "PackageFileSize" = "3:-2147483648"
+        "CabType" = "3:1"
+        "Compression" = "3:2"
+        "SignOutput" = "11:FALSE"
+        "CertificateFile" = "8:"
+        "PrivateKeyFile" = "8:"
+        "TimeStampServer" = "8:"
+        "InstallerBootstrapper" = "3:2"
+        }
+        "Release"
+        {
+        "DisplayName" = "8:Release"
+        "IsDebugOnly" = "11:FALSE"
+        "IsReleaseOnly" = "11:TRUE"
+        "OutputFilename" = "8:Release\\GDCMatroska-Setup.msi"
+        "PackageFilesAs" = "3:2"
+        "PackageFileSize" = "3:-2147483648"
+        "CabType" = "3:1"
+        "Compression" = "3:3"
+        "SignOutput" = "11:FALSE"
+        "CertificateFile" = "8:"
+        "PrivateKeyFile" = "8:"
+        "TimeStampServer" = "8:"
+        "InstallerBootstrapper" = "3:2"
+        }
+    }
+    "Deployable"
+    {
+        "CustomAction"
+        {
+        }
+        "DefaultFeature"
+        {
+        "Name" = "8:DefaultFeature"
+        "Title" = "8:"
+        "Description" = "8:"
+        }
+        "ExternalPersistence"
+        {
+            "LaunchCondition"
+            {
+            }
+        }
+        "Feature"
+        {
+        }
+        "File"
+        {
+        }
+        "FileType"
+        {
+        }
+        "Folder"
+        {
+            "{58C0ADA3-3CEA-43BD-A3B3-2EA121BC8217}:_5E96DF27E65D45FB9A81C83FD074A586"
+            {
+            "DefaultLocation" = "8:[ProgramFilesFolder][ProductName]"
+            "Name" = "8:#1925"
+            "AlwaysCreate" = "11:FALSE"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Property" = "8:TARGETDIR"
+                "Folders"
+                {
+                }
+            }
+            "{78BAF5CE-F2E5-45BE-83BC-DB6AF387E941}:_66B776E609CA46389E9E85C159778E30"
+            {
+            "Name" = "8:#1919"
+            "AlwaysCreate" = "11:FALSE"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Property" = "8:ProgramMenuFolder"
+                "Folders"
+                {
+                }
+            }
+            "{78BAF5CE-F2E5-45BE-83BC-DB6AF387E941}:_79C70FF64A3B400C88C3F0CFA73D0246"
+            {
+            "Name" = "8:#1916"
+            "AlwaysCreate" = "11:FALSE"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Property" = "8:DesktopFolder"
+                "Folders"
+                {
+                }
+            }
+        }
+        "LaunchCondition"
+        {
+        }
+        "Locator"
+        {
+        }
+        "MsiBootstrapper"
+        {
+        "LangId" = "3:1033"
+        }
+        "Product"
+        {
+        "Name" = "8:Microsoft Visual Studio"
+        "ProductName" = "8:GDCMatroska"
+        "ProductCode" = "8:{ACAC7295-2780-4B24-9E3D-AE1F703A0268}"
+        "PackageCode" = "8:{8FF50B41-09F3-4415-BDA0-BE37E07D1D27}"
+        "UpgradeCode" = "8:{884E153F-08C8-40A9-86E4-46B1C75596B6}"
+        "RestartWWWService" = "11:FALSE"
+        "RemovePreviousVersions" = "11:TRUE"
+        "DetectNewerInstalledVersion" = "11:TRUE"
+        "ProductVersion" = "8:1.0.0"
+        "Manufacturer" = "8:Jory Stone"
+        "ARPHELPTELEPHONE" = "8:"
+        "ARPHELPLINK" = "8:"
+        "Title" = "8:GDC Matroska"
+        "Subject" = "8:"
+        "ARPCONTACT" = "8:Jory Stone"
+        "Keywords" = "8:"
+        "ARPCOMMENTS" = "8:Google Desktop Search plugin for Matroska (http://www.matroska.org) files"
+        "ARPURLINFOABOUT" = "8:http://www.jory.info/"
+        "ARPPRODUCTICON" = "8:"
+        "ARPIconIndex" = "3:0"
+        "SearchPath" = "8:"
+        "UseSystemSearchPath" = "11:TRUE"
+        }
+        "Registry"
+        {
+            "HKLM"
+            {
+                "Keys"
+                {
+                    "{6A471EEF-D31B-40F8-BCF6-C9E8EC783F36}:_91017A2C2F4B4FEA97BDD24019B232E5"
+                    {
+                    "Name" = "8:Software"
+                    "Condition" = "8:"
+                    "AlwaysCreate" = "11:FALSE"
+                    "DeleteAtUninstall" = "11:FALSE"
+                    "Transitive" = "11:FALSE"
+                        "Keys"
+                        {
+                            "{6A471EEF-D31B-40F8-BCF6-C9E8EC783F36}:_11A0764738334FF28E2EA73091721C67"
+                            {
+                            "Name" = "8:[Manufacturer]"
+                            "Condition" = "8:"
+                            "AlwaysCreate" = "11:FALSE"
+                            "DeleteAtUninstall" = "11:FALSE"
+                            "Transitive" = "11:FALSE"
+                                "Keys"
+                                {
+                                }
+                                "Values"
+                                {
+                                }
+                            }
+                        }
+                        "Values"
+                        {
+                        }
+                    }
+                }
+            }
+            "HKCU"
+            {
+                "Keys"
+                {
+                    "{6A471EEF-D31B-40F8-BCF6-C9E8EC783F36}:_82D4D49B9C7D43658D6E97AB3F16C20F"
+                    {
+                    "Name" = "8:Software"
+                    "Condition" = "8:"
+                    "AlwaysCreate" = "11:FALSE"
+                    "DeleteAtUninstall" = "11:FALSE"
+                    "Transitive" = "11:FALSE"
+                        "Keys"
+                        {
+                            "{6A471EEF-D31B-40F8-BCF6-C9E8EC783F36}:_3798F9082C44481FA416A0C050DEA771"
+                            {
+                            "Name" = "8:[Manufacturer]"
+                            "Condition" = "8:"
+                            "AlwaysCreate" = "11:FALSE"
+                            "DeleteAtUninstall" = "11:FALSE"
+                            "Transitive" = "11:FALSE"
+                                "Keys"
+                                {
+                                }
+                                "Values"
+                                {
+                                }
+                            }
+                        }
+                        "Values"
+                        {
+                        }
+                    }
+                }
+            }
+            "HKCR"
+            {
+                "Keys"
+                {
+                }
+            }
+            "HKU"
+            {
+                "Keys"
+                {
+                }
+            }
+            "HKPU"
+            {
+                "Keys"
+                {
+                }
+            }
+        }
+        "Sequences"
+        {
+        }
+        "Shortcut"
+        {
+        }
+        "UserInterface"
+        {
+            "{B654A020-6903-4E6A-A86C-75DC463DB54B}:_26BD223BEAF44137BAD38A211617F2E9"
+            {
+            "UseDynamicProperties" = "11:FALSE"
+            "IsDependency" = "11:FALSE"
+            "SourcePath" = "8:<VsdDialogDir>\\VsdUserInterface.wim"
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_38BB4BED33F244738C4AC960CC0C8001"
+            {
+            "Name" = "8:#1901"
+            "Sequence" = "3:1"
+            "Attributes" = "3:2"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_B0B3B5C1F139416CA30BEC9724DD7C68"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Progress"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdProgressDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "ShowProgress"
+                            {
+                            "Name" = "8:ShowProgress"
+                            "DisplayName" = "8:#1009"
+                            "Description" = "8:#1109"
+                            "Type" = "3:5"
+                            "ContextData" = "8:1;True=1;False=0"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:0"
+                            "Value" = "3:1"
+                            "DefaultValue" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_3F751F04EDA24F67B1F104C0075D6250"
+            {
+            "Name" = "8:#1900"
+            "Sequence" = "3:2"
+            "Attributes" = "3:1"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_7A6D9140B95E4EF1B89EA075657BC505"
+                    {
+                    "Sequence" = "3:200"
+                    "DisplayName" = "8:Installation Folder"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdAdminFolderDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_D0A26A2B99634D2CAB2D13175B68C73F"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Welcome"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdAdminWelcomeDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "CopyrightWarning"
+                            {
+                            "Name" = "8:CopyrightWarning"
+                            "DisplayName" = "8:#1002"
+                            "Description" = "8:#1102"
+                            "Type" = "3:3"
+                            "ContextData" = "8:"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:1"
+                            "Value" = "8:#1202"
+                            "DefaultValue" = "8:#1202"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "Welcome"
+                            {
+                            "Name" = "8:Welcome"
+                            "DisplayName" = "8:#1003"
+                            "Description" = "8:#1103"
+                            "Type" = "3:3"
+                            "ContextData" = "8:"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:1"
+                            "Value" = "8:#1203"
+                            "DefaultValue" = "8:#1203"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_DA1202FB917B4357B4E84104848A65AE"
+                    {
+                    "Sequence" = "3:300"
+                    "DisplayName" = "8:Confirm Installation"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdAdminConfirmDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_58460D94ED6D45DAA6F984638440BEEB"
+            {
+            "Name" = "8:#1902"
+            "Sequence" = "3:2"
+            "Attributes" = "3:3"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_89A82E63E01942A992AD270A2E4505DF"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Finished"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdAdminFinishedDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_74EF7D43B5254DCAB47620B555A35AFF"
+            {
+            "Name" = "8:#1902"
+            "Sequence" = "3:1"
+            "Attributes" = "3:3"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_2D9D9DBC01B04592A4CE920E554E4975"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Finished"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdFinishedDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "UpdateText"
+                            {
+                            "Name" = "8:UpdateText"
+                            "DisplayName" = "8:#1058"
+                            "Description" = "8:#1158"
+                            "Type" = "3:15"
+                            "ContextData" = "8:"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:1"
+                            "Value" = "8:#1258"
+                            "DefaultValue" = "8:#1258"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_7AD9EA6D9E654E7C8ADE395310AA72BE"
+            {
+            "Name" = "8:#1901"
+            "Sequence" = "3:2"
+            "Attributes" = "3:2"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_2BC68147F0B24346B444A9381E6467FE"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Progress"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdAdminProgressDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "ShowProgress"
+                            {
+                            "Name" = "8:ShowProgress"
+                            "DisplayName" = "8:#1009"
+                            "Description" = "8:#1109"
+                            "Type" = "3:5"
+                            "ContextData" = "8:1;True=1;False=0"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:0"
+                            "Value" = "3:1"
+                            "DefaultValue" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{8D9DEE8B-DD8B-4F48-9072-C4364E4F4011}:_B3FB25833E0144E8B64CE2827A0D557F"
+            {
+            "Name" = "8:#1900"
+            "Sequence" = "3:1"
+            "Attributes" = "3:1"
+                "Dialogs"
+                {
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_25ACFA11F84D4623A06452B4C53CA704"
+                    {
+                    "Sequence" = "3:100"
+                    "DisplayName" = "8:Welcome"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdWelcomeDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "CopyrightWarning"
+                            {
+                            "Name" = "8:CopyrightWarning"
+                            "DisplayName" = "8:#1002"
+                            "Description" = "8:#1102"
+                            "Type" = "3:3"
+                            "ContextData" = "8:"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:1"
+                            "Value" = "8:#1202"
+                            "DefaultValue" = "8:#1202"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                            "Welcome"
+                            {
+                            "Name" = "8:Welcome"
+                            "DisplayName" = "8:#1003"
+                            "Description" = "8:#1103"
+                            "Type" = "3:3"
+                            "ContextData" = "8:"
+                            "Attributes" = "3:0"
+                            "Setting" = "3:1"
+                            "Value" = "8:#1203"
+                            "DefaultValue" = "8:#1203"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_720DB0273B7246BC98C89098F314F307"
+                    {
+                    "Sequence" = "3:300"
+                    "DisplayName" = "8:Confirm Installation"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdConfirmDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                    "{18ADD6EC-89FE-4ED7-AD3E-211C40278470}:_AE4F2ED222C94D67A81227D137F31AF5"
+                    {
+                    "Sequence" = "3:200"
+                    "DisplayName" = "8:Installation Folder"
+                    "UseDynamicProperties" = "11:TRUE"
+                    "IsDependency" = "11:FALSE"
+                    "SourcePath" = "8:<VsdDialogDir>\\VsdFolderDlg.wid"
+                        "Properties"
+                        {
+                            "BannerBitmap"
+                            {
+                            "Name" = "8:BannerBitmap"
+                            "DisplayName" = "8:#1001"
+                            "Description" = "8:#1101"
+                            "Type" = "3:8"
+                            "ContextData" = "8:Bitmap"
+                            "Attributes" = "3:4"
+                            "Setting" = "3:1"
+                            "UsePlugInResources" = "11:TRUE"
+                            }
+                        }
+                    }
+                }
+            }
+            "{B654A020-6903-4E6A-A86C-75DC463DB54B}:_E92AB8923820480FB0A10BC986FCB86B"
+            {
+            "UseDynamicProperties" = "11:FALSE"
+            "IsDependency" = "11:FALSE"
+            "SourcePath" = "8:<VsdDialogDir>\\VsdBasicDialogs.wim"
+            }
+        }
+        "MergeModule"
+        {
+            "{35A69C6E-5BA4-440D-803D-762B59A45393}:_66C3065023A74F609C625313053DA8F8"
+            {
+            "UseDynamicProperties" = "11:TRUE"
+            "IsDependency" = "11:TRUE"
+            "SourcePath" = "8:vc_user_crt71_rtl_x86_---.msm"
+                "Properties"
+                {
+                }
+            "LanguageId" = "3:0"
+            "Exclude" = "11:FALSE"
+            "Folder" = "8:"
+            "Feature" = "8:"
+            "IsolateTo" = "8:"
+            }
+        }
+        "ProjectOutput"
+        {
+            "{8062640A-2EEE-46E9-AB67-688E9A886E9F}:_E4F05E1860E8454A9F39C151AA3D3A86"
+            {
+            "SourcePath" = "8:..\\GDCMatroska\\Release\\GDCMatroska.dll"
+            "TargetName" = "8:"
+            "Tag" = "8:"
+            "Folder" = "8:_5E96DF27E65D45FB9A81C83FD074A586"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:FALSE"
+            "IsolateTo" = "8:"
+            "ProjectOutputGroupRegister" = "3:4"
+            "OutputConfiguration" = "8:"
+            "OutputGroupCanonicalName" = "8:Built"
+            "OutputProjectGuid" = "8:{D850DCDA-78AD-42C1-BF71-B5995900BCA9}"
+            "ShowKeyOutput" = "11:TRUE"
+                "ExcludeFilters"
+                {
+                }
+            }
+        }
+        "VJSharpPlugin"
+        {
+        }
+    }
+}

Modified: trunk/MatroskaUtils/GDC/GoogleDesktopComponent.sln
===================================================================
--- trunk/MatroskaUtils/GDC/GoogleDesktopComponent.sln	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/GoogleDesktopComponent.sln	2005-04-09 18:52:52 UTC (rev 1118)
@@ -1,47 +1,23 @@
 Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmatroska", "..\..\libmatroska\make\vc7\lib\static\libmatroska.v71.vcproj", "{FD69BB21-A9BF-4486-9B8A-F0E88C82F704}"
-	ProjectSection(ProjectDependencies) = postProject
-		{168C0F0D-9975-4D24-885C-87A9B018617E} = {168C0F0D-9975-4D24-885C-87A9B018617E}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libebml", "..\..\libebml\make\vc7\lib\libebml.v71.vcproj", "{168C0F0D-9975-4D24-885C-87A9B018617E}"
-	ProjectSection(ProjectDependencies) = postProject
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MatroskaUtils", "..\MatroskaUtils.vcproj", "{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}"
-	ProjectSection(ProjectDependencies) = postProject
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GoogleDesktopComponentCommon", "common\GoogleDesktopComponentCommon.vcproj", "{5A0D55C3-7C2A-4B61-8F28-6B757052788F}"
 	ProjectSection(ProjectDependencies) = postProject
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GDCMatroska", "GDCMatroska\GDCMatroska.vcproj", "{D850DCDA-78AD-42C1-BF71-B5995900BCA9}"
 	ProjectSection(ProjectDependencies) = postProject
-		{168C0F0D-9975-4D24-885C-87A9B018617E} = {168C0F0D-9975-4D24-885C-87A9B018617E}
-		{FD69BB21-A9BF-4486-9B8A-F0E88C82F704} = {FD69BB21-A9BF-4486-9B8A-F0E88C82F704}
 		{5A0D55C3-7C2A-4B61-8F28-6B757052788F} = {5A0D55C3-7C2A-4B61-8F28-6B757052788F}
-		{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750} = {E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}
 	EndProjectSection
 EndProject
+Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "GDCMatroska-Setup", "GDCMatroska-Setup\GDCMatroska-Setup.vdproj", "{79B454A7-63FC-4774-9EF1-A823D2CC0DB9}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfiguration) = preSolution
 		Debug = Debug
 		Release = Release
 	EndGlobalSection
 	GlobalSection(ProjectConfiguration) = postSolution
-		{FD69BB21-A9BF-4486-9B8A-F0E88C82F704}.Debug.ActiveCfg = Debug|Win32
-		{FD69BB21-A9BF-4486-9B8A-F0E88C82F704}.Debug.Build.0 = Debug|Win32
-		{FD69BB21-A9BF-4486-9B8A-F0E88C82F704}.Release.ActiveCfg = Release|Win32
-		{FD69BB21-A9BF-4486-9B8A-F0E88C82F704}.Release.Build.0 = Release|Win32
-		{168C0F0D-9975-4D24-885C-87A9B018617E}.Debug.ActiveCfg = Debug|Win32
-		{168C0F0D-9975-4D24-885C-87A9B018617E}.Debug.Build.0 = Debug|Win32
-		{168C0F0D-9975-4D24-885C-87A9B018617E}.Release.ActiveCfg = Release|Win32
-		{168C0F0D-9975-4D24-885C-87A9B018617E}.Release.Build.0 = Release|Win32
-		{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}.Debug.ActiveCfg = Debug Minimal|Win32
-		{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}.Debug.Build.0 = Debug Minimal|Win32
-		{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}.Release.ActiveCfg = Release Minimal|Win32
-		{E3C2A4E1-3DC5-4B67-A3F1-D8AB645DC750}.Release.Build.0 = Release Minimal|Win32
 		{5A0D55C3-7C2A-4B61-8F28-6B757052788F}.Debug.ActiveCfg = Debug|Win32
 		{5A0D55C3-7C2A-4B61-8F28-6B757052788F}.Debug.Build.0 = Debug|Win32
 		{5A0D55C3-7C2A-4B61-8F28-6B757052788F}.Release.ActiveCfg = Release|Win32
@@ -50,6 +26,8 @@
 		{D850DCDA-78AD-42C1-BF71-B5995900BCA9}.Debug.Build.0 = Debug|Win32
 		{D850DCDA-78AD-42C1-BF71-B5995900BCA9}.Release.ActiveCfg = Release|Win32
 		{D850DCDA-78AD-42C1-BF71-B5995900BCA9}.Release.Build.0 = Release|Win32
+		{79B454A7-63FC-4774-9EF1-A823D2CC0DB9}.Debug.ActiveCfg = Debug
+		{79B454A7-63FC-4774-9EF1-A823D2CC0DB9}.Release.ActiveCfg = Release
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 	EndGlobalSection

Modified: trunk/MatroskaUtils/GDC/common/GoogleDesktopComponentCommon.vcproj
===================================================================
--- trunk/MatroskaUtils/GDC/common/GoogleDesktopComponentCommon.vcproj	2005-04-09 18:30:20 UTC (rev 1117)
+++ trunk/MatroskaUtils/GDC/common/GoogleDesktopComponentCommon.vcproj	2005-04-09 18:52:52 UTC (rev 1118)
@@ -55,11 +55,11 @@
 			OutputDirectory="Release"
 			IntermediateDirectory="Release"
 			ConfigurationType="4"
-			CharacterSet="2">
+			CharacterSet="1">
 			<Tool
 				Name="VCCLCompilerTool"
 				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
-				RuntimeLibrary="2"
+				RuntimeLibrary="0"
 				UsePrecompiledHeader="3"
 				WarningLevel="3"
 				Detect64BitPortabilityProblems="TRUE"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.