[matroska] r1297 - trunk/foo_input_matroska

[email protected] Sun, 10 Jun 2007 19:33:52 +0400 (MSD)
Newsgroups gmane.comp.multimedia.matroska.cvs
Message-ID <[email protected]>
Author: ayana
Date: 2007-06-10 19:33:45 +0400 (Sun, 10 Jun 2007)
New Revision: 1297

Modified:
   trunk/foo_input_matroska/DbgOut.cpp
   trunk/foo_input_matroska/container_matroska_impl.cpp
   trunk/foo_input_matroska/matroska_parser.cpp
Log:
fix EOL style

Modified: trunk/foo_input_matroska/DbgOut.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/foo_input_matroska/DbgOut.cpp	2007-06-10 15:32:41 UTC (rev 1296=
)
+++ trunk/foo_input_matroska/DbgOut.cpp	2007-06-10 15:33:45 UTC (rev 1297=
)
@@ -1,73 +1,73 @@
-/**
-  *  Part of the foobar2000 Matroska plugin
-	*
-	*  Copyright (C) Jory Stone - 2003
-	*
-  *  This library is free software; you can redistribute it and/or
-  *  modify it under the terms of the GNU Library General Public
-  *  License as published by the Free Software Foundation; either
-  *  version 2 of the License, or (at your option) any later version.
-  *
-  *  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING=
 THE
-  *  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE.
-	*
-*/
-
-#include "DbgOut.h"
-
-#ifdef DEBUG_OUT_PUT
-#include <stdio.h>
-#include <wchar.h>
-#include <stdarg.h>
-
-static DWORD g_dwTimeOffset =3D timeGetTime();
-
-void WINAPI DbgStringOut(const TCHAR *pFormat,...)
-{    =09
-  TCHAR szInfo[2000];
-
-  // Format the variable length parameter list
-  va_list va;
-  va_start(va, pFormat);
-
-  lstrcpy(szInfo, TEXT("foo_input_matroska - "));
-  wsprintf(szInfo + lstrlen(szInfo),
-            TEXT("(tid %x) %8d : "),
-            GetCurrentThreadId(), timeGetTime() - g_dwTimeOffset);
-
-  _vstprintf(szInfo + lstrlen(szInfo), pFormat, va);
-  lstrcat(szInfo, TEXT("\r\n"));
-  OutputDebugString(szInfo);
-
-  va_end(va);
-};
-
-#ifdef UNICODE
-void WINAPI DbgLogInfo(const CHAR *pFormat,...)
-{
-    TCHAR szInfo[2000];
-
-    // Format the variable length parameter list
-    va_list va;
-    va_start(va, pFormat);
-
-    lstrcpy(szInfo, TEXT("foo_input_matroska - "));
-    wsprintf(szInfo + lstrlen(szInfo),
-             TEXT("(tid %x) %8d : "),
-             GetCurrentThreadId(), timeGetTime() - g_dwTimeOffset);
-
-    CHAR szInfoA[2000];
-    WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, sizeof(szInfoA)/=
sizeof(CHAR), 0, 0);
-
-    wvsprintfA(szInfoA + lstrlenA(szInfoA), pFormat, va);
-    lstrcatA(szInfoA, "\r\n");
-
-    WCHAR wszOutString[2000];
-    MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, sizeof(wsz=
OutString)/sizeof(WCHAR));
-    DbgOutString(wszOutString);
-
-    va_end(va);
-}
-#endif
-#endif
-
+/**
+  *  Part of the foobar2000 Matroska plugin
+	*
+	*  Copyright (C) Jory Stone - 2003
+	*
+  *  This library is free software; you can redistribute it and/or
+  *  modify it under the terms of the GNU Library General Public
+  *  License as published by the Free Software Foundation; either
+  *  version 2 of the License, or (at your option) any later version.
+  *
+  *  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING=
 THE
+  *  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE.
+	*
+*/
+
+#include "DbgOut.h"
+
+#ifdef DEBUG_OUT_PUT
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+
+static DWORD g_dwTimeOffset =3D timeGetTime();
+
+void WINAPI DbgStringOut(const TCHAR *pFormat,...)
+{    =09
+  TCHAR szInfo[2000];
+
+  // Format the variable length parameter list
+  va_list va;
+  va_start(va, pFormat);
+
+  lstrcpy(szInfo, TEXT("foo_input_matroska - "));
+  wsprintf(szInfo + lstrlen(szInfo),
+            TEXT("(tid %x) %8d : "),
+            GetCurrentThreadId(), timeGetTime() - g_dwTimeOffset);
+
+  _vstprintf(szInfo + lstrlen(szInfo), pFormat, va);
+  lstrcat(szInfo, TEXT("\r\n"));
+  OutputDebugString(szInfo);
+
+  va_end(va);
+};
+
+#ifdef UNICODE
+void WINAPI DbgLogInfo(const CHAR *pFormat,...)
+{
+    TCHAR szInfo[2000];
+
+    // Format the variable length parameter list
+    va_list va;
+    va_start(va, pFormat);
+
+    lstrcpy(szInfo, TEXT("foo_input_matroska - "));
+    wsprintf(szInfo + lstrlen(szInfo),
+             TEXT("(tid %x) %8d : "),
+             GetCurrentThreadId(), timeGetTime() - g_dwTimeOffset);
+
+    CHAR szInfoA[2000];
+    WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, sizeof(szInfoA)/=
sizeof(CHAR), 0, 0);
+
+    wvsprintfA(szInfoA + lstrlenA(szInfoA), pFormat, va);
+    lstrcatA(szInfoA, "\r\n");
+
+    WCHAR wszOutString[2000];
+    MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, sizeof(wsz=
OutString)/sizeof(WCHAR));
+    DbgOutString(wszOutString);
+
+    va_end(va);
+}
+#endif
+#endif
+


Property changes on: trunk/foo_input_matroska/DbgOut.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/foo_input_matroska/container_matroska_impl.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/foo_input_matroska/container_matroska_impl.cpp	2007-06-10 15:32=
:41 UTC (rev 1296)
+++ trunk/foo_input_matroska/container_matroska_impl.cpp	2007-06-10 15:33=
:45 UTC (rev 1297)
@@ -1,40 +1,40 @@
-#include "container_matroska_impl.h"
-
-/**
- * container_matroska
- */
-
-void container_matroska_impl::open(const char * p_path, bool p_info_only=
, foobar2000_io::abort_callback &p_abort) {
-    cleanup();
-    if (!is_our_path(p_path)) {
-        throw exception_io_unsupported_format();
-    }
-    m_path =3D p_path;
-    m_abort =3D &p_abort;
-    service_ptr_t<file> file_ptr;
-    try {
-        filesystem::g_open_read(file_ptr, m_path, *m_abort);
-        matroska_parser_ptr parser =3D matroska_parser_ptr(new MatroskaA=
udioParser(file_ptr, *m_abort));
-        parser->Parse(p_info_only);
-        for (t_size i =3D 0; i !=3D parser->GetAttachmentList().get_coun=
t(); ++i) {
-            MatroskaAttachment & item =3D parser->GetAttachmentList().ge=
t_item(i);
-            matroska::attachment attachment(this, *m_abort, item.FileNam=
e.GetUTF8().c_str(), item.MimeType.c_str(), item.Description.GetUTF8().c_=
str(),
-                static_cast<t_size>(item.SourceDataLength), static_cast<=
t_sfilesize>(item.SourceStartPos));
-            m_attachment_list.add_item(attachment);
-        }
-    } catch (...) {
-        throw exception_io_unsupported_format();
-    }
-}
-
-void container_matroska_impl::open_file(service_ptr_t<file> & p_out, con=
st filesystem::t_open_mode p_mode) const {
-    filesystem::g_open(p_out, m_path, p_mode, *m_abort);
-}
-
-void container_matroska_impl::get_display_path(pfc::string_base & p_out)=
 const {
-    p_out =3D m_path;
-}
-
-const matroska::attachment_list * container_matroska_impl::get_attachmen=
t_list() const {
-    return reinterpret_cast<const matroska::attachment_list *>(&m_attach=
ment_list);
-}
+#include "container_matroska_impl.h"
+
+/**
+ * container_matroska
+ */
+
+void container_matroska_impl::open(const char * p_path, bool p_info_only=
, foobar2000_io::abort_callback &p_abort) {
+    cleanup();
+    if (!is_our_path(p_path)) {
+        throw exception_io_unsupported_format();
+    }
+    m_path =3D p_path;
+    m_abort =3D &p_abort;
+    service_ptr_t<file> file_ptr;
+    try {
+        filesystem::g_open_read(file_ptr, m_path, *m_abort);
+        matroska_parser_ptr parser =3D matroska_parser_ptr(new MatroskaA=
udioParser(file_ptr, *m_abort));
+        parser->Parse(p_info_only);
+        for (t_size i =3D 0; i !=3D parser->GetAttachmentList().get_coun=
t(); ++i) {
+            MatroskaAttachment & item =3D parser->GetAttachmentList().ge=
t_item(i);
+            matroska::attachment attachment(this, *m_abort, item.FileNam=
e.GetUTF8().c_str(), item.MimeType.c_str(), item.Description.GetUTF8().c_=
str(),
+                static_cast<t_size>(item.SourceDataLength), static_cast<=
t_sfilesize>(item.SourceStartPos));
+            m_attachment_list.add_item(attachment);
+        }
+    } catch (...) {
+        throw exception_io_unsupported_format();
+    }
+}
+
+void container_matroska_impl::open_file(service_ptr_t<file> & p_out, con=
st filesystem::t_open_mode p_mode) const {
+    filesystem::g_open(p_out, m_path, p_mode, *m_abort);
+}
+
+void container_matroska_impl::get_display_path(pfc::string_base & p_out)=
 const {
+    p_out =3D m_path;
+}
+
+const matroska::attachment_list * container_matroska_impl::get_attachmen=
t_list() const {
+    return reinterpret_cast<const matroska::attachment_list *>(&m_attach=
ment_list);
+}


Property changes on: trunk/foo_input_matroska/container_matroska_impl.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/foo_input_matroska/matroska_parser.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/foo_input_matroska/matroska_parser.cpp	2007-06-10 15:32:41 UTC =
(rev 1296)
+++ trunk/foo_input_matroska/matroska_parser.cpp	2007-06-10 15:33:45 UTC =
(rev 1297)
@@ -1,2651 +1,2651 @@
-/*
- *  Part of the foobar2000 Matroska plugin
- *
- *  Copyright (C) Jory 'jcsston' Stone (jcsston at toughguy net) - 2003-=
2004
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING =
THE
- *  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PUR=
POSE.
- *
- */
-
-/*!
-    \file matroska_parser.cpp
-		\version $Id$
-    \brief An audio slated Matroska Reader+Parser
-		\author Jory Stone     <jcsston @ toughguy.net>
-*/
-
-#include "matroska_parser.h"
-
-#include <string>
-using std::string;
-
-using namespace LIBEBML_NAMESPACE;=09
-using namespace LIBMATROSKA_NAMESPACE;
-
-static const char * rg_fields[]=3D
-{
-	"REPLAYGAIN_GAIN",
-	"REPLAYGAIN_PEAK"
-};
-
-static const char * rg_track_fields[]=3D
-{
-	"REPLAYGAIN_TRACK_GAIN",
-	"REPLAYGAIN_TRACK_PEAK"
-};
-
-static const char * rg_album_fields[]=3D
-{
-	"REPLAYGAIN_ALBUM_GAIN",
-	"REPLAYGAIN_ALBUM_PEAK"
-};
-
-#define MATROSKA_TAG_IDX 0
-#define FOOBAR2K_TAG_IDX 1
-
-static const char * chapter_tag_mapping[][2] =3D
-{
-	{ "PART_NUMBER", "TRACKNUMBER" },
-	{ "DATE_RELEASED", "DATE" },
-    //{ "LEAD_PERFORMER", "PERFORMER" },
-    //{ "ACCOMPANIMENT", "BAND" },
-    //{ "LYRICIST", "WRITER" }
-};
-
-static const char * edition_tag_mapping[][2] =3D
-{
-	{ "TITLE", "ALBUM" },
-	{ "CATALOG_NUMBER", "CATALOG" },
-    { "TOTAL_PARTS", "TOTALTRACKS" },
-    //{ "PART_NUMBER", "DISCNUMBER" },
-    //{ "TOTAL_DISCS", "TOTALDISCS" }
-};
-
-static const char * hidden_edition_field[] =3D
-{
-	"___DUMMY___",
-};
-
-static const char * hidden_chapter_field[] =3D
-{
-	"CDAUDIO_TRACK_FLAGS",
-};
-
-bool starts_with(const string &s, const char *start) {
-  return strncmp(s.c_str(), start, strlen(start)) =3D=3D 0;
-};
-
-uint64 MatroskaAudioParser::SecondsToTimecode(double seconds)
-{
-	return (uint64)floor(seconds * 1000000000);
-};
-
-double MatroskaAudioParser::TimecodeToSeconds(uint64 code,unsigned sampl=
erate_hint)
-{
-	return ((double)(int64)code / 1000000000);
-};
-
-
-MatroskaAudioFrame::MatroskaAudioFrame()=20
-{
-	timecode =3D 0;
-	duration =3D 0;
-    add_id =3D 0;
-};
-
-MatroskaAttachment::MatroskaAttachment()
-{
-	FileName =3D L"";
-	MimeType =3D "";
-	Description =3D L"";
-	SourceFilename =3D L"";
-	SourceStartPos =3D 0;
-	SourceDataLength =3D 0;
-};
-
-void MatroskaAudioFrame::Reset()
-{
-	timecode =3D 0;
-	duration =3D 0;
-    add_id =3D 0;
-};
-
-MatroskaSimpleTag::MatroskaSimpleTag()
-{
-	name =3D L"";
-	value =3D L"";
-	language =3D "und";
-	defaultFlag =3D 1;
-	hidden =3D false;
-	removalPending =3D false;
-};
-
-MatroskaTagInfo::MatroskaTagInfo()
-{
-	targetTrackUID =3D 0;
-	targetEditionUID =3D 0;
-	targetChapterUID =3D 0;
-	targetAttachmentUID =3D 0;
-	targetTypeValue =3D 0;
-};
-
-void MatroskaTagInfo::SetTagValue(const char *name, const char *value, i=
nt index)
-{
-	for (size_t s =3D 0; s < tags.size(); s++)
-	{
-		MatroskaSimpleTag &currentSimpleTag =3D tags.at(s);
-		if (strcmpi(currentSimpleTag.name.GetUTF8().c_str(), name) =3D=3D 0)		=
=09
-		{
-			if(index =3D=3D 0)
-			{
-				currentSimpleTag.value.SetUTF8(value);
-				currentSimpleTag.removalPending =3D false;
-				return;
-			}
-			index--;
-		}
-	}
-
-	// If we are here then we didn't find this tag in the vector already
-	MatroskaSimpleTag newSimpleTag;
-	newSimpleTag.name.SetUTF8(name);
-	newSimpleTag.value.SetUTF8(value);=09
-	newSimpleTag.removalPending =3D false;
-	tags.push_back(newSimpleTag);
-};
-
-void MatroskaTagInfo::RemoveMarkedTags()
-{
-	for (int i =3D tags.size()-1; i >=3D 0; i--)
-	{
-		MatroskaSimpleTag &simpleTag =3D tags.at(i);
-		if(simpleTag.removalPending =3D=3D true)
-		{
-			tags.erase(tags.begin() + i);
-		}
-	}
-}
-
-void MatroskaTagInfo::MarkAllAsRemovalPending()
-{
-	for (int i =3D tags.size()-1; i >=3D 0; i--)
-	{
-		MatroskaSimpleTag &simpleTag =3D tags.at(i);
-		simpleTag.removalPending =3D true;
-	}
-}
-
-MatroskaChapterDisplayInfo::MatroskaChapterDisplayInfo()  {
-	string =3D L"";
-};
-
-MatroskaChapterInfo::MatroskaChapterInfo() {
-	chapterUID =3D 0;
-	timeStart =3D 0;
-	timeEnd =3D 0;
-}
-
-MatroskaEditionInfo::MatroskaEditionInfo() {
-	editionUID =3D 0;
-}
-
-MatroskaTrackInfo::MatroskaTrackInfo() {
-	trackNumber =3D 0;
-	trackUID =3D 0;	=09
-	duration =3D 0;
-
-	channels =3D 1;
-	samplesPerSec =3D 0;
-	samplesOutputPerSec =3D 0;
-	bitsPerSample =3D 0;
-	avgBytesPerSec =3D 0;
-	defaultDuration =3D 0;
-
-	name =3D L"";
-
-	codecPrivateReady =3D false;
-};
-
-MatroskaAudioParser::MatroskaAudioParser(service_ptr_t<file> input, abor=
t_callback & p_abort)=20
-	: m_IOCallback(input, p_abort),
-		m_InputStream(m_IOCallback)
-{
-	m_TimecodeScale =3D TIMECODE_SCALE;
-	m_FileDate =3D 0;
-	m_Duration =3D 0;
-	m_CurrentTimecode =3D 0;
-	//m_ElementLevel0 =3D NULL;
-	//UpperElementLevel =3D 0;
-	m_CurrentEdition =3D 0;
-	m_CurrentChapter =3D 0;
-	m_FileSize =3D input->get_size(p_abort);
-	m_TagPos =3D 0;
-	m_TagSize =3D 0;
-	m_TagScanRange =3D 1024 * 64;
-	m_CurrentTrackNo =3D 0;
-};
-
-MatroskaAudioParser::~MatroskaAudioParser() {
-	//if (m_ElementLevel0 !=3D NULL)
-	//	_DELETE(m_ElementLevel0);
-		//delete m_ElementLevel0;
-=09
-	while (!m_Queue.empty()) {
-		MatroskaAudioFrame *currentPacket =3D m_Queue.front();
-		//delete currentPacket;
-		_DELETE(currentPacket);
-		m_Queue.pop();
-	}
-};
-
-int MatroskaAudioParser::Parse(bool bInfoOnly, bool bBreakAtClusters)=20
-{
-	try {
-		int UpperElementLevel =3D 0;
-		bool bAllowDummy =3D false;
-		// Elements for different levels
-		ElementPtr ElementLevel1;
-		ElementPtr ElementLevel2;
-		ElementPtr ElementLevel3;
-		ElementPtr ElementLevel4;
-		ElementPtr ElementLevel5;
-		ElementPtr NullElement;
-
-		// Be sure we are at the beginning of the file
-		m_IOCallback.setFilePointer(0);
-		// Find the EbmlHead element. Must be the first one.
-		m_ElementLevel0 =3D ElementPtr(m_InputStream.FindNextID(EbmlHead::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
-		if (m_ElementLevel0 =3D=3D NullElement) {
-			return 1;
-		}
-		//We must have found the EBML head :)
-		m_ElementLevel0->SkipData(m_InputStream, m_ElementLevel0->Generic().Co=
ntext);
-		//delete m_ElementLevel0;
-		//_DELETE(m_ElementLevel0);
-
-		// Next element must be a segment
-		m_ElementLevel0 =3D ElementPtr(m_InputStream.FindNextID(KaxSegment::Cl=
assInfos, 0xFFFFFFFFFFFFFFFFL));
-		if (m_ElementLevel0 =3D=3D NullElement) {
-			//No segment/level 0 element found.
-			return 1;
-		}
-		if (!(EbmlId(*m_ElementLevel0) =3D=3D KaxSegment::ClassInfos.GlobalId)=
) {
-			//delete m_ElementLevel0;
-			//m_ElementLevel0 =3D NULL;
-			//_DELETE(m_ElementLevel0);
-			return 1;
-		}
-
-		UpperElementLevel =3D 0;
-		// We've got our segment, so let's find the tracks
-		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextElement(m_ElementLe=
vel0->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1)=
);
-		while (ElementLevel1 !=3D NullElement) {
-			if (UpperElementLevel > 0) {
-				break;
-			}
-			if (UpperElementLevel < 0) {
-				UpperElementLevel =3D 0;
-			}
-
-			if (EbmlId(*ElementLevel1) =3D=3D KaxSeekHead::ClassInfos.GlobalId) {
-				if (m_IOCallback.seekable()) {
-					Parse_MetaSeek(ElementLevel1, bInfoOnly);
-					if (m_TagPos =3D=3D 0) {
-						// Search for them at the end of the file
-						if (m_TagScanRange > 0)
-						{
-							m_IOCallback.setFilePointer(m_FileSize - m_TagScanRange);
-							uint64 init_pos =3D m_IOCallback.getFilePointer();
-							/*
-								BM Search
-							*/
-							binary buf[1024*64];
-							binary pat[3]; pat[0] =3D 0x54; pat[1] =3D 0xc3; pat[2] =3D 0x67;
-							uint64 s_pos =3D m_IOCallback.getFilePointer();
-							m_IOCallback.read(buf, m_TagScanRange);
-							MatroskaSearch search(buf, pat);
-							int pos =3D search.Match();
-							if (pos !=3D -1) {
-								do {
-									m_IOCallback.setFilePointer(s_pos+pos+3);
-									uint64 startPos =3D m_IOCallback.getFilePointer();
-									m_IOCallback.setFilePointer(-4, seek_current);
-									ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextID=
(KaxTags::ClassInfos, 0xFFFFFFFFFFFFFFFFL));
-									if ((levelUnknown !=3D NullElement)=20
-										&& (m_FileSize >=3D startPos + levelUnknown->GetSize())=20
-										&& (EbmlId(*levelUnknown) =3D=3D KaxTags::ClassInfos.GlobalId)=
)
-									{
-										Parse_Tags(static_cast<KaxTags *>(levelUnknown.get()));
-										break;
-									}
-									m_IOCallback.setFilePointer(s_pos);
-									pos =3D search.Match(pos+1);
-								} while (pos !=3D -1);
-								/*
-									~BM Search
-								*/
-							} else {
-								m_IOCallback.setFilePointer(init_pos);
-								binary Buffer[4];
-								while (m_IOCallback.read(Buffer, 3) >=3D 3)
-								{//0x18
-									if ((Buffer[0] =3D=3D 0x54) && (Buffer[1] =3D=3D 0xc3) && (Buff=
er[2] =3D=3D 0x67))
-									{
-										uint64 startPos =3D m_IOCallback.getFilePointer();
-
-										//seek back 3 bytes, so libmatroska can find the Tags element =
Ebml ID
-										m_IOCallback.setFilePointer(-4, seek_current);
-
-										ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextI=
D(KaxTags::ClassInfos, 0xFFFFFFFFFFFFFFFFL));
-										if ((levelUnknown !=3D NullElement)=20
-											&& (m_FileSize >=3D startPos + levelUnknown->GetSize())=20
-											&& (EbmlId(*levelUnknown) =3D=3D KaxTags::ClassInfos.GlobalId=
))
-										{
-											Parse_Tags(static_cast<KaxTags *>(levelUnknown.get()));
-											//_DELETE(levelUnknown);
-											break;
-										}
-										//_DELETE(levelUnknown);
-
-										//Restore the file pos
-										m_IOCallback.setFilePointer(startPos);
-									}
-									//seek back 2 bytes
-									m_IOCallback.setFilePointer(-2, seek_current);
-								}
-							}
-						} else {
-							//m_TagPos =3D m_FileSize;
-						}
-					}
-				}
-			}else if (EbmlId(*ElementLevel1) =3D=3D KaxInfo::ClassInfos.GlobalId)=
 {
-				// General info about this Matroska file
-				ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLe=
vel1->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, bAllowDu=
mmy));
-				while (ElementLevel2 !=3D NullElement) {
-					if (UpperElementLevel > 0) {
-						break;
-					}
-					if (UpperElementLevel < 0) {
-						UpperElementLevel =3D 0;
-					}
-
-					if (EbmlId(*ElementLevel2) =3D=3D KaxTimecodeScale::ClassInfos.Glob=
alId) {
-						KaxTimecodeScale &TimeScale =3D *static_cast<KaxTimecodeScale *>(E=
lementLevel2.get());
-						TimeScale.ReadData(m_InputStream.I_O());
-
-						//matroskaGlobalTrack->SetTimecodeScale(uint64(TimeScale));
-						m_TimecodeScale =3D uint64(TimeScale);
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxDuration::ClassInfos.Gl=
obalId) {
-						KaxDuration &duration =3D *static_cast<KaxDuration *>(ElementLevel=
2.get());
-						duration.ReadData(m_InputStream.I_O());
-
-						// it's in milliseconds? -- in nanoseconds.
-						m_Duration =3D double(duration) * m_TimecodeScale;
-
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxDateUTC::ClassInfos.Glo=
balId) {
-						KaxDateUTC & DateUTC =3D *static_cast<KaxDateUTC *>(ElementLevel2.=
get());
-						DateUTC.ReadData(m_InputStream.I_O());
-					=09
-						m_FileDate =3D DateUTC.GetEpochDate();
-
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxSegmentFilename::ClassI=
nfos.GlobalId) {
-						KaxSegmentFilename &tag_SegmentFilename =3D *static_cast<KaxSegmen=
tFilename *>(ElementLevel2.get());
-						tag_SegmentFilename.ReadData(m_InputStream.I_O());
-
-						m_SegmentFilename =3D *static_cast<EbmlUnicodeString *>(&tag_Segme=
ntFilename);
-
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxMuxingApp::ClassInfos.G=
lobalId)	{
-						KaxMuxingApp &tag_MuxingApp =3D *static_cast<KaxMuxingApp *>(Eleme=
ntLevel2.get());
-						tag_MuxingApp.ReadData(m_InputStream.I_O());
-
-						m_MuxingApp =3D *static_cast<EbmlUnicodeString *>(&tag_MuxingApp);
-
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxWritingApp::ClassInfos.=
GlobalId) {
-						KaxWritingApp &tag_WritingApp =3D *static_cast<KaxWritingApp *>(El=
ementLevel2.get());
-						tag_WritingApp.ReadData(m_InputStream.I_O());
-					=09
-						m_WritingApp =3D *static_cast<EbmlUnicodeString *>(&tag_WritingApp=
);
-
-					} else if (EbmlId(*ElementLevel2) =3D=3D KaxTitle::ClassInfos.Globa=
lId) {
-						KaxTitle &Title =3D *static_cast<KaxTitle*>(ElementLevel2.get());
-						Title.ReadData(m_InputStream.I_O());
-						m_FileTitle =3D UTFstring(Title).c_str();
-					}
-
-					if (UpperElementLevel > 0) {	// we're coming from ElementLevel3
-						UpperElementLevel--;
-						//delete ElementLevel2;
-						ElementLevel2 =3D ElementLevel3;
-						if (UpperElementLevel > 0)
-							break;
-					} else {
-						ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Co=
ntext);
-						//delete ElementLevel2;
-						//_DELETE(ElementLevel2);
-						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, bAllow=
Dummy));
-					}
-				}
-			}else if (EbmlId(*ElementLevel1) =3D=3D KaxChapters::ClassInfos.Globa=
lId) {
-				Parse_Chapters(static_cast<KaxChapters *>(ElementLevel1.get()));
-			}else if (EbmlId(*ElementLevel1) =3D=3D KaxTags::ClassInfos.GlobalId)=
 {
-				Parse_Tags(static_cast<KaxTags *>(ElementLevel1.get()));
-			} else if (EbmlId(*ElementLevel1) =3D=3D KaxTracks::ClassInfos.Global=
Id) {
-				// Yep, we've found our KaxTracks element. Now find all tracks
-				// contained in this segment.=20
-				KaxTracks *Tracks =3D static_cast<KaxTracks *>(ElementLevel1.get());
-				EbmlElement* tmpElement =3D ElementLevel2.get();
-				Tracks->Read(m_InputStream, KaxTracks::ClassInfos.Context, UpperElem=
entLevel, tmpElement, bAllowDummy);
-
-				unsigned int Index0;
-				for (Index0 =3D 0; Index0 < Tracks->ListSize(); Index0++) {
-					if ((*Tracks)[Index0]->Generic().GlobalId =3D=3D KaxTrackEntry::Cla=
ssInfos.GlobalId) {
-						KaxTrackEntry &TrackEntry =3D *static_cast<KaxTrackEntry *>((*Trac=
ks)[Index0]);
-						// Create a new MatroskaTrack
-						MatroskaTrackInfo newTrack;
-					=09
-						unsigned int Index1;
-						for (Index1 =3D 0; Index1 < TrackEntry.ListSize(); Index1++) {
-							if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrackNumber:=
:ClassInfos.GlobalId) {
-								KaxTrackNumber &TrackNumber =3D *static_cast<KaxTrackNumber*>(Tr=
ackEntry[Index1]);
-								newTrack.trackNumber =3D TrackNumber;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
UID::ClassInfos.GlobalId) {
-								KaxTrackUID &TrackUID =3D *static_cast<KaxTrackUID*>(TrackEntry[=
Index1]);
-								newTrack.trackUID =3D TrackUID;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Type::ClassInfos.GlobalId) {
-								KaxTrackType &TrackType =3D *static_cast<KaxTrackType*>(TrackEnt=
ry[Index1]);
-								if (uint8(TrackType) !=3D track_audio) {
-									newTrack.trackNumber =3D 0xFFFF;
-									break;
-								}
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
TimecodeScale::ClassInfos.GlobalId) {
-								KaxTrackTimecodeScale &TrackTimecodeScale =3D *static_cast<KaxTr=
ackTimecodeScale*>(TrackEntry[Index1]);
-								// TODO: Support Tracks with different timecode scales?
-								//newTrack->TrackTimecodeScale =3D TrackTimecodeScale;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
DefaultDuration::ClassInfos.GlobalId) {
-								KaxTrackDefaultDuration &TrackDefaultDuration =3D *static_cast<K=
axTrackDefaultDuration*>(TrackEntry[Index1]);
-								newTrack.defaultDuration =3D uint64(TrackDefaultDuration);
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxCodec=
ID::ClassInfos.GlobalId) {
-								KaxCodecID &CodecID =3D *static_cast<KaxCodecID*>(TrackEntry[Ind=
ex1]);
-								newTrack.codecID =3D std::string(CodecID);
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxCodec=
Private::ClassInfos.GlobalId) {
-								KaxCodecPrivate &CodecPrivate =3D *static_cast<KaxCodecPrivate*>=
(TrackEntry[Index1]);
-								newTrack.codecPrivate.resize(CodecPrivate.GetSize());							=09
-								memcpy(&newTrack.codecPrivate[0], CodecPrivate.GetBuffer(), Code=
cPrivate.GetSize());
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagDefault::ClassInfos.GlobalId) {
-								KaxTrackFlagDefault &TrackFlagDefault =3D *static_cast<KaxTrackF=
lagDefault*>(TrackEntry[Index1]);
-								//newTrack->FlagDefault =3D TrackFlagDefault;
-							/* Matroska2
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagEnabled::ClassInfos.GlobalId) {
-								KaxTrackFlagEnabled &TrackFlagEnabled =3D *static_cast<KaxTrackF=
lagEnabled*>(TrackEntry[Index1]);
-								//newTrack->FlagEnabled =3D TrackFlagEnabled;
-							*/
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagLacing::ClassInfos.GlobalId) {
-								KaxTrackFlagLacing &TrackFlagLacing =3D *static_cast<KaxTrackFla=
gLacing*>(TrackEntry[Index1]);
-								//newTrack->FlagLacing =3D TrackFlagLacing;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Language::ClassInfos.GlobalId) {
-								KaxTrackLanguage &TrackLanguage =3D *static_cast<KaxTrackLanguag=
e*>(TrackEntry[Index1]);
-								newTrack.language =3D std::string(TrackLanguage);
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
MaxCache::ClassInfos.GlobalId) {
-								KaxTrackMaxCache &TrackMaxCache =3D *static_cast<KaxTrackMaxCach=
e*>(TrackEntry[Index1]);
-								//newTrack->MaxCache =3D TrackMaxCache;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
MinCache::ClassInfos.GlobalId) {
-								KaxTrackMinCache &TrackMinCache =3D *static_cast<KaxTrackMinCach=
e*>(TrackEntry[Index1]);
-								//newTrack->MinCache =3D TrackMinCache;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Name::ClassInfos.GlobalId) {
-								KaxTrackName &TrackName =3D *static_cast<KaxTrackName*>(TrackEnt=
ry[Index1]);
-								newTrack.name =3D TrackName;
-
-							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Audio::ClassInfos.GlobalId) {
-								KaxTrackAudio &TrackAudio =3D *static_cast<KaxTrackAudio*>(Track=
Entry[Index1]);
-
-								unsigned int Index2;
-								for (Index2 =3D 0; Index2 < TrackAudio.ListSize(); Index2++) {
-									if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAudioBitDe=
pth::ClassInfos.GlobalId) {
-										KaxAudioBitDepth &AudioBitDepth =3D *static_cast<KaxAudioBitDe=
pth*>(TrackAudio[Index2]);
-										newTrack.bitsPerSample =3D AudioBitDepth;
-									/* Matroska2
-									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioPosition::ClassInfos.GlobalId) {
-										KaxAudioPosition &AudioPosition =3D *static_cast<KaxAudioPosit=
ion*>(TrackAudio[Index2]);
-
-										// TODO: Support multi-channel?
-										//newTrack->audio->ChannelPositionSize =3D AudioPosition.GetSi=
ze();
-										//newTrack->audio->ChannelPosition =3D new binary[AudioPositio=
n.GetSize()+1];
-										//memcpy(newTrack->audio->ChannelPosition, AudioPosition.GetBu=
ffer(), AudioPosition.GetSize());
-									*/
-									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioChannels::ClassInfos.GlobalId) {
-										KaxAudioChannels &AudioChannels =3D *static_cast<KaxAudioChann=
els*>(TrackAudio[Index2]);
-										newTrack.channels =3D AudioChannels;
-
-									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioOutputSamplingFreq::ClassInfos.GlobalId) {
-										KaxAudioOutputSamplingFreq &AudioOutputSamplingFreq =3D *stati=
c_cast<KaxAudioOutputSamplingFreq*>(TrackAudio[Index2]);
-										newTrack.samplesOutputPerSec =3D AudioOutputSamplingFreq;
-
-									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioSamplingFreq::ClassInfos.GlobalId) {
-										KaxAudioSamplingFreq &AudioSamplingFreq =3D *static_cast<KaxAu=
dioSamplingFreq*>(TrackAudio[Index2]);
-										newTrack.samplesPerSec =3D AudioSamplingFreq;
-									}
-								}
-							}
-						}
-						if (newTrack.trackNumber !=3D 0xFFFF)
-							m_Tracks.push_back(newTrack);
-					}
-				}
-			} else if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.Globa=
lId) {
-				if (bBreakAtClusters) {
-					m_IOCallback.setFilePointer(ElementLevel1->GetElementPosition());
-					//delete ElementLevel1;
-					//ElementLevel1 =3D NULL;
-					//_DELETE(ElementLevel1);
-					break;
-				}
-			} else if (EbmlId(*ElementLevel1) =3D=3D KaxAttachments::ClassInfos.G=
lobalId) {
-				// Yep, we've found our KaxAttachment element. Now find all attached=
 files
-				// contained in this segment.
-#if 1
-				ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLe=
vel1->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
-				while (ElementLevel2 !=3D NullElement) {
-					if (UpperElementLevel > 0) {
-						break;
-					}
-					if (UpperElementLevel < 0) {
-						UpperElementLevel =3D 0;
-					}
-					if (EbmlId(*ElementLevel2) =3D=3D KaxAttached::ClassInfos.GlobalId)=
 {
-						// We actually found a attached file entry :D
-						MatroskaAttachment newAttachment;
-
-						ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level2->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
-						while (ElementLevel3 !=3D NullElement) {
-							if (UpperElementLevel > 0) {
-								break;
-							}
-							if (UpperElementLevel < 0) {
-								UpperElementLevel =3D 0;
-							}
-
-							// Now evaluate the data belonging to this track
-							if (EbmlId(*ElementLevel3) =3D=3D KaxFileName::ClassInfos.GlobalI=
d) {
-								KaxFileName &attached_filename =3D *static_cast<KaxFileName *>(E=
lementLevel3.get());
-								attached_filename.ReadData(m_InputStream.I_O());
-								newAttachment.FileName =3D UTFstring(attached_filename);
-
-							} else if (EbmlId(*ElementLevel3) =3D=3D KaxMimeType::ClassInfos.=
GlobalId) {
-								KaxMimeType &attached_mime_type =3D *static_cast<KaxMimeType *>(=
ElementLevel3.get());
-								attached_mime_type.ReadData(m_InputStream.I_O());
-								newAttachment.MimeType =3D std::string(attached_mime_type);
-
-							} else if (EbmlId(*ElementLevel3) =3D=3D KaxFileDescription::Clas=
sInfos.GlobalId) {
-								KaxFileDescription &attached_description =3D *static_cast<KaxFil=
eDescription *>(ElementLevel3.get());
-								attached_description.ReadData(m_InputStream.I_O());
-								newAttachment.Description =3D UTFstring(attached_description);
-
-							} else if (EbmlId(*ElementLevel3) =3D=3D KaxFileData::ClassInfos.=
GlobalId) {
-								KaxFileData &attached_data =3D *static_cast<KaxFileData *>(Eleme=
ntLevel3.get());
-
-								//We don't what to read the data into memory because it could be=
 very large
-								//attached_data.ReadData(m_InputStream.I_O());
-
-								//Instead we store the Matroska filename, the start of the data =
and the length, so we can read it
-								//later at the users request. IMHO This will save a lot of memor=
y
-								newAttachment.SourceStartPos =3D attached_data.GetElementPositio=
n() + attached_data.HeadSize();
-								newAttachment.SourceDataLength =3D attached_data.GetSize();
-							}
-
-							if (UpperElementLevel > 0) {	// we're coming from ElementLevel4
-								UpperElementLevel--;
-								ElementLevel3 =3D ElementLevel4;
-								if (UpperElementLevel > 0)
-									break;
-							} else {
-								ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().=
Context);
-								ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Eleme=
ntLevel2->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
-							}				=09
-						} // while (ElementLevel3 !=3D NULL)
-						//m_AttachmentList.push_back(newAttachment);
-                        m_AttachmentList.add_item(newAttachment);
-					}
-
-					if (UpperElementLevel > 0) {	// we're coming from ElementLevel3
-						UpperElementLevel--;
-						ElementLevel2 =3D ElementLevel3;
-						if (UpperElementLevel > 0)
-							break;
-					} else {
-						ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Co=
ntext);
-						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
-					}
-				} // while (ElementLevel2 !=3D NULL)
-#endif
-			}
-		=09
-			if (UpperElementLevel > 0) {		// we're coming from ElementLevel2
-				UpperElementLevel--;
-				//delete ElementLevel1;
-				//_DELETE(ElementLevel1);
-				ElementLevel1 =3D ElementLevel2;
-				if (UpperElementLevel > 0)
-					break;
-			} else {
-				ElementLevel1->SkipData(m_InputStream, ElementLevel1->Generic().Cont=
ext);
-				//delete ElementLevel1;
-				//ElementLevel1 =3D NULL;
-				//_DELETE(ElementLevel1);
-
-				ElementLevel1 =3D ElementPtr(m_InputStream.FindNextElement(m_Element=
Level0->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, =
1));
-			}
-		} // while (ElementLevel1 !=3D NULL)
-		//_DELETE(ElementLevel3);
-		//_DELETE(ElementLevel2);
-		//_DELETE(ElementLevel1);
-	} catch (std::exception &) {
-		return 1;
-
-	} catch (...) {
-		return 1;
-	}
-
-	CountClusters();
-	return 0;
-};
-
-//int MatroskaAudioParser::WriteTags(const file_info & info)
-int MatroskaAudioParser::WriteTags()
-{
-	KaxTags & MyKaxTags =3D GetChild<KaxTags>(*static_cast<EbmlMaster *>(m_=
ElementLevel0.get()));
-
-	// On to writing :)
-	if (m_TagPos =3D=3D 0) {
-		// Ok, we need to append the tags onto the end of the file, no existin=
g tag element
-		m_TagPos =3D m_FileSize;
-	} else {
-	=09
-	}=09
-
-	//Start going through the list and adding tags
-	KaxTag *MyKaxTag_last =3D NULL;
-	for(size_t current_tag_track =3D 0; current_tag_track < m_Tags.size(); =
current_tag_track++) {
-		KaxTag *MyKaxTag =3D NULL;
-		if (MyKaxTag_last !=3D NULL)
-		{
-			MyKaxTag =3D &GetNextChild<KaxTag>(MyKaxTags, *MyKaxTag_last);
-			MyKaxTag_last =3D MyKaxTag;
-		}else {
-			MyKaxTag =3D &GetChild<KaxTag>(MyKaxTags);
-			MyKaxTag_last =3D MyKaxTag;
-		}
-		MatroskaTagInfo &currentTag =3D m_Tags.at(current_tag_track);
-		//The Targets group
-		KaxTagTargets & MyKaxTagTargets =3D GetChild<KaxTagTargets>(*MyKaxTag)=
;
-		if (currentTag.targetTrackUID !=3D 0) {
-			KaxTagTrackUID & MyKaxTagTrackUID =3D GetChild<KaxTagTrackUID>(MyKaxT=
agTargets);
-			*static_cast<EbmlUInteger *>(&MyKaxTagTrackUID) =3D currentTag.target=
TrackUID;
-		}
-		if (currentTag.targetEditionUID !=3D 0) {
-			KaxTagEditionUID & MyKaxTagEditionUID =3D GetChild<KaxTagEditionUID>(=
MyKaxTagTargets);
-			*static_cast<EbmlUInteger *>(&MyKaxTagEditionUID) =3D currentTag.targ=
etEditionUID;
-		}
-		if (currentTag.targetChapterUID !=3D 0) {
-			KaxTagChapterUID & MyKaxTagChapterUID =3D GetChild<KaxTagChapterUID>(=
MyKaxTagTargets);
-			*static_cast<EbmlUInteger *>(&MyKaxTagChapterUID) =3D currentTag.targ=
etChapterUID;
-		}
-		if (currentTag.targetAttachmentUID !=3D 0) {
-			KaxTagAttachmentUID & MyKaxTagAttachmentUID =3D GetChild<KaxTagAttach=
mentUID>(MyKaxTagTargets);
-			*static_cast<EbmlUInteger *>(&MyKaxTagAttachmentUID) =3D currentTag.t=
argetAttachmentUID;
-		}
-		if(currentTag.targetTypeValue !=3D 0) {
-			KaxTagTargetTypeValue& MyKaxTagTargetTypeValue =3D GetChild<KaxTagTar=
getTypeValue>(MyKaxTagTargets);
-			*static_cast<EbmlUInteger *>(&MyKaxTagTargetTypeValue) =3D currentTag=
.targetTypeValue;
-			if(!currentTag.targetType.empty())
-			{
-				KaxTagTargetType& MyKaxTagTargetType =3D GetChild<KaxTagTargetType>(=
MyKaxTagTargets);
-				*static_cast<EbmlString *>(&MyKaxTagTargetType) =3D currentTag.targe=
tType;			=09
-			}
-		}
-	=09
-		// Add the millions of simple tags we can have ;)
-		KaxTagSimple *MySimpleTag_last =3D NULL;
-		for(size_t st =3D 0; st < currentTag.tags.size(); st++) {
-			KaxTagSimple *MySimpleTag =3D NULL;
-			if (MySimpleTag_last !=3D NULL)
-			{
-				MySimpleTag =3D &GetNextChild<KaxTagSimple>(*MyKaxTag, *MySimpleTag_=
last);
-				MySimpleTag_last =3D MySimpleTag;
-			}else {
-				MySimpleTag =3D &GetChild<KaxTagSimple>(*MyKaxTag);
-				MySimpleTag_last =3D MySimpleTag;
-			}
-			MatroskaSimpleTag &currentSimpleTag =3D currentTag.tags.at(st);
-
-			KaxTagName & MyKaxTagName =3D GetChild<KaxTagName>(*MySimpleTag);
-			*static_cast<EbmlUnicodeString *>(&MyKaxTagName) =3D currentSimpleTag=
.name;
-
-			KaxTagString & MyKaxTagString =3D GetChild<KaxTagString>(*MySimpleTag=
);
-			*static_cast<EbmlUnicodeString *>(&MyKaxTagString) =3D currentSimpleT=
ag.value;
-		=09
-			KaxTagLangue& MyKaxTagLangue =3D GetChild<KaxTagLangue>(*MySimpleTag)=
;
-			*static_cast<EbmlString *>(&MyKaxTagLangue) =3D currentSimpleTag.lang=
uage;
-
-			KaxTagDefault& MyKaxTagDefault =3D GetChild<KaxTagDefault>(*MySimpleT=
ag);
-			*static_cast<EbmlUInteger *>(&MyKaxTagDefault) =3D currentSimpleTag.d=
efaultFlag;		=09
-		}
-
-		m_IOCallback.setFilePointer(m_TagPos);
-		// Now we write the tags to the file
-		EbmlVoid & Dummy =3D GetChild<EbmlVoid>(*static_cast<EbmlMaster *>(m_E=
lementLevel0.get()));
-		uint64 size_of_tags =3D m_TagSize;
-		MyKaxTags.UpdateSize(true);
-		if (size_of_tags < MyKaxTags.GetSize())
-			size_of_tags =3D MyKaxTags.GetSize();
-
-		Dummy.SetSize(size_of_tags+8); // Size of the previous tag element
-		uint64 pos =3D m_IOCallback.getFilePointer();
-		if (pos =3D=3D 0)
-			//We don't want to overwrite the EBML header :P
-			return 2;
-		Dummy.Render(m_IOCallback);
-		m_IOCallback.setFilePointer(Dummy.GetElementPosition());
-		pos =3D m_IOCallback.getFilePointer();
-		if (pos =3D=3D 0)
-			//We don't want to overwrite the EBML header :P
-			return 2;
-
-		MyKaxTags.Render(m_IOCallback);
-	=09
-		//l0->UpdateSize(false, true);
-		std::auto_ptr<KaxSegment> new_segment(new KaxSegment);
-		KaxSegment * segment =3D (KaxSegment *)m_ElementLevel0.get();
-
-		m_IOCallback.setFilePointer(segment->GetElementPosition());
-		new_segment->WriteHead(m_IOCallback, segment->HeadSize() - 4);
-		m_IOCallback.setFilePointer(0, seek_end);
-		int ret =3D new_segment->ForceSize(m_IOCallback.getFilePointer() - seg=
ment->HeadSize() - segment->GetElementPosition());
-		if (!ret) {=20
-			segment->OverwriteHead(m_IOCallback);
-		      /*("Wrote the element at the end of the file but could "
-                      "not update the segment size. Therefore the elemen=
t "
-                      "will not be visible. Aborting the process. The fi=
le "
-                      "has been changed!")*/
-			m_IOCallback.setFilePointer(segment->HeadSize() - segment->GetElement=
Position());
-			m_IOCallback.truncate();
-
-			return 1;
-		} else {
-			new_segment->OverwriteHead(m_IOCallback);
-
-		}
-
-	}
-	return 0;
-};
-
-static const char* foobar2k_to_matroska_edition_tag(const char * name)
-{
-	if (!stricmp_utf8(name, "ALBUM"))
-		return "TITLE";
-	else if (!stricmp_utf8(name, "SUBALBUM"))
-		return "SUBTITLE";
-	else if (starts_with(name, "ALBUM ")) {
-		static char newname[255];
-		ZeroMemory(newname,255);
-		strncpy(newname,name+6,254);
-		name =3D newname;
-	}
-	for (int i =3D 0; i < tabsize(edition_tag_mapping); i++)
-		if (!stricmp_utf8(name, edition_tag_mapping[i][FOOBAR2K_TAG_IDX]))
-			return edition_tag_mapping[i][MATROSKA_TAG_IDX];
-	return name;
-}
-
-static const char* foobar2k_to_matroska_chapter_tag(const char * name)
-{
-	for (int i =3D 0; i < tabsize(chapter_tag_mapping); i++)
-		if (!stricmp_utf8(name, chapter_tag_mapping[i][FOOBAR2K_TAG_IDX]))
-			return chapter_tag_mapping[i][MATROSKA_TAG_IDX];
-		return name;
-}
-
-int meta_get_num(const file_info &info, const char* name, int idx)
-{
-	assert(pfc::is_valid_utf8(name));
-	int n, m =3D min(info.meta_get_count(), idx);
-	int rv =3D 0;
-	for(n=3D0; n<m; n++)
-	{
-		if (!stricmp_utf8(name, info.meta_enum_name(n)))
-			rv++;
-	}
-	return rv;
-}
-
-bool isEditionTag(const char * name) {
-	if (starts_with(name, "ALBUM") ||
-		starts_with(name, "SUBALBUM") ||
-		starts_with(name, "DISCID") ||
-		starts_with(name, "CATALOG"))
-	{
-		return true;
-	} else {
-		return false;
-	}
-}
-
-void MatroskaAudioParser::SetTags(const file_info &info)
-{
-	int i, idx;
-	const char *name, *value;=09
-
-	if (m_Chapters.size() =3D=3D 0)
-	{	=09
-		// No chapters, works on track
-		MatroskaTagInfo *trackTag;
-		trackTag =3D FindTagWithTrackUID(m_Tracks.at(m_CurrentTrackNo).trackUI=
D);
-		if (trackTag =3D=3D NULL) {
-			// The tag doesn't exist yet
-			MatroskaTagInfo tempTag;
-			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;
-			m_Tags.push_back(tempTag);
-			trackTag =3D &m_Tags.at(m_Tags.size()-1);
-		}
-		//if(trackTag->targetTypeValue =3D=3D 0)
-		//	trackTag->targetTypeValue =3D 50;
-        trackTag->targetTypeValue =3D 30;
-		trackTag->MarkAllAsRemovalPending();
-		int metaDataCount =3D info.meta_get_count();
-		for (i =3D 0; i < metaDataCount; i++)
-		{
-			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
-				name =3D info.meta_enum_name(i);
-				value =3D info.meta_enum_value(i, j);
-				//idx =3D meta_get_num(info, name, i);
-				idx =3D j;
-				name =3D foobar2k_to_matroska_chapter_tag(name);
-				if ((name !=3D NULL) && (value !=3D NULL)) {
-					trackTag->SetTagValue(name, value, idx);
-				}
-			}
-		}
-		// Add the replay_gain tags
-		replaygain_info rg =3D info.get_replaygain();
-		if (rg.is_track_gain_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_gain, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			trackTag->SetTagValue("REPLAYGAIN_GAIN", value);
-		if (rg.is_track_peak_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_peak, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			trackTag->SetTagValue("REPLAYGAIN_PEAK", value);
-		trackTag->RemoveMarkedTags();
-	}
-=09
-	// Set global track tags as album tags
-	if ((m_Chapters.size() > 0) && (m_CurrentChapter !=3D NULL))
-	{
-		MatroskaTagInfo *trackTag;
-		trackTag =3D FindTagWithTrackUID(m_Tracks.at(m_CurrentTrackNo).trackUI=
D);
-		if (trackTag =3D=3D NULL)
-		{
-			MatroskaTagInfo tempTag;
-			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;		=09
-			m_Tags.push_back(tempTag);
-			trackTag =3D &m_Tags.at(m_Tags.size()-1);
-		}
-		if(trackTag->targetTypeValue =3D=3D 0)
-			trackTag->targetTypeValue =3D 50;
-		trackTag->MarkAllAsRemovalPending();
-		int metaDataCount =3D info.meta_get_count();
-		for (i =3D 0; i < metaDataCount; i++)
-		{
-			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
-				name =3D info.meta_enum_name(i);
-				value =3D info.meta_enum_value(i, j);
-				//idx =3D meta_get_num(info, name, i);
-				idx =3D j;
-				if (isEditionTag(name))
-				{
-					name =3D foobar2k_to_matroska_edition_tag(name);
-				} else {
-					name =3D NULL;
-				}
-				if ((name !=3D NULL) && (value !=3D NULL)) {
-					trackTag->SetTagValue(name, value, idx);
-				}
-			}
-		}
-		replaygain_info rg =3D info.get_replaygain();
-		if (rg.is_album_gain_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_album_gain, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			trackTag->SetTagValue("REPLAYGAIN_GAIN", value);
-		if (rg.is_album_peak_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_album_peak, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			trackTag->SetTagValue("REPLAYGAIN_PEAK", value);
-		trackTag->RemoveMarkedTags();
-	}
-
-
-	//If there's not only a track, set all the chapter tags
-	if ((m_Chapters.size() > 0) && (m_CurrentChapter !=3D NULL))
-	{
-		// Ok we add the tags to tag with chapter+track UID's
-		MatroskaTagInfo *chapterTag;	=09
-		chapterTag =3D FindTagWithChapterUID(m_CurrentChapter->chapterUID,
-			m_Tracks.at(m_CurrentTrackNo).trackUID);
-		if (chapterTag =3D=3D NULL)
-		{
-			MatroskaTagInfo tempTag;
-			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;
-			tempTag.targetChapterUID =3D m_CurrentChapter->chapterUID;
-			m_Tags.push_back(tempTag);
-			chapterTag =3D &m_Tags.at(m_Tags.size()-1);
-		}
-		if(chapterTag->targetTypeValue =3D=3D 0)
-			chapterTag->targetTypeValue =3D 30;
-		chapterTag->MarkAllAsRemovalPending();
-		int metaDataCount =3D info.meta_get_count();
-		for (i =3D 0; i < metaDataCount; i++)
-		{
-			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
-				name =3D info.meta_enum_name(i);
-				value =3D info.meta_enum_value(i, j);
-				//idx =3D meta_get_num(info, name, i);
-				idx =3D j;
-				if (isEditionTag(name))
-				{
-					name =3D NULL;
-				} else {
-					name =3D foobar2k_to_matroska_chapter_tag(name);
-				}
-				if ((name !=3D NULL) && (value !=3D NULL)) {
-					chapterTag->SetTagValue(name, value, idx);
-				}
-			}
-		}
-		replaygain_info rg =3D info.get_replaygain();
-		if (rg.is_track_gain_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_gain, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			chapterTag->SetTagValue("REPLAYGAIN_GAIN", value);
-		if (rg.is_track_peak_present()) {
-			char tmp[rg.text_buffer_size];
-			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_peak, 7);
-			value =3D (const char*)tmp;
-		} else {
-			value =3D NULL;
-		}
-		if (value)
-			chapterTag->SetTagValue("REPLAYGAIN_PEAK", value);
-		chapterTag->RemoveMarkedTags();
-	}
-};
-
-MatroskaTagInfo *MatroskaAudioParser::FindTagWithTrackUID(uint64 trackUI=
D)=20
-{
-	MatroskaTagInfo *foundTag =3D NULL;
-
-	for (size_t t =3D 0; t < m_Tags.size(); t++)
-	{
-		MatroskaTagInfo& currentTag =3D m_Tags.at(t);
-		if (currentTag.targetTrackUID =3D=3D trackUID &&
-			currentTag.targetEditionUID =3D=3D 0 &&
-			currentTag.targetChapterUID =3D=3D 0 &&
-			currentTag.targetAttachmentUID =3D=3D 0)
-		{
-			foundTag =3D &currentTag;
-			break;
-		}
-	}
-
-	return foundTag;
-};
-
-MatroskaTagInfo *MatroskaAudioParser::FindTagWithEditionUID(uint64 editi=
onUID, uint64 trackUID)
-{
-	MatroskaTagInfo *foundTag =3D NULL;
-
-	for (size_t t =3D 0; t < m_Tags.size(); t++)
-	{
-		MatroskaTagInfo &currentTag =3D m_Tags.at(t);
-		if (currentTag.targetEditionUID =3D=3D editionUID &&
-			(trackUID =3D=3D 0 || (currentTag.targetTrackUID =3D=3D trackUID)))
-		{
-			foundTag =3D &currentTag;
-			break;
-		}
-	}
-
-	return foundTag;
-};
-
-MatroskaTagInfo *MatroskaAudioParser::FindTagWithChapterUID(uint64 chapt=
erUID, uint64 trackUID)
-{
-	MatroskaTagInfo *foundTag =3D NULL;
-
-	for (size_t t =3D 0; t < m_Tags.size(); t++)
-	{
-		MatroskaTagInfo &currentTag =3D m_Tags.at(t);
-		if (currentTag.targetChapterUID =3D=3D chapterUID &&
-			(trackUID =3D=3D 0 || (currentTag.targetTrackUID =3D=3D trackUID)))
-		{
-			foundTag =3D &currentTag;
-			break;
-		}
-	}
-
-	return foundTag;
-};
-
-double MatroskaAudioParser::GetDuration() {=20
-	if (m_CurrentChapter !=3D NULL) {
-		return TimecodeToSeconds(m_CurrentChapter->timeEnd - m_CurrentChapter-=
>timeStart);
-	};
-	return m_Duration / 1000000000.0;
-	if (m_Tracks.size() !=3D 0) {
-		return m_Tracks.at(m_CurrentTrackNo).defaultDuration * (int64)m_Timeco=
deScale;
-	}
-};
-
-int32 MatroskaAudioParser::GetFirstAudioTrack()
-{
-	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
-	{
-		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
-		if (!strncmp(currentTrack.codecID.c_str(),"A_",2)) return t;
-	}
-	return -1;
-}
-
-uint32 MatroskaAudioParser::GetAudioTrackCount()
-{
-	uint32 count =3D 0;
-	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
-	{
-		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
-		if (!strncmp(currentTrack.codecID.c_str(),"A_",2))
-			count++;
-	}
-	return count;
-}
-
-uint32 MatroskaAudioParser::GetAudioTrackIndex(uint32 index)
-{
-	uint32 idx =3D 0;
-	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
-	{
-		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
-		if (!strncmp(currentTrack.codecID.c_str(),"A_",2))
-		{
-			if(t =3D=3D index)
-				break;
-			idx++;
-		}
-	}
-	return idx;
-}
-
-static bool is_rg_field(const char * name)
-{
-	int m;
-	for (m =3D 0; m < tabsize(rg_fields); m++)
-	{
-		if (!stricmp_utf8(name,rg_fields[m])) return true;
-	}
-	return false;
-}
-
-static bool is_hidden_edition_field(const char * name)
-{
-	for (int i =3D 0; i < tabsize(hidden_edition_field); i++)
-		if (!stricmp_utf8(name, hidden_edition_field[i]))
-			return true;
-	return false;
-}
-
-static bool is_hidden_chapter_field(const char * name)
-{
-	for (int i =3D 0; i < tabsize(hidden_chapter_field); i++)
-		if (!stricmp_utf8(name, hidden_chapter_field[i]))
-			return true;
-	return false;
-}
-
-static const char* matroska_to_foobar2k_edition_tag(const char * name)
-{
-	for (int i =3D 0; i < tabsize(edition_tag_mapping); i++)
-		if (!stricmp_utf8(name, edition_tag_mapping[i][MATROSKA_TAG_IDX]))
-			return edition_tag_mapping[i][FOOBAR2K_TAG_IDX];
-	return name;
-}
-
-static const char* matroska_to_foobar2k_chapter_tag(const char * name)
-{
-	for (int i =3D 0; i < tabsize(chapter_tag_mapping); i++)
-		if (!stricmp_utf8(name, chapter_tag_mapping[i][MATROSKA_TAG_IDX]))
-			return chapter_tag_mapping[i][FOOBAR2K_TAG_IDX];
-	return name;
-}
-
-static void convert_matroska_to_foobar2k_tag(pfc::string_base & p_out, c=
onst char * p_name)
-{
-    pfc::string8 name(p_name);
-    //name.replace_char('_', ' ');
-    p_out =3D name;
-}
-
-static bool IsTagNamed(const MatroskaSimpleTag &currentSimpleTag, const =
char * name)
-{
-	return !stricmp_utf8(currentSimpleTag.name.GetUTF8().c_str(), name);
-}
-
-static bool IsTagValued(const MatroskaSimpleTag &currentSimpleTag, const=
 char * value)
-{
-	return !strcmp(currentSimpleTag.value.GetUTF8().c_str(), value);
-}
-
-static bool AreTagsNameEqual(const MatroskaSimpleTag &tag1, const Matros=
kaSimpleTag &tag2)
-{
-	return !stricmp_utf8(tag1.name.GetUTF8().c_str(), tag2.name.GetUTF8().c=
_str());
-}
-
-static bool AreTagsValueEqual(const MatroskaSimpleTag &tag1, const Matro=
skaSimpleTag &tag2)
-{
-	return !strcmp(tag1.value.GetUTF8().c_str(), tag2.value.GetUTF8().c_str=
());
-}
-
-static bool AreTagsEqual(const MatroskaSimpleTag &tag1, const MatroskaSi=
mpleTag &tag2)
-{
-	return AreTagsNameEqual(tag1,tag2) && AreTagsValueEqual(tag1,tag2);
-}
-
-const MatroskaSimpleTag* GetTagWithName(MatroskaTagInfo *SimpleTags, con=
st char * name)
-{
-	if(SimpleTags =3D=3D NULL)
-		return NULL;
-
-	for (size_t s =3D 0; s < SimpleTags->tags.size(); s++)
-	{
-		const MatroskaSimpleTag &currentSimpleTag =3D SimpleTags->tags.at(s);	=
=09
-		if(IsTagNamed(currentSimpleTag, name))
-			return &currentSimpleTag;
-	}
-	return NULL;
-}
-
-bool TagExistsAtEditionLevel(MatroskaTagInfo *TrackTags, const char * na=
me)
-{
-	if(TrackTags =3D=3D NULL)
-		return false;
-
-	for (size_t s =3D 0; s < TrackTags->tags.size(); s++)
-	{
-		const MatroskaSimpleTag &currentSimpleTag =3D TrackTags->tags.at(s);	=09
-		if(IsTagNamed(currentSimpleTag,name))
-			return true;
-	}
-	return false;
-}
-
-bool TagExistsAtChapterLevel(MatroskaTagInfo *ChapterTags, const char * =
name)
-{
-	if(ChapterTags =3D=3D NULL)
-		return false;
-
-	for (size_t s =3D 0; s < ChapterTags->tags.size(); s++)
-	{
-		const MatroskaSimpleTag &currentSimpleTag =3D ChapterTags->tags.at(s);=
	=09
-		if(IsTagNamed(currentSimpleTag,name))
-			return true;
-	}
-	return false;
-}
-
-bool MatroskaAudioParser::AreTagsIdenticalAtAllLevels(const char * name)
-{
-	const MatroskaSimpleTag* ReferenceTag =3D NULL;
-	bool AtLeastOneChapter =3D false;
-
-	for (size_t i =3D 0; i < m_Tags.size(); i++)
-	{
-		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
-		if(ReferenceTag =3D=3D NULL)
-		{
-			AtLeastOneChapter =3D true;
-			ReferenceTag =3D GetTagWithName(&currentTags, name);
-		} else {
-			const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags, =
name);
-			if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
-				return false;			=09
-		}
-	}
-	return AtLeastOneChapter;
-}
-
-bool MatroskaAudioParser::AreTagsIdenticalAtEditionLevel(const char * na=
me)
-{
-	const MatroskaSimpleTag* ReferenceTag =3D NULL;
-	bool AtLeastOneChapter =3D false;
-
-	for (size_t i =3D 0; i < m_Tags.size(); i++)
-	{
-		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
-		if (currentTags.targetChapterUID =3D=3D 0)
-		{
-			// Chapter tags
-			if(ReferenceTag =3D=3D NULL)
-			{
-				AtLeastOneChapter =3D true;
-				ReferenceTag =3D GetTagWithName(&currentTags, name);
-			} else {
-				const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags,=
 name);
-				if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
-					return false;			=09
-			}
-		}
-	}
-	return AtLeastOneChapter;
-}
-
-bool MatroskaAudioParser::AreTagsIdenticalAtChapterLevel(const char * na=
me)
-{
-	const MatroskaSimpleTag* ReferenceTag =3D NULL;
-	bool AtLeastOneChapter =3D false;
-
-	for (size_t i =3D 0; i < m_Tags.size(); i++)
-	{
-		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
-		if (currentTags.targetChapterUID !=3D 0)
-		{
-			// Chapter tags
-			if(ReferenceTag =3D=3D NULL)
-			{
-				AtLeastOneChapter =3D true;
-				ReferenceTag =3D GetTagWithName(&currentTags, name);
-			} else {
-				const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags,=
 name);
-				if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
-					return false;			=09
-			}
-		}
-	}
-	return AtLeastOneChapter;
-}
-
-void MatroskaAudioParser::SetAlbumTags(file_info & info,
-									   MatroskaTagInfo* AlbumTags,
-									   MatroskaTagInfo* TrackTags)
-{
-	if (AlbumTags =3D=3D NULL)
-		return;
-
-	for (size_t s =3D 0; s < AlbumTags->tags.size(); s++)
-	{
-		MatroskaSimpleTag &simpleTag =3D AlbumTags->tags.at(s);
-	=09
-		if (is_rg_field(simpleTag.name.GetUTF8().c_str()))
-		{
-			if(IsTagNamed(simpleTag, "REPLAYGAIN_GAIN"))
-			{
-				info.info_set_replaygain("replaygain_album_gain", simpleTag.value.Ge=
tUTF8().c_str());
-				if (TrackTags =3D=3D NULL) info.info_set_replaygain("replaygain_trac=
k_gain", simpleTag.value.GetUTF8().c_str());
-			} else if(IsTagNamed(simpleTag, "REPLAYGAIN_PEAK")) {
-				info.info_set_replaygain("replaygain_album_peak", simpleTag.value.Ge=
tUTF8().c_str());
-				if (TrackTags =3D=3D NULL) info.info_set_replaygain("replaygain_trac=
k_peak", simpleTag.value.GetUTF8().c_str());
-			}
-		}
-		else if (is_hidden_edition_field(simpleTag.name.GetUTF8().c_str()))
-		{
-			// Ignored tag, will be rewrited later
-			simpleTag.hidden =3D true;
-		}
-		else if(IsTagNamed(simpleTag,"TITLE"))
-		{
-			// Special case for Edition/TITLE
-			if(TagExistsAtChapterLevel(TrackTags, "ALBUM"))
-			{
-				info.meta_add("ALBUM TITLE", simpleTag.value.GetUTF8().c_str());
-			} else {
-				info.meta_add("ALBUM", simpleTag.value.GetUTF8().c_str());
-			}
-		}
-        /*
-		else if(IsTagNamed(simpleTag,"SUBTITLE"))
-		{
-			// Special case for Edition/SUBTITLE
-			if(TagExistsAtChapterLevel(TrackTags, "SUBALBUM"))
-			{
-				info.meta_add("ALBUM SUBTITLE", simpleTag.value.GetUTF8().c_str());
-			} else {
-				info.meta_add("SUBALBUM", simpleTag.value.GetUTF8().c_str());
-			}
-		}
-        */
-        else if (IsTagNamed(simpleTag, "DISCID") ||
-		         IsTagNamed(simpleTag, "CATALOG_NUMBER") ||
-                 IsTagNamed(simpleTag, "TOTAL_PARTS") ||
-                 IsTagNamed(simpleTag, "PART_NUMBER") ||
-                 IsTagNamed(simpleTag, "TOTAL_DISCS"))
-		{
-			info.meta_add(matroska_to_foobar2k_edition_tag(simpleTag.name.GetUTF8=
().c_str()), simpleTag.value.GetUTF8().c_str());
-		}
-        /*else if (IsTagNamed(simpleTag,"COMMENTS"))
-		{
-			info.meta_add("ALBUM COMMENT", simpleTag.value.GetUTF8().c_str());
-		}*/
-		else if((!AreTagsIdenticalAtAllLevels(simpleTag.name.GetUTF8().c_str()=
))
-			|| (!TagExistsAtChapterLevel(TrackTags, simpleTag.name.GetUTF8().c_st=
r())))
-		{
-			// Prefix tag with "ALBUM "
-			char newTagName[255] =3D "ALBUM ";
-			strncat(newTagName, matroska_to_foobar2k_edition_tag(simpleTag.name.G=
etUTF8().c_str()),255);
-            pfc::string8 new_tagname;
-            convert_matroska_to_foobar2k_tag(new_tagname, newTagName);
-			info.meta_add(new_tagname, simpleTag.value.GetUTF8().c_str());
-		}
-		else=20
-		{
-			// Ignored tag, will be rewrited later
-			simpleTag.hidden =3D true;
-		}
-	}
-}
-
-void MatroskaAudioParser::SetTrackTags(file_info &info, MatroskaTagInfo*=
 TrackTags)
-{
-	if(TrackTags =3D=3D NULL)
-		return;
-
-	for (size_t s =3D 0; s < TrackTags->tags.size(); s++)
-	{
-		MatroskaSimpleTag &simpleTag =3D TrackTags->tags.at(s);
-	=09
-		if (is_rg_field(simpleTag.name.GetUTF8().c_str()))
-		{
-			if(IsTagNamed(simpleTag, "REPLAYGAIN_GAIN"))
-			{
-				info.info_set_replaygain("replaygain_track_gain", simpleTag.value.Ge=
tUTF8().c_str());
-			} else if(IsTagNamed(simpleTag, "REPLAYGAIN_PEAK")) {
-				info.info_set_replaygain("replaygain_track_peak", simpleTag.value.Ge=
tUTF8().c_str());
-			}
-		}
-		else if (is_hidden_chapter_field(simpleTag.name.GetUTF8().c_str()))
-		{
-			// Ignore tag
-			simpleTag.hidden =3D true;
-		}
-        /*else if(IsTagNamed(simpleTag,"COMMENTS"))
-		{
-			info.meta_add("COMMENT", simpleTag.value.GetUTF8().c_str());
-		}*/
-		else if(IsTagNamed(simpleTag,"ALBUM"))
-		{
-			if(!TagExistsAtEditionLevel(TrackTags, "TITLE") && AreTagsIdenticalAt=
ChapterLevel("ALBUM")) {
-				info.meta_add("ALBUM", simpleTag.value.GetUTF8().c_str());
-			} else {
-				info.meta_add("ORIGINAL ALBUM", simpleTag.value.GetUTF8().c_str());
-			}
-		}
-		else
-		{
-            pfc::string8 new_tagname;
-            convert_matroska_to_foobar2k_tag(new_tagname, matroska_to_fo=
obar2k_chapter_tag(simpleTag.name.GetUTF8().c_str()));
-			info.meta_add(new_tagname, simpleTag.value.GetUTF8().c_str());=09
-		}
-	}
-}
-
-bool MatroskaAudioParser::SetFB2KInfo(file_info &info, t_uint32 p_subson=
g)
-{
-	if (m_MuxingApp.length() > 0)
-		info.info_set("MUXING_APP", m_MuxingApp.GetUTF8().c_str());
-	if (m_WritingApp.length() > 0)
-		info.info_set("WRITING_APP", m_WritingApp.GetUTF8().c_str());
-	if (m_FileTitle.length() > 0)
-		info.info_set("TITLE", m_FileTitle.GetUTF8().c_str());
-
-	// pregap
-	try {
-		if (m_Chapters.at(p_subsong).subChapters.size() > 1) {
-			double pregap =3D TimecodeToSeconds(m_Chapters.at(p_subsong).subChapt=
ers.at(1).timeStart - m_Chapters.at(p_subsong).subChapters.at(0).timeStar=
t);
-			info.info_set("pregap", cuesheet_format_index_time(pregap));
-		}
-	} catch (std::out_of_range & e) {
-	}
-
-	MatroskaTagInfo *TrackTags =3D FindTagWithTrackUID(m_Tracks.at(m_Curren=
tTrackNo).trackUID);
-	MatroskaTagInfo *ChapterTags =3D NULL;
-	if(m_CurrentChapter !=3D NULL)
-	{
-		ChapterTags =3D FindTagWithChapterUID(m_CurrentChapter->chapterUID,
-			m_Tracks.at(m_CurrentTrackNo).trackUID);
-	}
-
-	MatroskaTagInfo *EditionTags =3D NULL;
-	if(m_CurrentEdition !=3D NULL)
-	{
-		EditionTags =3D FindTagWithEditionUID(m_CurrentEdition->editionUID,
-			m_Tracks.at(m_CurrentTrackNo).trackUID);
-	}
-	if(EditionTags !=3D NULL && EditionTags->targetTypeValue =3D=3D 50)
-	{
-		SetAlbumTags(info, EditionTags, ChapterTags);
-	}
-
-	if(TrackTags !=3D NULL)
-	{
-		if(TrackTags->targetTypeValue =3D=3D 50)
-		{
-			SetAlbumTags(info, TrackTags, ChapterTags);
-			SetTrackTags(info, ChapterTags);
-		} else if (TrackTags->targetTypeValue =3D=3D 30) {
-			SetTrackTags(info, TrackTags);
-		}
-	}
-=09
-	// Last chance,
-	if(m_CurrentChapter !=3D NULL)
-	{
-		// If TITLE tag is empty we get it from the chapter name
-		if ( (m_CurrentChapter->display.size() > 0) &&
-			 ((info.meta_get("TITLE", 0) =3D=3D NULL) ||
-			  (strlen(info.meta_get("TITLE", 0)) =3D=3D 0) ) )
-		{
-			info.meta_set("TITLE", m_CurrentChapter->display.at(0).string.GetUTF8=
().c_str());
-		}
-		if ((info.meta_get("TRACKNUMBER", 0) =3D=3D NULL) || (strlen(info.meta=
_get("TRACKNUMBER", 0)) =3D=3D 0))
-		{
-			//char trackNumberString[32];
-            pfc::string8 trackNumberString;
-#ifdef MULTITRACK		=09
-			//wsprintf((LPWSTR)trackNumberString, (LPCWSTR)"%d",
-			//	(p_subsong % m_Chapters.size()) +1);
-            trackNumberString << ((p_subsong % m_Chapters.size()) +1);
-#else
-			wsprintf(trackNumberString, "%d",p_subsong+1);
-#endif
-			info.meta_set("TRACKNUMBER", trackNumberString);
-		}
-		if ((info.meta_get("ALBUM", 0) =3D=3D NULL) || (strlen(info.meta_get("=
ALBUM", 0)) =3D=3D 0))
-		{
-			if(m_FileTitle.length() > 0)
-				info.meta_set("ALBUM", m_FileTitle.GetUTF8().c_str());
-		}
-	}
-
-	return true;
-};
-
-void MatroskaAudioParser::MarkHiddenTags()
-{
-	// We call MatroskaAudioParser::SetFB2KInfo with a dummy file_info that
-	// do nothing, so we will only mark hidden tags.
-	// Hidden tag will be copied to keep track of them.
-	// This is needed cause tag are read and written in 2 different instanc=
es
-	file_info_impl info;
-	SetFB2KInfo(info, 0);
-};
-
-void MatroskaAudioParser::SetCurrentTrack(uint32 newTrackNo)
-{
-	m_CurrentTrackNo =3D newTrackNo;
-	// Clear the current queue (we are changing tracks)
-	while (!m_Queue.empty())
-		m_Queue.pop();
-};
-
-void MatroskaAudioParser::SetSubSong(int subsong)
-{
-	// As we don't (yet?) use several Editions, select the first (default) =
one as the current one.
-	m_CurrentEdition =3D NULL;
-	m_CurrentChapter =3D NULL;
-	if(m_Editions.size() > 0)
-		m_CurrentEdition =3D &m_Editions.at(0);
-	if (m_Chapters.size() > subsong)
-		m_CurrentChapter =3D &m_Chapters.at(subsong);
-=09
-};
-
-int32 MatroskaAudioParser::GetAvgBitrate()=20
-{=20
-	double ret =3D 0;
-	ret =3D static_cast<double>(int64(m_FileSize)) / 1024;
-	ret =3D ret / (m_Duration / 1000000000.0);
-	ret =3D ret * 8;
-	return static_cast<int32>(ret);
-};
-
-bool MatroskaAudioParser::skip_frames_until(double destination,unsigned =
& frames,double & last_timecode_delta,unsigned hint_samplerate)
-{
-	unsigned done =3D 0;
-	unsigned last_laced =3D 0;
-
-	double last_time;
-	{
-		uint64 last_timecode =3D get_current_frame_timecode();
-		if (last_timecode =3D=3D (uint64)(-1)) return false;
-		last_time =3D TimecodeToSeconds(last_timecode,hint_samplerate);
-	}
-
-	for(;;)
-	{
-		while (!m_Queue.empty()) {
-			MatroskaAudioFrame *currentPacket =3D m_Queue.front();
-			double packet_time =3D TimecodeToSeconds(currentPacket->timecode,hint=
_samplerate);
-			if (packet_time > destination)
-			{
-				if (done=3D=3D0) return false;
-				last_timecode_delta =3D destination - last_time;
-				frames =3D done - last_laced;
-				return true;
-			}
-			last_time =3D packet_time;
-			done +=3D (last_laced =3D currentPacket->dataBuffer.size());
-			//delete currentPacket;
-			_DELETE(currentPacket);
-			m_Queue.pop();
-		}
-		if (FillQueue()!=3D0)
-			return false;
-	}
-}
-
-
-void MatroskaAudioParser::flush_queue()
-{
-	while (!m_Queue.empty()) {
-		MatroskaAudioFrame *currentPacket =3D m_Queue.front();
-		//delete currentPacket;
-		_DELETE(currentPacket);
-		m_Queue.pop();
-	}
-}
-
-uint64 MatroskaAudioParser::get_current_frame_timecode()
-{
-	if (m_Queue.empty())
-	{
-		if (FillQueue()!=3D0) return -1;
-		if (m_Queue.empty()) return -1;
-	}
-	return m_Queue.front()->timecode;
-}
-
-bool MatroskaAudioParser::Seek(double seconds,unsigned & frames_to_skip,=
double & time_to_skip,unsigned samplerate_hint)
-{
-	int64 ret =3D 0;
-
-	if (m_CurrentChapter !=3D NULL) {
-		seconds +=3D (double)(int64)m_CurrentChapter->timeStart / 1000000000; =
// ns -> seconds
-	}
-
-	uint64 seekToTimecode =3D SecondsToTimecode(seconds);
-=09
-	flush_queue();
-	m_CurrentTimecode =3D seekToTimecode;
-
-	if (!skip_frames_until(seconds,frames_to_skip,time_to_skip,samplerate_h=
int)) return false;
-
-	flush_queue();
-	m_CurrentTimecode =3D seekToTimecode;
-	if (FillQueue()!=3D0) return false;
-	return true;
-
-};
-
-MatroskaAudioFrame * MatroskaAudioParser::ReadSingleFrame()
-{
-	for(;;)
-	{
-		if (!m_Queue.empty()) {
-			MatroskaAudioFrame *newFrame =3D m_Queue.front();	=09
-			m_Queue.pop();
-			return newFrame;
-		} else {
-			if (FillQueue()!=3D0)
-				return 0;
-		}
-	}
-};
-
-MatroskaAudioFrame * MatroskaAudioParser::ReadFirstFrame()
-{
-    m_CurrentTimecode =3D 0;
-    return ReadSingleFrame();
-};
-
-typedef boost::shared_ptr<EbmlId> EbmlIdPtr;
-
-void MatroskaAudioParser::Parse_MetaSeek(ElementPtr metaSeekElement, boo=
l bInfoOnly)=20
-{
-    TIMER;
-	uint64 lastSeekPos =3D 0;
-	uint64 endSeekPos =3D 0;
-	ElementPtr l2;
-	ElementPtr l3;
-	ElementPtr NullElement;
-	int UpperElementLevel =3D 0;
-
-	if (metaSeekElement =3D=3D NullElement)
-		return;
-
-	l2 =3D ElementPtr(m_InputStream.FindNextElement(metaSeekElement->Generi=
c().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
-	while (l2 !=3D NullElement) {
-		if (UpperElementLevel > 0) {
-			break;
-		}
-		if (UpperElementLevel < 0) {
-			UpperElementLevel =3D 0;
-		}
-        if (bInfoOnly) {
-            if (m_ClusterIndex.size() >=3D 1) break;
-        }
-
-		if (EbmlId(*l2) =3D=3D KaxSeek::ClassInfos.GlobalId) {
-			//Wow we found the SeekEntries, time to speed up reading ;)
-			l3 =3D ElementPtr(m_InputStream.FindNextElement(l2->Generic().Context=
, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
-
-			EbmlIdPtr id;
-			while (l3 !=3D NullElement) {
-				if (UpperElementLevel > 0) {
-					break;
-				}
-				if (UpperElementLevel < 0) {
-					UpperElementLevel =3D 0;
-				}
-                if (bInfoOnly) {
-                    if (m_ClusterIndex.size() >=3D 1) break;
-                }
-
-				if (EbmlId(*l3) =3D=3D KaxSeekID::ClassInfos.GlobalId) {
-					binary *b =3D NULL;
-					uint16 s =3D 0;
-					KaxSeekID &seek_id =3D static_cast<KaxSeekID &>(*l3);
-					seek_id.ReadData(m_InputStream.I_O(), SCOPE_ALL_DATA);
-					b =3D seek_id.GetBuffer();
-					s =3D (uint16)seek_id.GetSize();
-                    id.reset();
-					id =3D EbmlIdPtr(new EbmlId(b, s));
-
-				} else if (EbmlId(*l3) =3D=3D KaxSeekPosition::ClassInfos.GlobalId) =
{
-					KaxSeekPosition &seek_pos =3D static_cast<KaxSeekPosition &>(*l3);
-					seek_pos.ReadData(m_InputStream.I_O());			=09
-					lastSeekPos =3D uint64(seek_pos);
-					if (endSeekPos < lastSeekPos)
-						endSeekPos =3D uint64(seek_pos);
-
-					if (*id =3D=3D KaxCluster::ClassInfos.GlobalId) {
-						//NOTE1("Found Cluster Seek Entry Postion: %u", (unsigned long)las=
tSeekPos);
-						//uint64 orig_pos =3D inputFile.getFilePointer();
-						//MatroskaMetaSeekClusterEntry newCluster;
-                        cluster_entry_ptr newCluster(new MatroskaMetaSee=
kClusterEntry());
-						newCluster->timecode =3D MAX_UINT64;
-						newCluster->filePos =3D static_cast<KaxSegment *>(m_ElementLevel0.=
get())->GetGlobalPosition(lastSeekPos);
-						m_ClusterIndex.push_back(newCluster);
-
-					} else if (*id =3D=3D KaxSeekHead::ClassInfos.GlobalId) {
-						NOTE1("Found MetaSeek Seek Entry Postion: %u", (unsigned long)last=
SeekPos);
-						uint64 orig_pos =3D m_IOCallback.getFilePointer();
-						m_IOCallback.setFilePointer(static_cast<KaxSegment *>(m_ElementLev=
el0.get())->GetGlobalPosition(lastSeekPos));
-					=09
-						ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextID(Ka=
xSeekHead::ClassInfos, 0xFFFFFFFFFFFFFFFFL));									=09
-						Parse_MetaSeek(levelUnknown, bInfoOnly);
-
-						m_IOCallback.setFilePointer(orig_pos);
-					}
-
-				} else {
-
-				}
-				l3->SkipData(m_InputStream, l3->Generic().Context);
-				l3 =3D ElementPtr(m_InputStream.FindNextElement(l2->Generic().Contex=
t, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
-			}
-		} else {
-
-		}
-
-		if (UpperElementLevel > 0) {    // we're coming from l3
-			UpperElementLevel--;
-			l2 =3D l3;
-			if (UpperElementLevel > 0)
-				break;
-
-		} else {
-			l2->SkipData(m_InputStream, l2->Generic().Context);
-			l2 =3D ElementPtr(m_InputStream.FindNextElement(metaSeekElement->Gene=
ric().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
-		}
-	}
-    _TIMER("Parse_MetaSeek");
-}
-
-#define IS_ELEMENT_ID(__x__) (Element->Generic().GlobalId =3D=3D __x__::=
ClassInfos.GlobalId)
-
-void MatroskaAudioParser::Parse_Chapter_Atom(KaxChapterAtom *ChapterAtom=
)
-{
-	Parse_Chapter_Atom(ChapterAtom, m_Chapters);
-}
-
-void MatroskaAudioParser::Parse_Chapter_Atom(KaxChapterAtom *ChapterAtom=
, std::vector<MatroskaChapterInfo> &p_chapters)
-{
-	int i, j;
-	EbmlElement *Element =3D NULL;
-	MatroskaChapterInfo newChapter;
-
-	NOTE("New chapter");
-
-	for (i =3D 0; i < ChapterAtom->ListSize(); i++)
-	{=09
-		Element =3D (*ChapterAtom)[i];
-			=09
-		if (IS_ELEMENT_ID(KaxChapterUID))
-		{
-			newChapter.chapterUID =3D uint64(*static_cast<EbmlUInteger *>(Element=
));
-			NOTE1("- UID : %I64d", newChapter.chapterUID);
-		}
-		else if(IS_ELEMENT_ID(KaxChapterTimeStart))
-		{						=09
-			newChapter.timeStart =3D uint64(*static_cast<EbmlUInteger *>(Element)=
); // it's in ns
-			NOTE1("- TimeStart : %I64d", newChapter.timeStart);
-		}
-		else if(IS_ELEMENT_ID(KaxChapterTimeEnd))
-		{
-			newChapter.timeEnd =3D uint64(*static_cast<EbmlUInteger *>(Element));=
 // it's in ns
-			NOTE1("- TimeEnd : %I64d", newChapter.timeEnd);
-		}
-		else if(IS_ELEMENT_ID(KaxChapterTrack))
-		{
-			KaxChapterTrack *ChapterTrack =3D (KaxChapterTrack *)Element;
-		=09
-			for (j =3D 0; j < ChapterTrack->ListSize(); j++)
-			{
-				Element =3D (*ChapterTrack)[j];
-				if(IS_ELEMENT_ID(KaxChapterTrackNumber))
-				{
-					uint64 chapTrackNo =3D uint64(*static_cast<EbmlUInteger *>(Element)=
);
-					newChapter.tracks.push_back(chapTrackNo);
-					NOTE1("- TrackNumber : %I64d", chapTrackNo);
-				}
-				else if(IS_ELEMENT_ID(KaxChapterAtom))
-				{								=09
-					// Ignore sub-chapter
-					NOTE("ignore sub-chapter");
-					//Parse_Chapter_Atom((KaxChapterAtom *)Element);
-				}
-			}
-		}
-		else if(IS_ELEMENT_ID(KaxChapterDisplay))
-		{
-			// A new chapter display string+lang+country
-			MatroskaChapterDisplayInfo newChapterDisplay;						=09
-			KaxChapterDisplay *ChapterDisplay =3D (KaxChapterDisplay *)Element;
-		=09
-			for (j =3D 0; j < ChapterDisplay->ListSize(); j++) {
-				Element =3D (*ChapterDisplay)[j];
-				if(IS_ELEMENT_ID(KaxChapterString))
-				{
-					newChapterDisplay.string =3D UTFstring(*static_cast <EbmlUnicodeStr=
ing *>(Element)).c_str();
-					NOTE1("- String : %s", newChapterDisplay.string.GetUTF8().c_str());
-				}
-				else if(IS_ELEMENT_ID(KaxChapterAtom))
-				{								=09
-					// Ignore sub-chapter
-					NOTE("ignore sub-chapter");
-					//Parse_Chapter_Atom((KaxChapterAtom *)Element);
-				}
-			}
-			// A emtpy string in a chapter display string is usless
-			if (newChapterDisplay.string.length() > 0)
-				newChapter.display.push_back(newChapterDisplay);
-		}
-		else if(IS_ELEMENT_ID(KaxChapterAtom))
-		{
-			/*
-			// Ignore sub-chapter
-			NOTE("ignore sub-chapter");
-			//Parse_Chapter_Atom((KaxChapterAtom *)Element);
-			*/
-			Parse_Chapter_Atom((KaxChapterAtom *)Element, newChapter.subChapters)=
;
-		}
-	}
-	if ((newChapter.chapterUID !=3D 0) && !FindChapterUID(newChapter.chapte=
rUID))
-		p_chapters.push_back(newChapter);
-}
-
-void MatroskaAudioParser::Parse_Chapters(KaxChapters *chaptersElement)
-{
-	int i, j;=09
-	EbmlElement *Element =3D NULL;=09
-	int UpperEltFound =3D 0;
-
-	NOTE("New edition");
-
-	if (chaptersElement =3D=3D NULL)
-		return;
-
-	chaptersElement->Read(m_InputStream, KaxChapters::ClassInfos.Context,
-		UpperEltFound, Element, true);
-
-	for (i =3D 0; i < chaptersElement->ListSize(); i++)
-	{
-		Element =3D (*chaptersElement)[i];
-		if(IS_ELEMENT_ID(KaxEditionEntry))
-		{
-			MatroskaEditionInfo newEdition;
-			KaxEditionEntry *edition =3D (KaxEditionEntry *)Element;
-			for (j =3D 0; j < edition->ListSize(); j++)
-			{
-				Element =3D (*edition)[j];
-				if(IS_ELEMENT_ID(KaxEditionUID))
-				{
-					// A new edition :)
-					newEdition.editionUID =3D uint64(*static_cast<EbmlUInteger *>(Eleme=
nt));
-					NOTE1("- UID : %I64d", newEdition.editionUID);
-				}
-				else if(IS_ELEMENT_ID(KaxChapterAtom))
-				{
-					// A new chapter :)
-					Parse_Chapter_Atom((KaxChapterAtom *)Element);
-				}
-			}
-			if ((newEdition.editionUID !=3D 0) && !FindEditionUID(newEdition.edit=
ionUID))
-				m_Editions.push_back(newEdition);
-		}
-	}
-	FixChapterEndTimes();
-}
-
-void MatroskaAudioParser::Parse_Tags(KaxTags *tagsElement)
-{
-	int i, j, k;
-	EbmlElement *Element =3D NULL;
-	int UpperEltFound =3D 0;
-
-	if (tagsElement =3D=3D NULL)
-		return;
-
-	m_TagPos =3D tagsElement->GetElementPosition();
-	m_TagSize =3D tagsElement->GetSize();
-
-	tagsElement->Read(m_InputStream, KaxTags::ClassInfos.Context, UpperEltF=
ound, Element, true);
-
-	for (i =3D 0; i < tagsElement->ListSize(); i++)
-	{
-		Element =3D (*tagsElement)[i];
-		if(IS_ELEMENT_ID(KaxTag))
-		{
-			MatroskaTagInfo newTag;
-			newTag.targetTypeValue =3D 50;
-			KaxTag *tagElement =3D (KaxTag*)Element;
-			NOTE("New Tag");
-			for (j =3D 0; j < tagElement->ListSize(); j++)
-			{
-				Element =3D (*tagElement)[j];
-				if(IS_ELEMENT_ID(KaxTagTargets))
-				{
-					KaxTagTargets *tagTargetsElement =3D (KaxTagTargets*)Element;				=09
-					for (k =3D 0; k < tagTargetsElement->ListSize(); k++)
-					{
-						Element =3D (*tagTargetsElement)[k];
-						if(IS_ELEMENT_ID(KaxTagTrackUID))
-						{
-							newTag.targetTrackUID =3D uint64(*static_cast<EbmlUInteger *>(Ele=
ment));
-							NOTE1("- TargetTrackUID : %I64d", newTag.targetTrackUID);
-						}
-						else if(IS_ELEMENT_ID(KaxTagEditionUID))
-						{
-							newTag.targetEditionUID =3D uint64(*static_cast<EbmlUInteger *>(E=
lement));
-							NOTE1("- TargetEditionUID : %I64d", newTag.targetEditionUID);
-						}
-						else if(IS_ELEMENT_ID(KaxTagChapterUID))
-						{
-							newTag.targetChapterUID =3D uint64(*static_cast<EbmlUInteger *>(E=
lement));
-							NOTE1("- TargetChapterUIDUID : %I64d", newTag.targetChapterUID);
-						}
-						else if(IS_ELEMENT_ID(KaxTagAttachmentUID))
-						{
-							newTag.targetAttachmentUID =3D uint64(*static_cast<EbmlUInteger *=
>(Element));
-							NOTE1("- TargetAttachmentUID : %I64d", newTag.targetAttachmentUID=
);
-						}
-						else if(IS_ELEMENT_ID(KaxTagTargetTypeValue))
-						{
-							newTag.targetTypeValue =3D uint32(*static_cast<EbmlUInteger *>(El=
ement));
-							NOTE1("- TargetTypeValue : %d", newTag.targetTypeValue);
-						}
-						else if(IS_ELEMENT_ID(KaxTagTargetType))
-						{
-							newTag.targetType =3D std::string(*static_cast<KaxTagTargetType *=
>(Element));
-							NOTE1("- TargetType : %s", newTag.targetType.c_str());
-						}
-					}
-				}
-				else if(IS_ELEMENT_ID(KaxTagSimple))
-				{
-					MatroskaSimpleTag newSimpleTag;
-					KaxTagSimple *tagSimpleElement =3D (KaxTagSimple*)Element;
-					NOTE("New SimpleTag");
-					for (k =3D 0; k < tagSimpleElement->ListSize(); k++)
-					{
-						Element =3D (*tagSimpleElement)[k];
-						if(IS_ELEMENT_ID(KaxTagName))
-						{
-							newSimpleTag.name =3D wcsupr((wchar_t *)UTFstring(*static_cast <E=
bmlUnicodeString *>(Element)).c_str());
-							NOTE1("- Name : %s", newSimpleTag.name.GetUTF8().c_str());
-						}
-						else if(IS_ELEMENT_ID(KaxTagString))
-						{
-							newSimpleTag.value =3D UTFstring(*static_cast <EbmlUnicodeString =
*>(Element)).c_str();
-							NOTE1("- Value : %s", newSimpleTag.value.GetUTF8().c_str());
-						}
-						else if(IS_ELEMENT_ID(KaxTagDefault))
-						{
-							newSimpleTag.defaultFlag =3D uint32(*static_cast<EbmlUInteger *>(=
Element));
-							NOTE1("- TargetTypeValue : %d", newSimpleTag.default);
-						}
-						else if(IS_ELEMENT_ID(KaxTagLangue))
-						{
-							newSimpleTag.language =3D std::string(*static_cast <KaxTagLangue =
*>(Element));
-							NOTE1("- Language : %s", newSimpleTag.language.c_str());
-						}
-						else if(IS_ELEMENT_ID(KaxTagSimple))
-						{
-							// ignore sub-tags
-							// if we want "sub-tags" put this loop in another
-							// function and call it recursively
-						}
-					}
-					newTag.tags.push_back(newSimpleTag);
-				}
-			}
-			m_Tags.push_back(newTag);
-		}
-	}
-};
-
-int MatroskaAudioParser::FillQueue()=20
-{
-	flush_queue();
-
-	NOTE("MatroskaAudioParser::FillQueue()");
-
-	int UpperElementLevel =3D 0;
-	bool bAllowDummy =3D false;
-	// Elements for different levels
-	ElementPtr ElementLevel1;
-	ElementPtr ElementLevel2;
-	ElementPtr ElementLevel3;
-	ElementPtr ElementLevel4;
-    ElementPtr ElementLevel5;
-	ElementPtr NullElement;
-	//m_framebuffer.set_size(0);
-
-	if (m_IOCallback.seekable()) {
-		cluster_entry_ptr currentCluster =3D FindCluster(m_CurrentTimecode);
-		if (currentCluster.get() =3D=3D NULL)
-			return 2;
-		int64 clusterFilePos =3D currentCluster->filePos;
-
-		//console::info(uStringPrintf("cluster %d", currentCluster->clusterNo)=
);
-
-		m_IOCallback.setFilePointer(clusterFilePos);
-		// Find the element data
-		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
-		if (ElementLevel1 =3D=3D NullElement)
-			return 1;
-
-		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
-			KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLevel=
1.get());
-			uint32 ClusterTimecode =3D 0;
-			MatroskaAudioFrame *prevFrame =3D NULL;
-
-			// read blocks and discard the ones we don't care about
-			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
bAllowDummy));
-			while (ElementLevel2 !=3D NullElement) {
-				if (UpperElementLevel > 0) {
-					break;
-				}
-				if (UpperElementLevel < 0) {
-					UpperElementLevel =3D 0;
-				}
-				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
-					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
-					ClusterTime.ReadData(m_InputStream.I_O());
-					ClusterTimecode =3D uint32(ClusterTime);
-					currentCluster->timecode =3D ClusterTimecode * m_TimecodeScale;
-					SegmentCluster->InitTimecode(ClusterTimecode, m_TimecodeScale);
-				} else  if (EbmlId(*ElementLevel2) =3D=3D KaxBlockGroup::ClassInfos.=
GlobalId) {
-					//KaxBlockGroup & aBlockGroup =3D *static_cast<KaxBlockGroup*>(Elem=
entLevel2);
-
-					// Create a new frame
-					MatroskaAudioFrame *newFrame =3D new MatroskaAudioFrame;
-
-					ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize()=
, bAllowDummy));
-					while (ElementLevel3 !=3D NullElement) {
-						if (UpperElementLevel > 0) {
-							break;
-						}
-						if (UpperElementLevel < 0) {
-							UpperElementLevel =3D 0;
-						}
-						if (EbmlId(*ElementLevel3) =3D=3D KaxBlock::ClassInfos.GlobalId) {=
							=09
-							KaxBlock & DataBlock =3D *static_cast<KaxBlock*>(ElementLevel3.ge=
t());													=09
-							DataBlock.ReadData(m_InputStream.I_O());
-							DataBlock.SetParent(*SegmentCluster);
-
-							//NOTE4("Track # %u / %u frame%s / Timecode %I64d", DataBlock.Tra=
ckNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"",=
 DataBlock.GlobalTimecode()/m_TimecodeScale);
-							if (DataBlock.TrackNum() =3D=3D m_Tracks.at(m_CurrentTrackNo).tra=
ckNumber) {										=09
-								newFrame->timecode =3D DataBlock.GlobalTimecode();
-
-								if (DataBlock.NumberFrames() > 1) {=09
-									// The evil lacing has been used
-									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation * DataBlock.NumberFrames();
-
-									newFrame->dataBuffer.resize(DataBlock.NumberFrames());
-									for (uint32 f =3D 0; f < DataBlock.NumberFrames(); f++) {
-										DataBuffer &buffer =3D DataBlock.GetBuffer(f);
-										newFrame->dataBuffer[f].resize(buffer.Size());							=09
-										memcpy(&newFrame->dataBuffer[f][0], buffer.Buffer(), buffer.Si=
ze());
-									}
-								} else {
-									// Non-lacing block	=09
-									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation;
-
-									newFrame->dataBuffer.resize(1);
-									DataBuffer &buffer =3D DataBlock.GetBuffer(0);
-									newFrame->dataBuffer.at(0).resize(buffer.Size());
-                                       =20
-									memcpy(&newFrame->dataBuffer.at(0).at(0), buffer.Buffer(), buff=
er.Size());
-								}
-							} else {
-								//newFrame->timecode =3D MAX_UINT64;
-							}
-						/*
-						} else if (EbmlId(*ElementLevel3) =3D=3D KaxReferenceBlock::ClassI=
nfos.GlobalId) {
-							KaxReferenceBlock & RefTime =3D *static_cast<KaxReferenceBlock*>(=
ElementLevel3);
-							RefTime.ReadData(m_InputStream.I_O());
-							newFrame->frameReferences.push_back(int32(RefTime));
-							//wxLogDebug("  Reference frame at scaled (%d) timecode %ld\n", i=
nt32(RefTime), int32(int64(RefTime) * TimecodeScale));
-							*/
-						} else if (EbmlId(*ElementLevel3) =3D=3D KaxBlockDuration::ClassIn=
fos.GlobalId) {
-							KaxBlockDuration & BlockDuration =3D *static_cast<KaxBlockDuratio=
n*>(ElementLevel3.get());
-							BlockDuration.ReadData(m_InputStream.I_O());
-							newFrame->duration =3D uint64(BlockDuration);
-                        } else if (EbmlId(*ElementLevel3) =3D=3D KaxBloc=
kAdditions::ClassInfos.GlobalId) {
-                            ElementLevel4 =3D ElementPtr(m_InputStream.F=
indNextElement(ElementLevel3->Generic().Context, UpperElementLevel, 0xFFF=
FFFFFL, bAllowDummy));
-                            while (ElementLevel4 !=3D NullElement) {
-                                if (UpperElementLevel > 0) {
-							        break;
-						        }
-						        if (UpperElementLevel < 0) {
-							        UpperElementLevel =3D 0;
-						        }
-                                if (EbmlId(*ElementLevel4) =3D=3D KaxBlo=
ckMore::ClassInfos.GlobalId) {
-                                    ElementLevel5 =3D ElementPtr(m_Input=
Stream.FindNextElement(ElementLevel4->Generic().Context, UpperElementLeve=
l, 0xFFFFFFFFL, bAllowDummy));
-                                    while (ElementLevel5 !=3D NullElemen=
t) {
-                                        if (UpperElementLevel > 0) {
-							                break;
-						                }
-						                if (UpperElementLevel < 0) {
-							                UpperElementLevel =3D 0;
-						                }
-                                        if (EbmlId(*ElementLevel5) =3D=3D=
 KaxBlockAddID::ClassInfos.GlobalId) {
-                                            KaxBlockAddID & AddId =3D *s=
tatic_cast<KaxBlockAddID*>(ElementLevel5.get());
-                                            AddId.ReadData(m_InputStream=
.I_O());
-                                            newFrame->add_id =3D uint64(=
AddId);
-                                        } else if (EbmlId(*ElementLevel5=
) =3D=3D KaxBlockAdditional::ClassInfos.GlobalId) {
-                                            KaxBlockAdditional & DataBlo=
ckAdditional =3D *static_cast<KaxBlockAdditional*>(ElementLevel5.get());	=
												=09
-							                DataBlockAdditional.ReadData(m_InputStream.I_O())=
;	=09
-                                            newFrame->additional_data_bu=
ffer.resize(DataBlockAdditional.GetSize());
-                                            if (!newFrame->add_id) {
-                                                newFrame->add_id =3D 1;
-                                            }
-                                            memcpy(&newFrame->additional=
_data_buffer.at(0), DataBlockAdditional.GetBuffer(), DataBlockAdditional.=
GetSize());
-                                        }
-                                        ElementLevel5->SkipData(m_InputS=
tream, ElementLevel5->Generic().Context);
-							            ElementLevel5 =3D ElementPtr(m_InputStream.FindNextEl=
ement(ElementLevel4->Generic().Context, UpperElementLevel, ElementLevel4-=
>ElementSize(), bAllowDummy));
-                                    }
-                                }
-                                if (UpperElementLevel > 0) {
-							        UpperElementLevel--;
-							        ElementLevel4 =3D ElementLevel5;
-							        if (UpperElementLevel > 0)
-								        break;
-						        } else {
-							        ElementLevel4->SkipData(m_InputStream, ElementLevel4->Gen=
eric().Context);
-							        ElementLevel4 =3D ElementPtr(m_InputStream.FindNextElemen=
t(ElementLevel3->Generic().Context, UpperElementLevel, ElementLevel3->Ele=
mentSize(), bAllowDummy));
-						        }
-                            }
-                        }
-						if (UpperElementLevel > 0) {
-							UpperElementLevel--;
-							ElementLevel3 =3D ElementLevel4;
-							if (UpperElementLevel > 0)
-								break;
-						} else {
-							ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().C=
ontext);
-
-							ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Elemen=
tLevel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize=
(), bAllowDummy));
-						}						=09
-						//newFrame =3D new MatroskaReadFrame();
-					}
-					if (newFrame->dataBuffer.size()>0) {
-						m_Queue.push(newFrame);
-						if (prevFrame !=3D NULL && prevFrame->duration =3D=3D 0) {
-							prevFrame->duration =3D newFrame->timecode - prevFrame->timecode;
-							//if (newFrame->duration =3D=3D 0)
-							//	newFrame->duration =3D prevFrame->duration;
-						}
-
-						// !!!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!!!!!!!!!!!
-						// This is an ugly hack to keep us from re-seeking to the same clu=
ster
-						m_CurrentTimecode =3D newFrame->timecode + (newFrame->duration * 2=
);
-						if (newFrame->duration =3D=3D 0) {
-							m_CurrentTimecode +=3D (int64)m_Tracks.at(m_CurrentTrackNo).defau=
ltDuration * 2;
-						}
-						// !!!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!!!!!!!!!!!
-
-						prevFrame =3D newFrame;
-                    } else {
-                        hprintf(L"newFrame =3D=3D!! delete!!\n");
-                        _DELETE(newFrame);
-                    }
-				}
-
-				if (UpperElementLevel > 0) {
-					UpperElementLevel--;
-					//delete ElementLevel2;
-					//_DELETE(ElementLevel2);
-					ElementLevel2 =3D ElementLevel3;
-					if (UpperElementLevel > 0)
-						break;
-				} else {
-					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
-					//if (ElementLevel2 !=3D pChecksum)
-					//	delete ElementLevel2;							=09
-					//ElementLevel2 =3D NULL;
-					//_DELETE(ElementLevel2);
-
-					ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize()=
, bAllowDummy));
-				}
-			}
-		}
-		//_DELETE(ElementLevel3);
-		//_DELETE(ElementLevel2);
-		//_DELETE(ElementLevel1);
-		//delete ElementLevel1;
-	=09
-		if (currentCluster->clusterNo < m_ClusterIndex.size()-1) {
-			if (m_ClusterIndex.at(currentCluster->clusterNo+1)->timecode =3D=3D M=
AX_UINT64)
-				m_ClusterIndex.at(currentCluster->clusterNo+1)->timecode =3D GetClus=
terTimecode(m_ClusterIndex.at(currentCluster->clusterNo+1)->filePos);
-			m_CurrentTimecode =3D m_ClusterIndex.at(currentCluster->clusterNo+1)-=
>timecode;
-			if(m_CurrentTimecode =3D=3D 0)
-			{
-				console::error(uStringPrintf("clusterNo : %d, m_ClusterIndex.size() =
: %d", currentCluster->clusterNo, m_ClusterIndex.size()));
-				console::info("m_CurrentTimecode =3D=3D 0 (a)");
-			}
-		} else {
-			m_CurrentTimecode =3D MAX_UINT64;
-		}
-	=09
-	} else {
-		// Find the element data
-		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
-		if (ElementLevel1 =3D=3D NullElement)
-			return 1;
-
-		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
-			KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLevel=
1.get());
-			uint32 ClusterTimecode =3D 0;
-
-			// read blocks and discard the ones we don't care about
-			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
bAllowDummy));
-			while (ElementLevel2 !=3D NullElement) {
-				if (UpperElementLevel > 0) {
-					break;
-				}
-				if (UpperElementLevel < 0) {
-					UpperElementLevel =3D 0;
-				}
-				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
-					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
-					ClusterTime.ReadData(m_InputStream.I_O());
-					ClusterTimecode =3D uint32(ClusterTime);
-					SegmentCluster->InitTimecode(ClusterTimecode, m_TimecodeScale);
-				} else  if (EbmlId(*ElementLevel2) =3D=3D KaxBlockGroup::ClassInfos.=
GlobalId) {
-					//KaxBlockGroup & aBlockGroup =3D *static_cast<KaxBlockGroup*>(Elem=
entLevel2);
-
-					// Create a new frame
-					MatroskaAudioFrame *newFrame =3D new MatroskaAudioFrame;			=09
-
-					ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize()=
, bAllowDummy));
-					while (ElementLevel3 !=3D NullElement) {
-						if (UpperElementLevel > 0) {
-							break;
-						}
-						if (UpperElementLevel < 0) {
-							UpperElementLevel =3D 0;
-						}
-						if (EbmlId(*ElementLevel3) =3D=3D KaxBlock::ClassInfos.GlobalId) {=
							=09
-							KaxBlock & DataBlock =3D *static_cast<KaxBlock*>(ElementLevel3.ge=
t());													=09
-							DataBlock.ReadData(m_InputStream.I_O());	=09
-							DataBlock.SetParent(*SegmentCluster);
-
-							//NOTE4("Track # %u / %u frame%s / Timecode %I64d", DataBlock.Tra=
ckNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"",=
 DataBlock.GlobalTimecode()/m_TimecodeScale);
-							if (DataBlock.TrackNum() =3D=3D m_Tracks.at(m_CurrentTrackNo).tra=
ckNumber) {										=09
-								newFrame->timecode =3D DataBlock.GlobalTimecode();						=09
-
-								if (DataBlock.NumberFrames() > 1) {=09
-									// The evil lacing has been used
-									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation * DataBlock.NumberFrames();
-
-									newFrame->dataBuffer.resize(DataBlock.NumberFrames());
-									for (uint32 f =3D 0; f < DataBlock.NumberFrames(); f++) {
-										DataBuffer &buffer =3D DataBlock.GetBuffer(f);
-										newFrame->dataBuffer[f].resize(buffer.Size());							=09
-										memcpy(&newFrame->dataBuffer[f][0], buffer.Buffer(), buffer.Si=
ze());
-									}
-								} else {
-									// Non-lacing block	=09
-									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation;
-								=09
-									newFrame->dataBuffer.resize(1);
-									DataBuffer &buffer =3D DataBlock.GetBuffer(0);
-									newFrame->dataBuffer.at(0).resize(buffer.Size());							=09
-									memcpy(&newFrame->dataBuffer[0][0], buffer.Buffer(), buffer.Siz=
e());
-								}
-							} else {
-								//newFrame->timecode =3D MAX_UINT64;
-							}
-						/*
-						} else if (EbmlId(*ElementLevel3) =3D=3D KaxReferenceBlock::ClassI=
nfos.GlobalId) {
-							KaxReferenceBlock & RefTime =3D *static_cast<KaxReferenceBlock*>(=
ElementLevel3);
-							RefTime.ReadData(m_InputStream.I_O());
-							newFrame->frameReferences.push_back(int32(RefTime));
-							//wxLogDebug("  Reference frame at scaled (%d) timecode %ld\n", i=
nt32(RefTime), int32(int64(RefTime) * TimecodeScale));
-							*/
-						} else if (EbmlId(*ElementLevel3) =3D=3D KaxBlockDuration::ClassIn=
fos.GlobalId) {
-							KaxBlockDuration & BlockDuration =3D *static_cast<KaxBlockDuratio=
n*>(ElementLevel3.get());
-							BlockDuration.ReadData(m_InputStream.I_O());
-							newFrame->duration =3D uint64(BlockDuration);
-						}
-						if (UpperElementLevel > 0) {
-							UpperElementLevel--;
-							//delete ElementLevel3;
-							//_DELETE(ElementLevel3);
-							ElementLevel3 =3D ElementLevel4;
-							if (UpperElementLevel > 0)
-								break;
-						} else {
-							ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().C=
ontext);
-							//delete ElementLevel3;
-							//ElementLevel3 =3D NULL;
-							//_DELETE(ElementLevel3);
-
-							ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Elemen=
tLevel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize=
(), bAllowDummy));
-						}						=09
-						//newFrame =3D new MatroskaReadFrame();
-					}
-					if (newFrame->dataBuffer.size()>0)
-						m_Queue.push(newFrame);
-				}
-
-				if (UpperElementLevel > 0) {
-					UpperElementLevel--;
-					//delete ElementLevel2;
-					//_DELETE(ElementLevel2);
-					ElementLevel2 =3D ElementLevel3;
-					if (UpperElementLevel > 0)
-						break;
-				} else {
-					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
-					//if (ElementLevel2 !=3D pChecksum)
-					//	delete ElementLevel2;							=09
-					//ElementLevel2 =3D NULL;
-					//_DELETE(ElementLevel2);
-
-					ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize()=
, bAllowDummy));
-				}
-			}
-		}
-		ElementLevel1->SkipData(m_InputStream, ElementLevel1->Generic().Contex=
t);
-		//_DELETE(ElementLevel3);
-		//_DELETE(ElementLevel2);
-		//_DELETE(ElementLevel1);
-		//delete ElementLevel1;
-	}
-	//NOTE1("MatroskaAudioParser::FillQueue() - Queue now has %u frames", m=
_Queue.size());
-	return 0;
-};
-
-uint64 MatroskaAudioParser::GetClusterTimecode(uint64 filePos) {=09
-	try {
-		uint64 ret =3D MAX_UINT64;
-
-		int UpperElementLevel =3D 0;
-		// Elements for different levels
-		ElementPtr ElementLevel1;
-		ElementPtr ElementLevel2;	=09
-		ElementPtr ElementLevel3;
-		ElementPtr NullElement;
-
-		m_IOCallback.setFilePointer(filePos);
-		// Find the element data
-		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
-		if (ElementLevel1 =3D=3D NullElement)
-			return MAX_UINT64;
-
-		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
-			//KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLev=
el1);
-			//uint32 ClusterTimecode =3D 0;
-
-			// read blocks and discard the ones we don't care about
-			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
false));
-			while (ElementLevel2 !=3D NullElement) {
-				if (UpperElementLevel > 0) {
-					break;
-				}
-				if (UpperElementLevel < 0) {
-					UpperElementLevel =3D 0;
-				}
-				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
-					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
-					ClusterTime.ReadData(m_InputStream.I_O());
-					ret =3D uint64(ClusterTime) * m_TimecodeScale;
-				=09
-				}
-
-				if (UpperElementLevel > 0) {
-					UpperElementLevel--;
-					//delete ElementLevel2;
-					//_DELETE(ElementLevel2);
-					ElementLevel2 =3D ElementLevel3;
-					if (UpperElementLevel > 0)
-						break;
-				} else {
-					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
-					//if (ElementLevel2 !=3D pChecksum)
-					//delete ElementLevel2;							=09
-					//ElementLevel2 =3D NULL;
-					//_DELETE(ElementLevel2);
-					ElementLevel2 =3D NullElement;
-					if (ret =3D=3D -1)
-						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(=
), false));
-				}
-			}
-		}
-		//_DELETE(ElementLevel3);
-		//_DELETE(ElementLevel2);
-		//_DELETE(ElementLevel1);
-		//delete ElementLevel1;
-
-		return ret;
-	} catch (...) {
-		return MAX_UINT64;
-	}=09
-};
-
-cluster_entry_ptr MatroskaAudioParser::FindCluster(uint64 timecode)
-{
-	try {
-		#ifdef _DEBUG_NO_SEEKING
-		static size_t callCount =3D 0;
-		if (callCount < m_ClusterIndex.size())
-			return &m_ClusterIndex[callCount++];
-		else return NULL;
-		#endif
-
-		if (timecode =3D=3D 0)
-			// Special case
-			return m_ClusterIndex.at(0);
-	=09
-		cluster_entry_ptr correctEntry;
-		double clusterDuration =3D (double)(int64)m_ClusterIndex.size() / m_Du=
ration;
-		size_t clusterIndex =3D clusterDuration * (double)(int64)timecode;
-		//int lookCount =3D 0;
-		if (clusterIndex > m_ClusterIndex.size())
-			clusterIndex =3D m_ClusterIndex.size()-1;
-
-		cluster_entry_ptr clusterEntry;
-		cluster_entry_ptr prevClusterEntry;
-		cluster_entry_ptr nextClusterEntry;
-		while (correctEntry =3D=3D NULL) {
-			clusterEntry =3D m_ClusterIndex.at(clusterIndex);	=09
-			if (clusterIndex > 0)
-				prevClusterEntry =3D m_ClusterIndex.at(clusterIndex-1);
-			if (clusterIndex+1 < m_ClusterIndex.size())
-				nextClusterEntry =3D m_ClusterIndex.at(clusterIndex+1);		=09
-		=09
-			// We need timecodes to do good seeking
-			if (clusterEntry->timecode =3D=3D MAX_UINT64) {			=09
-				clusterEntry->timecode =3D GetClusterTimecode(clusterEntry->filePos)=
;		=09
-			}
-			if (prevClusterEntry !=3D NULL && prevClusterEntry->timecode =3D=3D M=
AX_UINT64) {
-				prevClusterEntry->timecode =3D GetClusterTimecode(prevClusterEntry->=
filePos);		=09
-			}
-			if (nextClusterEntry !=3D NULL && nextClusterEntry->timecode =3D=3D M=
AX_UINT64) {			=09
-				nextClusterEntry->timecode =3D GetClusterTimecode(nextClusterEntry->=
filePos);		=09
-			}
-
-			if (clusterEntry->timecode =3D=3D timecode) {
-				// WOW, we are seeking directly to this cluster
-				correctEntry =3D clusterEntry;
-				break;
-			}
-
-			if (prevClusterEntry !=3D NULL) {
-				if (clusterEntry->timecode > timecode && timecode > prevClusterEntry=
->timecode) {
-					// We found it !!!
-					correctEntry =3D prevClusterEntry;
-					break;
-				}
-				if (prevClusterEntry->timecode =3D=3D timecode) {
-					// WOW, we are seeking directly to this cluster
-					correctEntry =3D prevClusterEntry;
-					break;
-				}
-				// Check if we overshot the needed cluster
-				if (timecode < prevClusterEntry->timecode) {
-					clusterIndex--;
-					//lookCount++; // This is how many times we have 'looked'
-					continue;
-				}
-			}
-		=09
-			if (nextClusterEntry !=3D NULL) {
-				if (clusterEntry->timecode < timecode && timecode < nextClusterEntry=
->timecode) {
-					// We found it !!!
-					correctEntry =3D clusterEntry;
-					break;
-				}		=09
-				if (nextClusterEntry->timecode =3D=3D timecode) {
-					// WOW, we are seeking directly to this cluster
-					correctEntry =3D nextClusterEntry;
-					break;
-				}
-				// Check if we undershot the needed cluster
-				if (timecode > nextClusterEntry->timecode) {
-					clusterIndex++;
-					//lookCount--;
-					continue;
-				}
-			}
-			// We should never get here, unless this is the last cluster
-			assert(clusterEntry !=3D NULL);=09
-			if (timecode <=3D m_Duration)
-				correctEntry =3D clusterEntry;
-			else
-				break;
-		}
-
-		if (correctEntry !=3D NULL)
-			NOTE3("MatroskaAudioParser::FindCluster(timecode =3D %u) seeking to c=
luster %i at %u", (uint32)(timecode / m_TimecodeScale), (uint32)correctEn=
try->clusterNo, (uint32)correctEntry->filePos);
-		else
-			NOTE1("MatroskaAudioParser::FindCluster(timecode =3D %u) seeking fail=
ed", (uint32)(timecode / m_TimecodeScale));
-
-		return correctEntry;
-	} catch (...) {
-        cluster_entry_ptr null_ptr;
-		return null_ptr;
-	}
-}
-
-void MatroskaAudioParser::CountClusters()=20
-{
-	for (uint32 c =3D 0; c < m_ClusterIndex.size(); c++) {
-		cluster_entry_ptr clusterEntry =3D m_ClusterIndex.at(c);	=09
-		clusterEntry->clusterNo =3D c;
-	}
-}
-
-void MatroskaAudioParser::FixChapterEndTimes()
-{
-	if (m_Chapters.size() > 0) {
-		MatroskaChapterInfo *nextChapter =3D &m_Chapters.at(m_Chapters.size()-=
1);
-		if (nextChapter->timeEnd =3D=3D 0) {
-			nextChapter->timeEnd =3D static_cast<uint64>(m_Duration);
-		}
-		for (uint32 c =3D 0; c < m_Chapters.size()-1; c++) {
-			MatroskaChapterInfo &currentChapter =3D m_Chapters.at(c);=09
-			nextChapter =3D &m_Chapters.at(c+1);
-			if (currentChapter.timeEnd =3D=3D 0) {
-				currentChapter.timeEnd =3D nextChapter->timeStart;
-			}
-		}
-		nextChapter =3D &m_Chapters.at(m_Chapters.size()-1);
-		if ((nextChapter->timeEnd =3D=3D 0) || (nextChapter->timeEnd =3D=3D ne=
xtChapter->timeStart)) {
-			nextChapter->timeEnd =3D static_cast<uint64>(m_Duration);
-		}
-	}=09
-}
-
-bool MatroskaAudioParser::FindEditionUID(uint64 uid)
-{
-	for (uint32 c =3D 0; c < m_Editions.size(); c++) {
-		MatroskaEditionInfo &currentEdition =3D m_Editions.at(c);=09
-		if (currentEdition.editionUID =3D=3D uid)
-			return true;
-	}=09
-	return false;
-}
-
-bool MatroskaAudioParser::FindChapterUID(uint64 uid)
-{
-	for (uint32 c =3D 0; c < m_Chapters.size(); c++) {
-		MatroskaChapterInfo &currentChapter =3D m_Chapters.at(c);=09
-		if (currentChapter.chapterUID =3D=3D uid)
-			return true;
-	}=09
-	return false;
-}
-
-void PrintChapters(std::vector<MatroskaChapterInfo> &theChapters)=20
-{
-	for (uint32 c =3D 0; c < theChapters.size(); c++) {
-		MatroskaChapterInfo &currentChapter =3D theChapters.at(c);=09
-		NOTE2("Chapter %u, UID: %u", c, (uint32)currentChapter.chapterUID);
-		NOTE1("\tStart Time: %u", (uint32)currentChapter.timeStart);
-		NOTE1("\tEnd Time: %u", (uint32)currentChapter.timeEnd);
-		for (uint32 d =3D 0; d < currentChapter.display.size(); d++) {
-			NOTE3("\tDisplay %u, String: %s Lang: %s", d, currentChapter.display.=
at(d).string.GetUTF8().c_str(), currentChapter.display.at(d).lang.c_str()=
);
-		}
-		for (uint32 t =3D 0; t < currentChapter.tracks.size(); t++) {
-			NOTE2("\tTrack %u, UID: %%u", t, (uint32)currentChapter.tracks.at(t))=
;
-		}
-
-	}
-};
-
-bool MatroskaSearch::Skip()
-{
-	int j;
-
-	for (j =3D 0; j < SEARCH_TABLE_SIZE; j++) skip[j] =3D SEARCH_PATTERN_SI=
ZE;
-	for (j =3D 0; j < SEARCH_PATTERN_SIZE - 1; j++)
-		skip[pattern[j] & 0x00ff] =3D SEARCH_PATTERN_SIZE-1-j;
-	return true;
-}
-
-bool MatroskaSearch::Next()
-{
-	int  j, k, s;
-	int  *g;
-
-	if ((g =3D (int *)malloc(sizeof(int)*SEARCH_PATTERN_SIZE)) =3D=3D NULL)=
 return false;
-	for (j =3D 0; j < SEARCH_PATTERN_SIZE; j++) next[j] =3D 2*SEARCH_PATTER=
N_SIZE - 1 - j;
-	j =3D SEARCH_PATTERN_SIZE;
-	for (k =3D SEARCH_PATTERN_SIZE - 1; k >=3D 0; k--) {
-		g[k] =3D j;
-		while (j !=3D SEARCH_PATTERN_SIZE && pattern[j] !=3D pattern[k]) {
-			next[j] =3D (next[j] <=3D SEARCH_PATTERN_SIZE-1-k) ? next[j] : SEARCH=
_PATTERN_SIZE-1-k;
-			j =3D g[j];
-		}
-		j--;
-	}
-	s =3D j;
-	for (j =3D 0; j < SEARCH_PATTERN_SIZE; j++) {
-		next[j] =3D (next[j] <=3D s+SEARCH_PATTERN_SIZE-j) ? next[j] : s+SEARC=
H_PATTERN_SIZE-j;
-		if (j >=3D s) s =3D g[s];
-	}
-	free(g);
-	return true;
-}
-
-int MatroskaSearch::Match(unsigned int start)
-{
-	int i, j;
-
-	i =3D SEARCH_PATTERN_SIZE - 1 + start;
-	while (i < SEARCH_SOURCE_SIZE) {
-		j =3D SEARCH_PATTERN_SIZE - 1;
-		while (j >=3D 0 && source[i] =3D=3D pattern[j]) {
-			i--;
-			j--;
-		}
-		if (j < 0) return i + 1;
-		if (skip[source[i] & 0x00ff] >=3D next[j])
-			i +=3D skip[source[i] & 0x00ff];
-		else i +=3D next[j];
-	}
-	return -1;
+/*
+ *  Part of the foobar2000 Matroska plugin
+ *
+ *  Copyright (C) Jory 'jcsston' Stone (jcsston at toughguy net) - 2003-=
2004
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING =
THE
+ *  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PUR=
POSE.
+ *
+ */
+
+/*!
+    \file matroska_parser.cpp
+		\version $Id$
+    \brief An audio slated Matroska Reader+Parser
+		\author Jory Stone     <jcsston @ toughguy.net>
+*/
+
+#include "matroska_parser.h"
+
+#include <string>
+using std::string;
+
+using namespace LIBEBML_NAMESPACE;=09
+using namespace LIBMATROSKA_NAMESPACE;
+
+static const char * rg_fields[]=3D
+{
+	"REPLAYGAIN_GAIN",
+	"REPLAYGAIN_PEAK"
+};
+
+static const char * rg_track_fields[]=3D
+{
+	"REPLAYGAIN_TRACK_GAIN",
+	"REPLAYGAIN_TRACK_PEAK"
+};
+
+static const char * rg_album_fields[]=3D
+{
+	"REPLAYGAIN_ALBUM_GAIN",
+	"REPLAYGAIN_ALBUM_PEAK"
+};
+
+#define MATROSKA_TAG_IDX 0
+#define FOOBAR2K_TAG_IDX 1
+
+static const char * chapter_tag_mapping[][2] =3D
+{
+	{ "PART_NUMBER", "TRACKNUMBER" },
+	{ "DATE_RELEASED", "DATE" },
+    //{ "LEAD_PERFORMER", "PERFORMER" },
+    //{ "ACCOMPANIMENT", "BAND" },
+    //{ "LYRICIST", "WRITER" }
+};
+
+static const char * edition_tag_mapping[][2] =3D
+{
+	{ "TITLE", "ALBUM" },
+	{ "CATALOG_NUMBER", "CATALOG" },
+    { "TOTAL_PARTS", "TOTALTRACKS" },
+    //{ "PART_NUMBER", "DISCNUMBER" },
+    //{ "TOTAL_DISCS", "TOTALDISCS" }
+};
+
+static const char * hidden_edition_field[] =3D
+{
+	"___DUMMY___",
+};
+
+static const char * hidden_chapter_field[] =3D
+{
+	"CDAUDIO_TRACK_FLAGS",
+};
+
+bool starts_with(const string &s, const char *start) {
+  return strncmp(s.c_str(), start, strlen(start)) =3D=3D 0;
+};
+
+uint64 MatroskaAudioParser::SecondsToTimecode(double seconds)
+{
+	return (uint64)floor(seconds * 1000000000);
+};
+
+double MatroskaAudioParser::TimecodeToSeconds(uint64 code,unsigned sampl=
erate_hint)
+{
+	return ((double)(int64)code / 1000000000);
+};
+
+
+MatroskaAudioFrame::MatroskaAudioFrame()=20
+{
+	timecode =3D 0;
+	duration =3D 0;
+    add_id =3D 0;
+};
+
+MatroskaAttachment::MatroskaAttachment()
+{
+	FileName =3D L"";
+	MimeType =3D "";
+	Description =3D L"";
+	SourceFilename =3D L"";
+	SourceStartPos =3D 0;
+	SourceDataLength =3D 0;
+};
+
+void MatroskaAudioFrame::Reset()
+{
+	timecode =3D 0;
+	duration =3D 0;
+    add_id =3D 0;
+};
+
+MatroskaSimpleTag::MatroskaSimpleTag()
+{
+	name =3D L"";
+	value =3D L"";
+	language =3D "und";
+	defaultFlag =3D 1;
+	hidden =3D false;
+	removalPending =3D false;
+};
+
+MatroskaTagInfo::MatroskaTagInfo()
+{
+	targetTrackUID =3D 0;
+	targetEditionUID =3D 0;
+	targetChapterUID =3D 0;
+	targetAttachmentUID =3D 0;
+	targetTypeValue =3D 0;
+};
+
+void MatroskaTagInfo::SetTagValue(const char *name, const char *value, i=
nt index)
+{
+	for (size_t s =3D 0; s < tags.size(); s++)
+	{
+		MatroskaSimpleTag &currentSimpleTag =3D tags.at(s);
+		if (strcmpi(currentSimpleTag.name.GetUTF8().c_str(), name) =3D=3D 0)		=
=09
+		{
+			if(index =3D=3D 0)
+			{
+				currentSimpleTag.value.SetUTF8(value);
+				currentSimpleTag.removalPending =3D false;
+				return;
+			}
+			index--;
+		}
+	}
+
+	// If we are here then we didn't find this tag in the vector already
+	MatroskaSimpleTag newSimpleTag;
+	newSimpleTag.name.SetUTF8(name);
+	newSimpleTag.value.SetUTF8(value);=09
+	newSimpleTag.removalPending =3D false;
+	tags.push_back(newSimpleTag);
+};
+
+void MatroskaTagInfo::RemoveMarkedTags()
+{
+	for (int i =3D tags.size()-1; i >=3D 0; i--)
+	{
+		MatroskaSimpleTag &simpleTag =3D tags.at(i);
+		if(simpleTag.removalPending =3D=3D true)
+		{
+			tags.erase(tags.begin() + i);
+		}
+	}
+}
+
+void MatroskaTagInfo::MarkAllAsRemovalPending()
+{
+	for (int i =3D tags.size()-1; i >=3D 0; i--)
+	{
+		MatroskaSimpleTag &simpleTag =3D tags.at(i);
+		simpleTag.removalPending =3D true;
+	}
+}
+
+MatroskaChapterDisplayInfo::MatroskaChapterDisplayInfo()  {
+	string =3D L"";
+};
+
+MatroskaChapterInfo::MatroskaChapterInfo() {
+	chapterUID =3D 0;
+	timeStart =3D 0;
+	timeEnd =3D 0;
+}
+
+MatroskaEditionInfo::MatroskaEditionInfo() {
+	editionUID =3D 0;
+}
+
+MatroskaTrackInfo::MatroskaTrackInfo() {
+	trackNumber =3D 0;
+	trackUID =3D 0;	=09
+	duration =3D 0;
+
+	channels =3D 1;
+	samplesPerSec =3D 0;
+	samplesOutputPerSec =3D 0;
+	bitsPerSample =3D 0;
+	avgBytesPerSec =3D 0;
+	defaultDuration =3D 0;
+
+	name =3D L"";
+
+	codecPrivateReady =3D false;
+};
+
+MatroskaAudioParser::MatroskaAudioParser(service_ptr_t<file> input, abor=
t_callback & p_abort)=20
+	: m_IOCallback(input, p_abort),
+		m_InputStream(m_IOCallback)
+{
+	m_TimecodeScale =3D TIMECODE_SCALE;
+	m_FileDate =3D 0;
+	m_Duration =3D 0;
+	m_CurrentTimecode =3D 0;
+	//m_ElementLevel0 =3D NULL;
+	//UpperElementLevel =3D 0;
+	m_CurrentEdition =3D 0;
+	m_CurrentChapter =3D 0;
+	m_FileSize =3D input->get_size(p_abort);
+	m_TagPos =3D 0;
+	m_TagSize =3D 0;
+	m_TagScanRange =3D 1024 * 64;
+	m_CurrentTrackNo =3D 0;
+};
+
+MatroskaAudioParser::~MatroskaAudioParser() {
+	//if (m_ElementLevel0 !=3D NULL)
+	//	_DELETE(m_ElementLevel0);
+		//delete m_ElementLevel0;
+=09
+	while (!m_Queue.empty()) {
+		MatroskaAudioFrame *currentPacket =3D m_Queue.front();
+		//delete currentPacket;
+		_DELETE(currentPacket);
+		m_Queue.pop();
+	}
+};
+
+int MatroskaAudioParser::Parse(bool bInfoOnly, bool bBreakAtClusters)=20
+{
+	try {
+		int UpperElementLevel =3D 0;
+		bool bAllowDummy =3D false;
+		// Elements for different levels
+		ElementPtr ElementLevel1;
+		ElementPtr ElementLevel2;
+		ElementPtr ElementLevel3;
+		ElementPtr ElementLevel4;
+		ElementPtr ElementLevel5;
+		ElementPtr NullElement;
+
+		// Be sure we are at the beginning of the file
+		m_IOCallback.setFilePointer(0);
+		// Find the EbmlHead element. Must be the first one.
+		m_ElementLevel0 =3D ElementPtr(m_InputStream.FindNextID(EbmlHead::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
+		if (m_ElementLevel0 =3D=3D NullElement) {
+			return 1;
+		}
+		//We must have found the EBML head :)
+		m_ElementLevel0->SkipData(m_InputStream, m_ElementLevel0->Generic().Co=
ntext);
+		//delete m_ElementLevel0;
+		//_DELETE(m_ElementLevel0);
+
+		// Next element must be a segment
+		m_ElementLevel0 =3D ElementPtr(m_InputStream.FindNextID(KaxSegment::Cl=
assInfos, 0xFFFFFFFFFFFFFFFFL));
+		if (m_ElementLevel0 =3D=3D NullElement) {
+			//No segment/level 0 element found.
+			return 1;
+		}
+		if (!(EbmlId(*m_ElementLevel0) =3D=3D KaxSegment::ClassInfos.GlobalId)=
) {
+			//delete m_ElementLevel0;
+			//m_ElementLevel0 =3D NULL;
+			//_DELETE(m_ElementLevel0);
+			return 1;
+		}
+
+		UpperElementLevel =3D 0;
+		// We've got our segment, so let's find the tracks
+		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextElement(m_ElementLe=
vel0->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1)=
);
+		while (ElementLevel1 !=3D NullElement) {
+			if (UpperElementLevel > 0) {
+				break;
+			}
+			if (UpperElementLevel < 0) {
+				UpperElementLevel =3D 0;
+			}
+
+			if (EbmlId(*ElementLevel1) =3D=3D KaxSeekHead::ClassInfos.GlobalId) {
+				if (m_IOCallback.seekable()) {
+					Parse_MetaSeek(ElementLevel1, bInfoOnly);
+					if (m_TagPos =3D=3D 0) {
+						// Search for them at the end of the file
+						if (m_TagScanRange > 0)
+						{
+							m_IOCallback.setFilePointer(m_FileSize - m_TagScanRange);
+							uint64 init_pos =3D m_IOCallback.getFilePointer();
+							/*
+								BM Search
+							*/
+							binary buf[1024*64];
+							binary pat[3]; pat[0] =3D 0x54; pat[1] =3D 0xc3; pat[2] =3D 0x67;
+							uint64 s_pos =3D m_IOCallback.getFilePointer();
+							m_IOCallback.read(buf, m_TagScanRange);
+							MatroskaSearch search(buf, pat);
+							int pos =3D search.Match();
+							if (pos !=3D -1) {
+								do {
+									m_IOCallback.setFilePointer(s_pos+pos+3);
+									uint64 startPos =3D m_IOCallback.getFilePointer();
+									m_IOCallback.setFilePointer(-4, seek_current);
+									ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextID=
(KaxTags::ClassInfos, 0xFFFFFFFFFFFFFFFFL));
+									if ((levelUnknown !=3D NullElement)=20
+										&& (m_FileSize >=3D startPos + levelUnknown->GetSize())=20
+										&& (EbmlId(*levelUnknown) =3D=3D KaxTags::ClassInfos.GlobalId)=
)
+									{
+										Parse_Tags(static_cast<KaxTags *>(levelUnknown.get()));
+										break;
+									}
+									m_IOCallback.setFilePointer(s_pos);
+									pos =3D search.Match(pos+1);
+								} while (pos !=3D -1);
+								/*
+									~BM Search
+								*/
+							} else {
+								m_IOCallback.setFilePointer(init_pos);
+								binary Buffer[4];
+								while (m_IOCallback.read(Buffer, 3) >=3D 3)
+								{//0x18
+									if ((Buffer[0] =3D=3D 0x54) && (Buffer[1] =3D=3D 0xc3) && (Buff=
er[2] =3D=3D 0x67))
+									{
+										uint64 startPos =3D m_IOCallback.getFilePointer();
+
+										//seek back 3 bytes, so libmatroska can find the Tags element =
Ebml ID
+										m_IOCallback.setFilePointer(-4, seek_current);
+
+										ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextI=
D(KaxTags::ClassInfos, 0xFFFFFFFFFFFFFFFFL));
+										if ((levelUnknown !=3D NullElement)=20
+											&& (m_FileSize >=3D startPos + levelUnknown->GetSize())=20
+											&& (EbmlId(*levelUnknown) =3D=3D KaxTags::ClassInfos.GlobalId=
))
+										{
+											Parse_Tags(static_cast<KaxTags *>(levelUnknown.get()));
+											//_DELETE(levelUnknown);
+											break;
+										}
+										//_DELETE(levelUnknown);
+
+										//Restore the file pos
+										m_IOCallback.setFilePointer(startPos);
+									}
+									//seek back 2 bytes
+									m_IOCallback.setFilePointer(-2, seek_current);
+								}
+							}
+						} else {
+							//m_TagPos =3D m_FileSize;
+						}
+					}
+				}
+			}else if (EbmlId(*ElementLevel1) =3D=3D KaxInfo::ClassInfos.GlobalId)=
 {
+				// General info about this Matroska file
+				ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLe=
vel1->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, bAllowDu=
mmy));
+				while (ElementLevel2 !=3D NullElement) {
+					if (UpperElementLevel > 0) {
+						break;
+					}
+					if (UpperElementLevel < 0) {
+						UpperElementLevel =3D 0;
+					}
+
+					if (EbmlId(*ElementLevel2) =3D=3D KaxTimecodeScale::ClassInfos.Glob=
alId) {
+						KaxTimecodeScale &TimeScale =3D *static_cast<KaxTimecodeScale *>(E=
lementLevel2.get());
+						TimeScale.ReadData(m_InputStream.I_O());
+
+						//matroskaGlobalTrack->SetTimecodeScale(uint64(TimeScale));
+						m_TimecodeScale =3D uint64(TimeScale);
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxDuration::ClassInfos.Gl=
obalId) {
+						KaxDuration &duration =3D *static_cast<KaxDuration *>(ElementLevel=
2.get());
+						duration.ReadData(m_InputStream.I_O());
+
+						// it's in milliseconds? -- in nanoseconds.
+						m_Duration =3D double(duration) * m_TimecodeScale;
+
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxDateUTC::ClassInfos.Glo=
balId) {
+						KaxDateUTC & DateUTC =3D *static_cast<KaxDateUTC *>(ElementLevel2.=
get());
+						DateUTC.ReadData(m_InputStream.I_O());
+					=09
+						m_FileDate =3D DateUTC.GetEpochDate();
+
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxSegmentFilename::ClassI=
nfos.GlobalId) {
+						KaxSegmentFilename &tag_SegmentFilename =3D *static_cast<KaxSegmen=
tFilename *>(ElementLevel2.get());
+						tag_SegmentFilename.ReadData(m_InputStream.I_O());
+
+						m_SegmentFilename =3D *static_cast<EbmlUnicodeString *>(&tag_Segme=
ntFilename);
+
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxMuxingApp::ClassInfos.G=
lobalId)	{
+						KaxMuxingApp &tag_MuxingApp =3D *static_cast<KaxMuxingApp *>(Eleme=
ntLevel2.get());
+						tag_MuxingApp.ReadData(m_InputStream.I_O());
+
+						m_MuxingApp =3D *static_cast<EbmlUnicodeString *>(&tag_MuxingApp);
+
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxWritingApp::ClassInfos.=
GlobalId) {
+						KaxWritingApp &tag_WritingApp =3D *static_cast<KaxWritingApp *>(El=
ementLevel2.get());
+						tag_WritingApp.ReadData(m_InputStream.I_O());
+					=09
+						m_WritingApp =3D *static_cast<EbmlUnicodeString *>(&tag_WritingApp=
);
+
+					} else if (EbmlId(*ElementLevel2) =3D=3D KaxTitle::ClassInfos.Globa=
lId) {
+						KaxTitle &Title =3D *static_cast<KaxTitle*>(ElementLevel2.get());
+						Title.ReadData(m_InputStream.I_O());
+						m_FileTitle =3D UTFstring(Title).c_str();
+					}
+
+					if (UpperElementLevel > 0) {	// we're coming from ElementLevel3
+						UpperElementLevel--;
+						//delete ElementLevel2;
+						ElementLevel2 =3D ElementLevel3;
+						if (UpperElementLevel > 0)
+							break;
+					} else {
+						ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Co=
ntext);
+						//delete ElementLevel2;
+						//_DELETE(ElementLevel2);
+						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, bAllow=
Dummy));
+					}
+				}
+			}else if (EbmlId(*ElementLevel1) =3D=3D KaxChapters::ClassInfos.Globa=
lId) {
+				Parse_Chapters(static_cast<KaxChapters *>(ElementLevel1.get()));
+			}else if (EbmlId(*ElementLevel1) =3D=3D KaxTags::ClassInfos.GlobalId)=
 {
+				Parse_Tags(static_cast<KaxTags *>(ElementLevel1.get()));
+			} else if (EbmlId(*ElementLevel1) =3D=3D KaxTracks::ClassInfos.Global=
Id) {
+				// Yep, we've found our KaxTracks element. Now find all tracks
+				// contained in this segment.=20
+				KaxTracks *Tracks =3D static_cast<KaxTracks *>(ElementLevel1.get());
+				EbmlElement* tmpElement =3D ElementLevel2.get();
+				Tracks->Read(m_InputStream, KaxTracks::ClassInfos.Context, UpperElem=
entLevel, tmpElement, bAllowDummy);
+
+				unsigned int Index0;
+				for (Index0 =3D 0; Index0 < Tracks->ListSize(); Index0++) {
+					if ((*Tracks)[Index0]->Generic().GlobalId =3D=3D KaxTrackEntry::Cla=
ssInfos.GlobalId) {
+						KaxTrackEntry &TrackEntry =3D *static_cast<KaxTrackEntry *>((*Trac=
ks)[Index0]);
+						// Create a new MatroskaTrack
+						MatroskaTrackInfo newTrack;
+					=09
+						unsigned int Index1;
+						for (Index1 =3D 0; Index1 < TrackEntry.ListSize(); Index1++) {
+							if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrackNumber:=
:ClassInfos.GlobalId) {
+								KaxTrackNumber &TrackNumber =3D *static_cast<KaxTrackNumber*>(Tr=
ackEntry[Index1]);
+								newTrack.trackNumber =3D TrackNumber;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
UID::ClassInfos.GlobalId) {
+								KaxTrackUID &TrackUID =3D *static_cast<KaxTrackUID*>(TrackEntry[=
Index1]);
+								newTrack.trackUID =3D TrackUID;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Type::ClassInfos.GlobalId) {
+								KaxTrackType &TrackType =3D *static_cast<KaxTrackType*>(TrackEnt=
ry[Index1]);
+								if (uint8(TrackType) !=3D track_audio) {
+									newTrack.trackNumber =3D 0xFFFF;
+									break;
+								}
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
TimecodeScale::ClassInfos.GlobalId) {
+								KaxTrackTimecodeScale &TrackTimecodeScale =3D *static_cast<KaxTr=
ackTimecodeScale*>(TrackEntry[Index1]);
+								// TODO: Support Tracks with different timecode scales?
+								//newTrack->TrackTimecodeScale =3D TrackTimecodeScale;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
DefaultDuration::ClassInfos.GlobalId) {
+								KaxTrackDefaultDuration &TrackDefaultDuration =3D *static_cast<K=
axTrackDefaultDuration*>(TrackEntry[Index1]);
+								newTrack.defaultDuration =3D uint64(TrackDefaultDuration);
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxCodec=
ID::ClassInfos.GlobalId) {
+								KaxCodecID &CodecID =3D *static_cast<KaxCodecID*>(TrackEntry[Ind=
ex1]);
+								newTrack.codecID =3D std::string(CodecID);
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxCodec=
Private::ClassInfos.GlobalId) {
+								KaxCodecPrivate &CodecPrivate =3D *static_cast<KaxCodecPrivate*>=
(TrackEntry[Index1]);
+								newTrack.codecPrivate.resize(CodecPrivate.GetSize());							=09
+								memcpy(&newTrack.codecPrivate[0], CodecPrivate.GetBuffer(), Code=
cPrivate.GetSize());
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagDefault::ClassInfos.GlobalId) {
+								KaxTrackFlagDefault &TrackFlagDefault =3D *static_cast<KaxTrackF=
lagDefault*>(TrackEntry[Index1]);
+								//newTrack->FlagDefault =3D TrackFlagDefault;
+							/* Matroska2
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagEnabled::ClassInfos.GlobalId) {
+								KaxTrackFlagEnabled &TrackFlagEnabled =3D *static_cast<KaxTrackF=
lagEnabled*>(TrackEntry[Index1]);
+								//newTrack->FlagEnabled =3D TrackFlagEnabled;
+							*/
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
FlagLacing::ClassInfos.GlobalId) {
+								KaxTrackFlagLacing &TrackFlagLacing =3D *static_cast<KaxTrackFla=
gLacing*>(TrackEntry[Index1]);
+								//newTrack->FlagLacing =3D TrackFlagLacing;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Language::ClassInfos.GlobalId) {
+								KaxTrackLanguage &TrackLanguage =3D *static_cast<KaxTrackLanguag=
e*>(TrackEntry[Index1]);
+								newTrack.language =3D std::string(TrackLanguage);
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
MaxCache::ClassInfos.GlobalId) {
+								KaxTrackMaxCache &TrackMaxCache =3D *static_cast<KaxTrackMaxCach=
e*>(TrackEntry[Index1]);
+								//newTrack->MaxCache =3D TrackMaxCache;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
MinCache::ClassInfos.GlobalId) {
+								KaxTrackMinCache &TrackMinCache =3D *static_cast<KaxTrackMinCach=
e*>(TrackEntry[Index1]);
+								//newTrack->MinCache =3D TrackMinCache;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Name::ClassInfos.GlobalId) {
+								KaxTrackName &TrackName =3D *static_cast<KaxTrackName*>(TrackEnt=
ry[Index1]);
+								newTrack.name =3D TrackName;
+
+							} else if (TrackEntry[Index1]->Generic().GlobalId =3D=3D KaxTrack=
Audio::ClassInfos.GlobalId) {
+								KaxTrackAudio &TrackAudio =3D *static_cast<KaxTrackAudio*>(Track=
Entry[Index1]);
+
+								unsigned int Index2;
+								for (Index2 =3D 0; Index2 < TrackAudio.ListSize(); Index2++) {
+									if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAudioBitDe=
pth::ClassInfos.GlobalId) {
+										KaxAudioBitDepth &AudioBitDepth =3D *static_cast<KaxAudioBitDe=
pth*>(TrackAudio[Index2]);
+										newTrack.bitsPerSample =3D AudioBitDepth;
+									/* Matroska2
+									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioPosition::ClassInfos.GlobalId) {
+										KaxAudioPosition &AudioPosition =3D *static_cast<KaxAudioPosit=
ion*>(TrackAudio[Index2]);
+
+										// TODO: Support multi-channel?
+										//newTrack->audio->ChannelPositionSize =3D AudioPosition.GetSi=
ze();
+										//newTrack->audio->ChannelPosition =3D new binary[AudioPositio=
n.GetSize()+1];
+										//memcpy(newTrack->audio->ChannelPosition, AudioPosition.GetBu=
ffer(), AudioPosition.GetSize());
+									*/
+									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioChannels::ClassInfos.GlobalId) {
+										KaxAudioChannels &AudioChannels =3D *static_cast<KaxAudioChann=
els*>(TrackAudio[Index2]);
+										newTrack.channels =3D AudioChannels;
+
+									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioOutputSamplingFreq::ClassInfos.GlobalId) {
+										KaxAudioOutputSamplingFreq &AudioOutputSamplingFreq =3D *stati=
c_cast<KaxAudioOutputSamplingFreq*>(TrackAudio[Index2]);
+										newTrack.samplesOutputPerSec =3D AudioOutputSamplingFreq;
+
+									} else if (TrackAudio[Index2]->Generic().GlobalId =3D=3D KaxAud=
ioSamplingFreq::ClassInfos.GlobalId) {
+										KaxAudioSamplingFreq &AudioSamplingFreq =3D *static_cast<KaxAu=
dioSamplingFreq*>(TrackAudio[Index2]);
+										newTrack.samplesPerSec =3D AudioSamplingFreq;
+									}
+								}
+							}
+						}
+						if (newTrack.trackNumber !=3D 0xFFFF)
+							m_Tracks.push_back(newTrack);
+					}
+				}
+			} else if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.Globa=
lId) {
+				if (bBreakAtClusters) {
+					m_IOCallback.setFilePointer(ElementLevel1->GetElementPosition());
+					//delete ElementLevel1;
+					//ElementLevel1 =3D NULL;
+					//_DELETE(ElementLevel1);
+					break;
+				}
+			} else if (EbmlId(*ElementLevel1) =3D=3D KaxAttachments::ClassInfos.G=
lobalId) {
+				// Yep, we've found our KaxAttachment element. Now find all attached=
 files
+				// contained in this segment.
+#if 1
+				ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLe=
vel1->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
+				while (ElementLevel2 !=3D NullElement) {
+					if (UpperElementLevel > 0) {
+						break;
+					}
+					if (UpperElementLevel < 0) {
+						UpperElementLevel =3D 0;
+					}
+					if (EbmlId(*ElementLevel2) =3D=3D KaxAttached::ClassInfos.GlobalId)=
 {
+						// We actually found a attached file entry :D
+						MatroskaAttachment newAttachment;
+
+						ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level2->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
+						while (ElementLevel3 !=3D NullElement) {
+							if (UpperElementLevel > 0) {
+								break;
+							}
+							if (UpperElementLevel < 0) {
+								UpperElementLevel =3D 0;
+							}
+
+							// Now evaluate the data belonging to this track
+							if (EbmlId(*ElementLevel3) =3D=3D KaxFileName::ClassInfos.GlobalI=
d) {
+								KaxFileName &attached_filename =3D *static_cast<KaxFileName *>(E=
lementLevel3.get());
+								attached_filename.ReadData(m_InputStream.I_O());
+								newAttachment.FileName =3D UTFstring(attached_filename);
+
+							} else if (EbmlId(*ElementLevel3) =3D=3D KaxMimeType::ClassInfos.=
GlobalId) {
+								KaxMimeType &attached_mime_type =3D *static_cast<KaxMimeType *>(=
ElementLevel3.get());
+								attached_mime_type.ReadData(m_InputStream.I_O());
+								newAttachment.MimeType =3D std::string(attached_mime_type);
+
+							} else if (EbmlId(*ElementLevel3) =3D=3D KaxFileDescription::Clas=
sInfos.GlobalId) {
+								KaxFileDescription &attached_description =3D *static_cast<KaxFil=
eDescription *>(ElementLevel3.get());
+								attached_description.ReadData(m_InputStream.I_O());
+								newAttachment.Description =3D UTFstring(attached_description);
+
+							} else if (EbmlId(*ElementLevel3) =3D=3D KaxFileData::ClassInfos.=
GlobalId) {
+								KaxFileData &attached_data =3D *static_cast<KaxFileData *>(Eleme=
ntLevel3.get());
+
+								//We don't what to read the data into memory because it could be=
 very large
+								//attached_data.ReadData(m_InputStream.I_O());
+
+								//Instead we store the Matroska filename, the start of the data =
and the length, so we can read it
+								//later at the users request. IMHO This will save a lot of memor=
y
+								newAttachment.SourceStartPos =3D attached_data.GetElementPositio=
n() + attached_data.HeadSize();
+								newAttachment.SourceDataLength =3D attached_data.GetSize();
+							}
+
+							if (UpperElementLevel > 0) {	// we're coming from ElementLevel4
+								UpperElementLevel--;
+								ElementLevel3 =3D ElementLevel4;
+								if (UpperElementLevel > 0)
+									break;
+							} else {
+								ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().=
Context);
+								ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Eleme=
ntLevel2->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
+							}				=09
+						} // while (ElementLevel3 !=3D NULL)
+						//m_AttachmentList.push_back(newAttachment);
+                        m_AttachmentList.add_item(newAttachment);
+					}
+
+					if (UpperElementLevel > 0) {	// we're coming from ElementLevel3
+						UpperElementLevel--;
+						ElementLevel2 =3D ElementLevel3;
+						if (UpperElementLevel > 0)
+							break;
+					} else {
+						ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Co=
ntext);
+						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, 0xFFFFFFFFL, true, 1));
+					}
+				} // while (ElementLevel2 !=3D NULL)
+#endif
+			}
+		=09
+			if (UpperElementLevel > 0) {		// we're coming from ElementLevel2
+				UpperElementLevel--;
+				//delete ElementLevel1;
+				//_DELETE(ElementLevel1);
+				ElementLevel1 =3D ElementLevel2;
+				if (UpperElementLevel > 0)
+					break;
+			} else {
+				ElementLevel1->SkipData(m_InputStream, ElementLevel1->Generic().Cont=
ext);
+				//delete ElementLevel1;
+				//ElementLevel1 =3D NULL;
+				//_DELETE(ElementLevel1);
+
+				ElementLevel1 =3D ElementPtr(m_InputStream.FindNextElement(m_Element=
Level0->Generic().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, =
1));
+			}
+		} // while (ElementLevel1 !=3D NULL)
+		//_DELETE(ElementLevel3);
+		//_DELETE(ElementLevel2);
+		//_DELETE(ElementLevel1);
+	} catch (std::exception &) {
+		return 1;
+
+	} catch (...) {
+		return 1;
+	}
+
+	CountClusters();
+	return 0;
+};
+
+//int MatroskaAudioParser::WriteTags(const file_info & info)
+int MatroskaAudioParser::WriteTags()
+{
+	KaxTags & MyKaxTags =3D GetChild<KaxTags>(*static_cast<EbmlMaster *>(m_=
ElementLevel0.get()));
+
+	// On to writing :)
+	if (m_TagPos =3D=3D 0) {
+		// Ok, we need to append the tags onto the end of the file, no existin=
g tag element
+		m_TagPos =3D m_FileSize;
+	} else {
+	=09
+	}=09
+
+	//Start going through the list and adding tags
+	KaxTag *MyKaxTag_last =3D NULL;
+	for(size_t current_tag_track =3D 0; current_tag_track < m_Tags.size(); =
current_tag_track++) {
+		KaxTag *MyKaxTag =3D NULL;
+		if (MyKaxTag_last !=3D NULL)
+		{
+			MyKaxTag =3D &GetNextChild<KaxTag>(MyKaxTags, *MyKaxTag_last);
+			MyKaxTag_last =3D MyKaxTag;
+		}else {
+			MyKaxTag =3D &GetChild<KaxTag>(MyKaxTags);
+			MyKaxTag_last =3D MyKaxTag;
+		}
+		MatroskaTagInfo &currentTag =3D m_Tags.at(current_tag_track);
+		//The Targets group
+		KaxTagTargets & MyKaxTagTargets =3D GetChild<KaxTagTargets>(*MyKaxTag)=
;
+		if (currentTag.targetTrackUID !=3D 0) {
+			KaxTagTrackUID & MyKaxTagTrackUID =3D GetChild<KaxTagTrackUID>(MyKaxT=
agTargets);
+			*static_cast<EbmlUInteger *>(&MyKaxTagTrackUID) =3D currentTag.target=
TrackUID;
+		}
+		if (currentTag.targetEditionUID !=3D 0) {
+			KaxTagEditionUID & MyKaxTagEditionUID =3D GetChild<KaxTagEditionUID>(=
MyKaxTagTargets);
+			*static_cast<EbmlUInteger *>(&MyKaxTagEditionUID) =3D currentTag.targ=
etEditionUID;
+		}
+		if (currentTag.targetChapterUID !=3D 0) {
+			KaxTagChapterUID & MyKaxTagChapterUID =3D GetChild<KaxTagChapterUID>(=
MyKaxTagTargets);
+			*static_cast<EbmlUInteger *>(&MyKaxTagChapterUID) =3D currentTag.targ=
etChapterUID;
+		}
+		if (currentTag.targetAttachmentUID !=3D 0) {
+			KaxTagAttachmentUID & MyKaxTagAttachmentUID =3D GetChild<KaxTagAttach=
mentUID>(MyKaxTagTargets);
+			*static_cast<EbmlUInteger *>(&MyKaxTagAttachmentUID) =3D currentTag.t=
argetAttachmentUID;
+		}
+		if(currentTag.targetTypeValue !=3D 0) {
+			KaxTagTargetTypeValue& MyKaxTagTargetTypeValue =3D GetChild<KaxTagTar=
getTypeValue>(MyKaxTagTargets);
+			*static_cast<EbmlUInteger *>(&MyKaxTagTargetTypeValue) =3D currentTag=
.targetTypeValue;
+			if(!currentTag.targetType.empty())
+			{
+				KaxTagTargetType& MyKaxTagTargetType =3D GetChild<KaxTagTargetType>(=
MyKaxTagTargets);
+				*static_cast<EbmlString *>(&MyKaxTagTargetType) =3D currentTag.targe=
tType;			=09
+			}
+		}
+	=09
+		// Add the millions of simple tags we can have ;)
+		KaxTagSimple *MySimpleTag_last =3D NULL;
+		for(size_t st =3D 0; st < currentTag.tags.size(); st++) {
+			KaxTagSimple *MySimpleTag =3D NULL;
+			if (MySimpleTag_last !=3D NULL)
+			{
+				MySimpleTag =3D &GetNextChild<KaxTagSimple>(*MyKaxTag, *MySimpleTag_=
last);
+				MySimpleTag_last =3D MySimpleTag;
+			}else {
+				MySimpleTag =3D &GetChild<KaxTagSimple>(*MyKaxTag);
+				MySimpleTag_last =3D MySimpleTag;
+			}
+			MatroskaSimpleTag &currentSimpleTag =3D currentTag.tags.at(st);
+
+			KaxTagName & MyKaxTagName =3D GetChild<KaxTagName>(*MySimpleTag);
+			*static_cast<EbmlUnicodeString *>(&MyKaxTagName) =3D currentSimpleTag=
.name;
+
+			KaxTagString & MyKaxTagString =3D GetChild<KaxTagString>(*MySimpleTag=
);
+			*static_cast<EbmlUnicodeString *>(&MyKaxTagString) =3D currentSimpleT=
ag.value;
+		=09
+			KaxTagLangue& MyKaxTagLangue =3D GetChild<KaxTagLangue>(*MySimpleTag)=
;
+			*static_cast<EbmlString *>(&MyKaxTagLangue) =3D currentSimpleTag.lang=
uage;
+
+			KaxTagDefault& MyKaxTagDefault =3D GetChild<KaxTagDefault>(*MySimpleT=
ag);
+			*static_cast<EbmlUInteger *>(&MyKaxTagDefault) =3D currentSimpleTag.d=
efaultFlag;		=09
+		}
+
+		m_IOCallback.setFilePointer(m_TagPos);
+		// Now we write the tags to the file
+		EbmlVoid & Dummy =3D GetChild<EbmlVoid>(*static_cast<EbmlMaster *>(m_E=
lementLevel0.get()));
+		uint64 size_of_tags =3D m_TagSize;
+		MyKaxTags.UpdateSize(true);
+		if (size_of_tags < MyKaxTags.GetSize())
+			size_of_tags =3D MyKaxTags.GetSize();
+
+		Dummy.SetSize(size_of_tags+8); // Size of the previous tag element
+		uint64 pos =3D m_IOCallback.getFilePointer();
+		if (pos =3D=3D 0)
+			//We don't want to overwrite the EBML header :P
+			return 2;
+		Dummy.Render(m_IOCallback);
+		m_IOCallback.setFilePointer(Dummy.GetElementPosition());
+		pos =3D m_IOCallback.getFilePointer();
+		if (pos =3D=3D 0)
+			//We don't want to overwrite the EBML header :P
+			return 2;
+
+		MyKaxTags.Render(m_IOCallback);
+	=09
+		//l0->UpdateSize(false, true);
+		std::auto_ptr<KaxSegment> new_segment(new KaxSegment);
+		KaxSegment * segment =3D (KaxSegment *)m_ElementLevel0.get();
+
+		m_IOCallback.setFilePointer(segment->GetElementPosition());
+		new_segment->WriteHead(m_IOCallback, segment->HeadSize() - 4);
+		m_IOCallback.setFilePointer(0, seek_end);
+		int ret =3D new_segment->ForceSize(m_IOCallback.getFilePointer() - seg=
ment->HeadSize() - segment->GetElementPosition());
+		if (!ret) {=20
+			segment->OverwriteHead(m_IOCallback);
+		      /*("Wrote the element at the end of the file but could "
+                      "not update the segment size. Therefore the elemen=
t "
+                      "will not be visible. Aborting the process. The fi=
le "
+                      "has been changed!")*/
+			m_IOCallback.setFilePointer(segment->HeadSize() - segment->GetElement=
Position());
+			m_IOCallback.truncate();
+
+			return 1;
+		} else {
+			new_segment->OverwriteHead(m_IOCallback);
+
+		}
+
+	}
+	return 0;
+};
+
+static const char* foobar2k_to_matroska_edition_tag(const char * name)
+{
+	if (!stricmp_utf8(name, "ALBUM"))
+		return "TITLE";
+	else if (!stricmp_utf8(name, "SUBALBUM"))
+		return "SUBTITLE";
+	else if (starts_with(name, "ALBUM ")) {
+		static char newname[255];
+		ZeroMemory(newname,255);
+		strncpy(newname,name+6,254);
+		name =3D newname;
+	}
+	for (int i =3D 0; i < tabsize(edition_tag_mapping); i++)
+		if (!stricmp_utf8(name, edition_tag_mapping[i][FOOBAR2K_TAG_IDX]))
+			return edition_tag_mapping[i][MATROSKA_TAG_IDX];
+	return name;
+}
+
+static const char* foobar2k_to_matroska_chapter_tag(const char * name)
+{
+	for (int i =3D 0; i < tabsize(chapter_tag_mapping); i++)
+		if (!stricmp_utf8(name, chapter_tag_mapping[i][FOOBAR2K_TAG_IDX]))
+			return chapter_tag_mapping[i][MATROSKA_TAG_IDX];
+		return name;
+}
+
+int meta_get_num(const file_info &info, const char* name, int idx)
+{
+	assert(pfc::is_valid_utf8(name));
+	int n, m =3D min(info.meta_get_count(), idx);
+	int rv =3D 0;
+	for(n=3D0; n<m; n++)
+	{
+		if (!stricmp_utf8(name, info.meta_enum_name(n)))
+			rv++;
+	}
+	return rv;
+}
+
+bool isEditionTag(const char * name) {
+	if (starts_with(name, "ALBUM") ||
+		starts_with(name, "SUBALBUM") ||
+		starts_with(name, "DISCID") ||
+		starts_with(name, "CATALOG"))
+	{
+		return true;
+	} else {
+		return false;
+	}
+}
+
+void MatroskaAudioParser::SetTags(const file_info &info)
+{
+	int i, idx;
+	const char *name, *value;=09
+
+	if (m_Chapters.size() =3D=3D 0)
+	{	=09
+		// No chapters, works on track
+		MatroskaTagInfo *trackTag;
+		trackTag =3D FindTagWithTrackUID(m_Tracks.at(m_CurrentTrackNo).trackUI=
D);
+		if (trackTag =3D=3D NULL) {
+			// The tag doesn't exist yet
+			MatroskaTagInfo tempTag;
+			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;
+			m_Tags.push_back(tempTag);
+			trackTag =3D &m_Tags.at(m_Tags.size()-1);
+		}
+		//if(trackTag->targetTypeValue =3D=3D 0)
+		//	trackTag->targetTypeValue =3D 50;
+        trackTag->targetTypeValue =3D 30;
+		trackTag->MarkAllAsRemovalPending();
+		int metaDataCount =3D info.meta_get_count();
+		for (i =3D 0; i < metaDataCount; i++)
+		{
+			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
+				name =3D info.meta_enum_name(i);
+				value =3D info.meta_enum_value(i, j);
+				//idx =3D meta_get_num(info, name, i);
+				idx =3D j;
+				name =3D foobar2k_to_matroska_chapter_tag(name);
+				if ((name !=3D NULL) && (value !=3D NULL)) {
+					trackTag->SetTagValue(name, value, idx);
+				}
+			}
+		}
+		// Add the replay_gain tags
+		replaygain_info rg =3D info.get_replaygain();
+		if (rg.is_track_gain_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_gain, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			trackTag->SetTagValue("REPLAYGAIN_GAIN", value);
+		if (rg.is_track_peak_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_peak, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			trackTag->SetTagValue("REPLAYGAIN_PEAK", value);
+		trackTag->RemoveMarkedTags();
+	}
+=09
+	// Set global track tags as album tags
+	if ((m_Chapters.size() > 0) && (m_CurrentChapter !=3D NULL))
+	{
+		MatroskaTagInfo *trackTag;
+		trackTag =3D FindTagWithTrackUID(m_Tracks.at(m_CurrentTrackNo).trackUI=
D);
+		if (trackTag =3D=3D NULL)
+		{
+			MatroskaTagInfo tempTag;
+			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;		=09
+			m_Tags.push_back(tempTag);
+			trackTag =3D &m_Tags.at(m_Tags.size()-1);
+		}
+		if(trackTag->targetTypeValue =3D=3D 0)
+			trackTag->targetTypeValue =3D 50;
+		trackTag->MarkAllAsRemovalPending();
+		int metaDataCount =3D info.meta_get_count();
+		for (i =3D 0; i < metaDataCount; i++)
+		{
+			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
+				name =3D info.meta_enum_name(i);
+				value =3D info.meta_enum_value(i, j);
+				//idx =3D meta_get_num(info, name, i);
+				idx =3D j;
+				if (isEditionTag(name))
+				{
+					name =3D foobar2k_to_matroska_edition_tag(name);
+				} else {
+					name =3D NULL;
+				}
+				if ((name !=3D NULL) && (value !=3D NULL)) {
+					trackTag->SetTagValue(name, value, idx);
+				}
+			}
+		}
+		replaygain_info rg =3D info.get_replaygain();
+		if (rg.is_album_gain_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_album_gain, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			trackTag->SetTagValue("REPLAYGAIN_GAIN", value);
+		if (rg.is_album_peak_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_album_peak, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			trackTag->SetTagValue("REPLAYGAIN_PEAK", value);
+		trackTag->RemoveMarkedTags();
+	}
+
+
+	//If there's not only a track, set all the chapter tags
+	if ((m_Chapters.size() > 0) && (m_CurrentChapter !=3D NULL))
+	{
+		// Ok we add the tags to tag with chapter+track UID's
+		MatroskaTagInfo *chapterTag;	=09
+		chapterTag =3D FindTagWithChapterUID(m_CurrentChapter->chapterUID,
+			m_Tracks.at(m_CurrentTrackNo).trackUID);
+		if (chapterTag =3D=3D NULL)
+		{
+			MatroskaTagInfo tempTag;
+			tempTag.targetTrackUID =3D m_Tracks.at(m_CurrentTrackNo).trackUID;
+			tempTag.targetChapterUID =3D m_CurrentChapter->chapterUID;
+			m_Tags.push_back(tempTag);
+			chapterTag =3D &m_Tags.at(m_Tags.size()-1);
+		}
+		if(chapterTag->targetTypeValue =3D=3D 0)
+			chapterTag->targetTypeValue =3D 30;
+		chapterTag->MarkAllAsRemovalPending();
+		int metaDataCount =3D info.meta_get_count();
+		for (i =3D 0; i < metaDataCount; i++)
+		{
+			for (int j =3D 0; j !=3D info.meta_enum_value_count(i); ++j) {
+				name =3D info.meta_enum_name(i);
+				value =3D info.meta_enum_value(i, j);
+				//idx =3D meta_get_num(info, name, i);
+				idx =3D j;
+				if (isEditionTag(name))
+				{
+					name =3D NULL;
+				} else {
+					name =3D foobar2k_to_matroska_chapter_tag(name);
+				}
+				if ((name !=3D NULL) && (value !=3D NULL)) {
+					chapterTag->SetTagValue(name, value, idx);
+				}
+			}
+		}
+		replaygain_info rg =3D info.get_replaygain();
+		if (rg.is_track_gain_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_gain, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			chapterTag->SetTagValue("REPLAYGAIN_GAIN", value);
+		if (rg.is_track_peak_present()) {
+			char tmp[rg.text_buffer_size];
+			pfc::float_to_string(tmp, rg.text_buffer_size, rg.m_track_peak, 7);
+			value =3D (const char*)tmp;
+		} else {
+			value =3D NULL;
+		}
+		if (value)
+			chapterTag->SetTagValue("REPLAYGAIN_PEAK", value);
+		chapterTag->RemoveMarkedTags();
+	}
+};
+
+MatroskaTagInfo *MatroskaAudioParser::FindTagWithTrackUID(uint64 trackUI=
D)=20
+{
+	MatroskaTagInfo *foundTag =3D NULL;
+
+	for (size_t t =3D 0; t < m_Tags.size(); t++)
+	{
+		MatroskaTagInfo& currentTag =3D m_Tags.at(t);
+		if (currentTag.targetTrackUID =3D=3D trackUID &&
+			currentTag.targetEditionUID =3D=3D 0 &&
+			currentTag.targetChapterUID =3D=3D 0 &&
+			currentTag.targetAttachmentUID =3D=3D 0)
+		{
+			foundTag =3D &currentTag;
+			break;
+		}
+	}
+
+	return foundTag;
+};
+
+MatroskaTagInfo *MatroskaAudioParser::FindTagWithEditionUID(uint64 editi=
onUID, uint64 trackUID)
+{
+	MatroskaTagInfo *foundTag =3D NULL;
+
+	for (size_t t =3D 0; t < m_Tags.size(); t++)
+	{
+		MatroskaTagInfo &currentTag =3D m_Tags.at(t);
+		if (currentTag.targetEditionUID =3D=3D editionUID &&
+			(trackUID =3D=3D 0 || (currentTag.targetTrackUID =3D=3D trackUID)))
+		{
+			foundTag =3D &currentTag;
+			break;
+		}
+	}
+
+	return foundTag;
+};
+
+MatroskaTagInfo *MatroskaAudioParser::FindTagWithChapterUID(uint64 chapt=
erUID, uint64 trackUID)
+{
+	MatroskaTagInfo *foundTag =3D NULL;
+
+	for (size_t t =3D 0; t < m_Tags.size(); t++)
+	{
+		MatroskaTagInfo &currentTag =3D m_Tags.at(t);
+		if (currentTag.targetChapterUID =3D=3D chapterUID &&
+			(trackUID =3D=3D 0 || (currentTag.targetTrackUID =3D=3D trackUID)))
+		{
+			foundTag =3D &currentTag;
+			break;
+		}
+	}
+
+	return foundTag;
+};
+
+double MatroskaAudioParser::GetDuration() {=20
+	if (m_CurrentChapter !=3D NULL) {
+		return TimecodeToSeconds(m_CurrentChapter->timeEnd - m_CurrentChapter-=
>timeStart);
+	};
+	return m_Duration / 1000000000.0;
+	if (m_Tracks.size() !=3D 0) {
+		return m_Tracks.at(m_CurrentTrackNo).defaultDuration * (int64)m_Timeco=
deScale;
+	}
+};
+
+int32 MatroskaAudioParser::GetFirstAudioTrack()
+{
+	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
+	{
+		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
+		if (!strncmp(currentTrack.codecID.c_str(),"A_",2)) return t;
+	}
+	return -1;
+}
+
+uint32 MatroskaAudioParser::GetAudioTrackCount()
+{
+	uint32 count =3D 0;
+	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
+	{
+		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
+		if (!strncmp(currentTrack.codecID.c_str(),"A_",2))
+			count++;
+	}
+	return count;
+}
+
+uint32 MatroskaAudioParser::GetAudioTrackIndex(uint32 index)
+{
+	uint32 idx =3D 0;
+	for (uint16 t =3D 0; t < m_Tracks.size(); t++)
+	{
+		MatroskaTrackInfo &currentTrack =3D m_Tracks.at(t);
+		if (!strncmp(currentTrack.codecID.c_str(),"A_",2))
+		{
+			if(t =3D=3D index)
+				break;
+			idx++;
+		}
+	}
+	return idx;
+}
+
+static bool is_rg_field(const char * name)
+{
+	int m;
+	for (m =3D 0; m < tabsize(rg_fields); m++)
+	{
+		if (!stricmp_utf8(name,rg_fields[m])) return true;
+	}
+	return false;
+}
+
+static bool is_hidden_edition_field(const char * name)
+{
+	for (int i =3D 0; i < tabsize(hidden_edition_field); i++)
+		if (!stricmp_utf8(name, hidden_edition_field[i]))
+			return true;
+	return false;
+}
+
+static bool is_hidden_chapter_field(const char * name)
+{
+	for (int i =3D 0; i < tabsize(hidden_chapter_field); i++)
+		if (!stricmp_utf8(name, hidden_chapter_field[i]))
+			return true;
+	return false;
+}
+
+static const char* matroska_to_foobar2k_edition_tag(const char * name)
+{
+	for (int i =3D 0; i < tabsize(edition_tag_mapping); i++)
+		if (!stricmp_utf8(name, edition_tag_mapping[i][MATROSKA_TAG_IDX]))
+			return edition_tag_mapping[i][FOOBAR2K_TAG_IDX];
+	return name;
+}
+
+static const char* matroska_to_foobar2k_chapter_tag(const char * name)
+{
+	for (int i =3D 0; i < tabsize(chapter_tag_mapping); i++)
+		if (!stricmp_utf8(name, chapter_tag_mapping[i][MATROSKA_TAG_IDX]))
+			return chapter_tag_mapping[i][FOOBAR2K_TAG_IDX];
+	return name;
+}
+
+static void convert_matroska_to_foobar2k_tag(pfc::string_base & p_out, c=
onst char * p_name)
+{
+    pfc::string8 name(p_name);
+    //name.replace_char('_', ' ');
+    p_out =3D name;
+}
+
+static bool IsTagNamed(const MatroskaSimpleTag &currentSimpleTag, const =
char * name)
+{
+	return !stricmp_utf8(currentSimpleTag.name.GetUTF8().c_str(), name);
+}
+
+static bool IsTagValued(const MatroskaSimpleTag &currentSimpleTag, const=
 char * value)
+{
+	return !strcmp(currentSimpleTag.value.GetUTF8().c_str(), value);
+}
+
+static bool AreTagsNameEqual(const MatroskaSimpleTag &tag1, const Matros=
kaSimpleTag &tag2)
+{
+	return !stricmp_utf8(tag1.name.GetUTF8().c_str(), tag2.name.GetUTF8().c=
_str());
+}
+
+static bool AreTagsValueEqual(const MatroskaSimpleTag &tag1, const Matro=
skaSimpleTag &tag2)
+{
+	return !strcmp(tag1.value.GetUTF8().c_str(), tag2.value.GetUTF8().c_str=
());
+}
+
+static bool AreTagsEqual(const MatroskaSimpleTag &tag1, const MatroskaSi=
mpleTag &tag2)
+{
+	return AreTagsNameEqual(tag1,tag2) && AreTagsValueEqual(tag1,tag2);
+}
+
+const MatroskaSimpleTag* GetTagWithName(MatroskaTagInfo *SimpleTags, con=
st char * name)
+{
+	if(SimpleTags =3D=3D NULL)
+		return NULL;
+
+	for (size_t s =3D 0; s < SimpleTags->tags.size(); s++)
+	{
+		const MatroskaSimpleTag &currentSimpleTag =3D SimpleTags->tags.at(s);	=
=09
+		if(IsTagNamed(currentSimpleTag, name))
+			return &currentSimpleTag;
+	}
+	return NULL;
+}
+
+bool TagExistsAtEditionLevel(MatroskaTagInfo *TrackTags, const char * na=
me)
+{
+	if(TrackTags =3D=3D NULL)
+		return false;
+
+	for (size_t s =3D 0; s < TrackTags->tags.size(); s++)
+	{
+		const MatroskaSimpleTag &currentSimpleTag =3D TrackTags->tags.at(s);	=09
+		if(IsTagNamed(currentSimpleTag,name))
+			return true;
+	}
+	return false;
+}
+
+bool TagExistsAtChapterLevel(MatroskaTagInfo *ChapterTags, const char * =
name)
+{
+	if(ChapterTags =3D=3D NULL)
+		return false;
+
+	for (size_t s =3D 0; s < ChapterTags->tags.size(); s++)
+	{
+		const MatroskaSimpleTag &currentSimpleTag =3D ChapterTags->tags.at(s);=
	=09
+		if(IsTagNamed(currentSimpleTag,name))
+			return true;
+	}
+	return false;
+}
+
+bool MatroskaAudioParser::AreTagsIdenticalAtAllLevels(const char * name)
+{
+	const MatroskaSimpleTag* ReferenceTag =3D NULL;
+	bool AtLeastOneChapter =3D false;
+
+	for (size_t i =3D 0; i < m_Tags.size(); i++)
+	{
+		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
+		if(ReferenceTag =3D=3D NULL)
+		{
+			AtLeastOneChapter =3D true;
+			ReferenceTag =3D GetTagWithName(&currentTags, name);
+		} else {
+			const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags, =
name);
+			if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
+				return false;			=09
+		}
+	}
+	return AtLeastOneChapter;
+}
+
+bool MatroskaAudioParser::AreTagsIdenticalAtEditionLevel(const char * na=
me)
+{
+	const MatroskaSimpleTag* ReferenceTag =3D NULL;
+	bool AtLeastOneChapter =3D false;
+
+	for (size_t i =3D 0; i < m_Tags.size(); i++)
+	{
+		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
+		if (currentTags.targetChapterUID =3D=3D 0)
+		{
+			// Chapter tags
+			if(ReferenceTag =3D=3D NULL)
+			{
+				AtLeastOneChapter =3D true;
+				ReferenceTag =3D GetTagWithName(&currentTags, name);
+			} else {
+				const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags,=
 name);
+				if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
+					return false;			=09
+			}
+		}
+	}
+	return AtLeastOneChapter;
+}
+
+bool MatroskaAudioParser::AreTagsIdenticalAtChapterLevel(const char * na=
me)
+{
+	const MatroskaSimpleTag* ReferenceTag =3D NULL;
+	bool AtLeastOneChapter =3D false;
+
+	for (size_t i =3D 0; i < m_Tags.size(); i++)
+	{
+		MatroskaTagInfo &currentTags =3D m_Tags.at(i);
+		if (currentTags.targetChapterUID !=3D 0)
+		{
+			// Chapter tags
+			if(ReferenceTag =3D=3D NULL)
+			{
+				AtLeastOneChapter =3D true;
+				ReferenceTag =3D GetTagWithName(&currentTags, name);
+			} else {
+				const MatroskaSimpleTag* TagToCheck =3D GetTagWithName(&currentTags,=
 name);
+				if(TagToCheck && !AreTagsValueEqual(*ReferenceTag,*TagToCheck))
+					return false;			=09
+			}
+		}
+	}
+	return AtLeastOneChapter;
+}
+
+void MatroskaAudioParser::SetAlbumTags(file_info & info,
+									   MatroskaTagInfo* AlbumTags,
+									   MatroskaTagInfo* TrackTags)
+{
+	if (AlbumTags =3D=3D NULL)
+		return;
+
+	for (size_t s =3D 0; s < AlbumTags->tags.size(); s++)
+	{
+		MatroskaSimpleTag &simpleTag =3D AlbumTags->tags.at(s);
+	=09
+		if (is_rg_field(simpleTag.name.GetUTF8().c_str()))
+		{
+			if(IsTagNamed(simpleTag, "REPLAYGAIN_GAIN"))
+			{
+				info.info_set_replaygain("replaygain_album_gain", simpleTag.value.Ge=
tUTF8().c_str());
+				if (TrackTags =3D=3D NULL) info.info_set_replaygain("replaygain_trac=
k_gain", simpleTag.value.GetUTF8().c_str());
+			} else if(IsTagNamed(simpleTag, "REPLAYGAIN_PEAK")) {
+				info.info_set_replaygain("replaygain_album_peak", simpleTag.value.Ge=
tUTF8().c_str());
+				if (TrackTags =3D=3D NULL) info.info_set_replaygain("replaygain_trac=
k_peak", simpleTag.value.GetUTF8().c_str());
+			}
+		}
+		else if (is_hidden_edition_field(simpleTag.name.GetUTF8().c_str()))
+		{
+			// Ignored tag, will be rewrited later
+			simpleTag.hidden =3D true;
+		}
+		else if(IsTagNamed(simpleTag,"TITLE"))
+		{
+			// Special case for Edition/TITLE
+			if(TagExistsAtChapterLevel(TrackTags, "ALBUM"))
+			{
+				info.meta_add("ALBUM TITLE", simpleTag.value.GetUTF8().c_str());
+			} else {
+				info.meta_add("ALBUM", simpleTag.value.GetUTF8().c_str());
+			}
+		}
+        /*
+		else if(IsTagNamed(simpleTag,"SUBTITLE"))
+		{
+			// Special case for Edition/SUBTITLE
+			if(TagExistsAtChapterLevel(TrackTags, "SUBALBUM"))
+			{
+				info.meta_add("ALBUM SUBTITLE", simpleTag.value.GetUTF8().c_str());
+			} else {
+				info.meta_add("SUBALBUM", simpleTag.value.GetUTF8().c_str());
+			}
+		}
+        */
+        else if (IsTagNamed(simpleTag, "DISCID") ||
+		         IsTagNamed(simpleTag, "CATALOG_NUMBER") ||
+                 IsTagNamed(simpleTag, "TOTAL_PARTS") ||
+                 IsTagNamed(simpleTag, "PART_NUMBER") ||
+                 IsTagNamed(simpleTag, "TOTAL_DISCS"))
+		{
+			info.meta_add(matroska_to_foobar2k_edition_tag(simpleTag.name.GetUTF8=
().c_str()), simpleTag.value.GetUTF8().c_str());
+		}
+        /*else if (IsTagNamed(simpleTag,"COMMENTS"))
+		{
+			info.meta_add("ALBUM COMMENT", simpleTag.value.GetUTF8().c_str());
+		}*/
+		else if((!AreTagsIdenticalAtAllLevels(simpleTag.name.GetUTF8().c_str()=
))
+			|| (!TagExistsAtChapterLevel(TrackTags, simpleTag.name.GetUTF8().c_st=
r())))
+		{
+			// Prefix tag with "ALBUM "
+			char newTagName[255] =3D "ALBUM ";
+			strncat(newTagName, matroska_to_foobar2k_edition_tag(simpleTag.name.G=
etUTF8().c_str()),255);
+            pfc::string8 new_tagname;
+            convert_matroska_to_foobar2k_tag(new_tagname, newTagName);
+			info.meta_add(new_tagname, simpleTag.value.GetUTF8().c_str());
+		}
+		else=20
+		{
+			// Ignored tag, will be rewrited later
+			simpleTag.hidden =3D true;
+		}
+	}
+}
+
+void MatroskaAudioParser::SetTrackTags(file_info &info, MatroskaTagInfo*=
 TrackTags)
+{
+	if(TrackTags =3D=3D NULL)
+		return;
+
+	for (size_t s =3D 0; s < TrackTags->tags.size(); s++)
+	{
+		MatroskaSimpleTag &simpleTag =3D TrackTags->tags.at(s);
+	=09
+		if (is_rg_field(simpleTag.name.GetUTF8().c_str()))
+		{
+			if(IsTagNamed(simpleTag, "REPLAYGAIN_GAIN"))
+			{
+				info.info_set_replaygain("replaygain_track_gain", simpleTag.value.Ge=
tUTF8().c_str());
+			} else if(IsTagNamed(simpleTag, "REPLAYGAIN_PEAK")) {
+				info.info_set_replaygain("replaygain_track_peak", simpleTag.value.Ge=
tUTF8().c_str());
+			}
+		}
+		else if (is_hidden_chapter_field(simpleTag.name.GetUTF8().c_str()))
+		{
+			// Ignore tag
+			simpleTag.hidden =3D true;
+		}
+        /*else if(IsTagNamed(simpleTag,"COMMENTS"))
+		{
+			info.meta_add("COMMENT", simpleTag.value.GetUTF8().c_str());
+		}*/
+		else if(IsTagNamed(simpleTag,"ALBUM"))
+		{
+			if(!TagExistsAtEditionLevel(TrackTags, "TITLE") && AreTagsIdenticalAt=
ChapterLevel("ALBUM")) {
+				info.meta_add("ALBUM", simpleTag.value.GetUTF8().c_str());
+			} else {
+				info.meta_add("ORIGINAL ALBUM", simpleTag.value.GetUTF8().c_str());
+			}
+		}
+		else
+		{
+            pfc::string8 new_tagname;
+            convert_matroska_to_foobar2k_tag(new_tagname, matroska_to_fo=
obar2k_chapter_tag(simpleTag.name.GetUTF8().c_str()));
+			info.meta_add(new_tagname, simpleTag.value.GetUTF8().c_str());=09
+		}
+	}
+}
+
+bool MatroskaAudioParser::SetFB2KInfo(file_info &info, t_uint32 p_subson=
g)
+{
+	if (m_MuxingApp.length() > 0)
+		info.info_set("MUXING_APP", m_MuxingApp.GetUTF8().c_str());
+	if (m_WritingApp.length() > 0)
+		info.info_set("WRITING_APP", m_WritingApp.GetUTF8().c_str());
+	if (m_FileTitle.length() > 0)
+		info.info_set("TITLE", m_FileTitle.GetUTF8().c_str());
+
+	// pregap
+	try {
+		if (m_Chapters.at(p_subsong).subChapters.size() > 1) {
+			double pregap =3D TimecodeToSeconds(m_Chapters.at(p_subsong).subChapt=
ers.at(1).timeStart - m_Chapters.at(p_subsong).subChapters.at(0).timeStar=
t);
+			info.info_set("pregap", cuesheet_format_index_time(pregap));
+		}
+	} catch (std::out_of_range & e) {
+	}
+
+	MatroskaTagInfo *TrackTags =3D FindTagWithTrackUID(m_Tracks.at(m_Curren=
tTrackNo).trackUID);
+	MatroskaTagInfo *ChapterTags =3D NULL;
+	if(m_CurrentChapter !=3D NULL)
+	{
+		ChapterTags =3D FindTagWithChapterUID(m_CurrentChapter->chapterUID,
+			m_Tracks.at(m_CurrentTrackNo).trackUID);
+	}
+
+	MatroskaTagInfo *EditionTags =3D NULL;
+	if(m_CurrentEdition !=3D NULL)
+	{
+		EditionTags =3D FindTagWithEditionUID(m_CurrentEdition->editionUID,
+			m_Tracks.at(m_CurrentTrackNo).trackUID);
+	}
+	if(EditionTags !=3D NULL && EditionTags->targetTypeValue =3D=3D 50)
+	{
+		SetAlbumTags(info, EditionTags, ChapterTags);
+	}
+
+	if(TrackTags !=3D NULL)
+	{
+		if(TrackTags->targetTypeValue =3D=3D 50)
+		{
+			SetAlbumTags(info, TrackTags, ChapterTags);
+			SetTrackTags(info, ChapterTags);
+		} else if (TrackTags->targetTypeValue =3D=3D 30) {
+			SetTrackTags(info, TrackTags);
+		}
+	}
+=09
+	// Last chance,
+	if(m_CurrentChapter !=3D NULL)
+	{
+		// If TITLE tag is empty we get it from the chapter name
+		if ( (m_CurrentChapter->display.size() > 0) &&
+			 ((info.meta_get("TITLE", 0) =3D=3D NULL) ||
+			  (strlen(info.meta_get("TITLE", 0)) =3D=3D 0) ) )
+		{
+			info.meta_set("TITLE", m_CurrentChapter->display.at(0).string.GetUTF8=
().c_str());
+		}
+		if ((info.meta_get("TRACKNUMBER", 0) =3D=3D NULL) || (strlen(info.meta=
_get("TRACKNUMBER", 0)) =3D=3D 0))
+		{
+			//char trackNumberString[32];
+            pfc::string8 trackNumberString;
+#ifdef MULTITRACK		=09
+			//wsprintf((LPWSTR)trackNumberString, (LPCWSTR)"%d",
+			//	(p_subsong % m_Chapters.size()) +1);
+            trackNumberString << ((p_subsong % m_Chapters.size()) +1);
+#else
+			wsprintf(trackNumberString, "%d",p_subsong+1);
+#endif
+			info.meta_set("TRACKNUMBER", trackNumberString);
+		}
+		if ((info.meta_get("ALBUM", 0) =3D=3D NULL) || (strlen(info.meta_get("=
ALBUM", 0)) =3D=3D 0))
+		{
+			if(m_FileTitle.length() > 0)
+				info.meta_set("ALBUM", m_FileTitle.GetUTF8().c_str());
+		}
+	}
+
+	return true;
+};
+
+void MatroskaAudioParser::MarkHiddenTags()
+{
+	// We call MatroskaAudioParser::SetFB2KInfo with a dummy file_info that
+	// do nothing, so we will only mark hidden tags.
+	// Hidden tag will be copied to keep track of them.
+	// This is needed cause tag are read and written in 2 different instanc=
es
+	file_info_impl info;
+	SetFB2KInfo(info, 0);
+};
+
+void MatroskaAudioParser::SetCurrentTrack(uint32 newTrackNo)
+{
+	m_CurrentTrackNo =3D newTrackNo;
+	// Clear the current queue (we are changing tracks)
+	while (!m_Queue.empty())
+		m_Queue.pop();
+};
+
+void MatroskaAudioParser::SetSubSong(int subsong)
+{
+	// As we don't (yet?) use several Editions, select the first (default) =
one as the current one.
+	m_CurrentEdition =3D NULL;
+	m_CurrentChapter =3D NULL;
+	if(m_Editions.size() > 0)
+		m_CurrentEdition =3D &m_Editions.at(0);
+	if (m_Chapters.size() > subsong)
+		m_CurrentChapter =3D &m_Chapters.at(subsong);
+=09
+};
+
+int32 MatroskaAudioParser::GetAvgBitrate()=20
+{=20
+	double ret =3D 0;
+	ret =3D static_cast<double>(int64(m_FileSize)) / 1024;
+	ret =3D ret / (m_Duration / 1000000000.0);
+	ret =3D ret * 8;
+	return static_cast<int32>(ret);
+};
+
+bool MatroskaAudioParser::skip_frames_until(double destination,unsigned =
& frames,double & last_timecode_delta,unsigned hint_samplerate)
+{
+	unsigned done =3D 0;
+	unsigned last_laced =3D 0;
+
+	double last_time;
+	{
+		uint64 last_timecode =3D get_current_frame_timecode();
+		if (last_timecode =3D=3D (uint64)(-1)) return false;
+		last_time =3D TimecodeToSeconds(last_timecode,hint_samplerate);
+	}
+
+	for(;;)
+	{
+		while (!m_Queue.empty()) {
+			MatroskaAudioFrame *currentPacket =3D m_Queue.front();
+			double packet_time =3D TimecodeToSeconds(currentPacket->timecode,hint=
_samplerate);
+			if (packet_time > destination)
+			{
+				if (done=3D=3D0) return false;
+				last_timecode_delta =3D destination - last_time;
+				frames =3D done - last_laced;
+				return true;
+			}
+			last_time =3D packet_time;
+			done +=3D (last_laced =3D currentPacket->dataBuffer.size());
+			//delete currentPacket;
+			_DELETE(currentPacket);
+			m_Queue.pop();
+		}
+		if (FillQueue()!=3D0)
+			return false;
+	}
+}
+
+
+void MatroskaAudioParser::flush_queue()
+{
+	while (!m_Queue.empty()) {
+		MatroskaAudioFrame *currentPacket =3D m_Queue.front();
+		//delete currentPacket;
+		_DELETE(currentPacket);
+		m_Queue.pop();
+	}
+}
+
+uint64 MatroskaAudioParser::get_current_frame_timecode()
+{
+	if (m_Queue.empty())
+	{
+		if (FillQueue()!=3D0) return -1;
+		if (m_Queue.empty()) return -1;
+	}
+	return m_Queue.front()->timecode;
+}
+
+bool MatroskaAudioParser::Seek(double seconds,unsigned & frames_to_skip,=
double & time_to_skip,unsigned samplerate_hint)
+{
+	int64 ret =3D 0;
+
+	if (m_CurrentChapter !=3D NULL) {
+		seconds +=3D (double)(int64)m_CurrentChapter->timeStart / 1000000000; =
// ns -> seconds
+	}
+
+	uint64 seekToTimecode =3D SecondsToTimecode(seconds);
+=09
+	flush_queue();
+	m_CurrentTimecode =3D seekToTimecode;
+
+	if (!skip_frames_until(seconds,frames_to_skip,time_to_skip,samplerate_h=
int)) return false;
+
+	flush_queue();
+	m_CurrentTimecode =3D seekToTimecode;
+	if (FillQueue()!=3D0) return false;
+	return true;
+
+};
+
+MatroskaAudioFrame * MatroskaAudioParser::ReadSingleFrame()
+{
+	for(;;)
+	{
+		if (!m_Queue.empty()) {
+			MatroskaAudioFrame *newFrame =3D m_Queue.front();	=09
+			m_Queue.pop();
+			return newFrame;
+		} else {
+			if (FillQueue()!=3D0)
+				return 0;
+		}
+	}
+};
+
+MatroskaAudioFrame * MatroskaAudioParser::ReadFirstFrame()
+{
+    m_CurrentTimecode =3D 0;
+    return ReadSingleFrame();
+};
+
+typedef boost::shared_ptr<EbmlId> EbmlIdPtr;
+
+void MatroskaAudioParser::Parse_MetaSeek(ElementPtr metaSeekElement, boo=
l bInfoOnly)=20
+{
+    TIMER;
+	uint64 lastSeekPos =3D 0;
+	uint64 endSeekPos =3D 0;
+	ElementPtr l2;
+	ElementPtr l3;
+	ElementPtr NullElement;
+	int UpperElementLevel =3D 0;
+
+	if (metaSeekElement =3D=3D NullElement)
+		return;
+
+	l2 =3D ElementPtr(m_InputStream.FindNextElement(metaSeekElement->Generi=
c().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
+	while (l2 !=3D NullElement) {
+		if (UpperElementLevel > 0) {
+			break;
+		}
+		if (UpperElementLevel < 0) {
+			UpperElementLevel =3D 0;
+		}
+        if (bInfoOnly) {
+            if (m_ClusterIndex.size() >=3D 1) break;
+        }
+
+		if (EbmlId(*l2) =3D=3D KaxSeek::ClassInfos.GlobalId) {
+			//Wow we found the SeekEntries, time to speed up reading ;)
+			l3 =3D ElementPtr(m_InputStream.FindNextElement(l2->Generic().Context=
, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
+
+			EbmlIdPtr id;
+			while (l3 !=3D NullElement) {
+				if (UpperElementLevel > 0) {
+					break;
+				}
+				if (UpperElementLevel < 0) {
+					UpperElementLevel =3D 0;
+				}
+                if (bInfoOnly) {
+                    if (m_ClusterIndex.size() >=3D 1) break;
+                }
+
+				if (EbmlId(*l3) =3D=3D KaxSeekID::ClassInfos.GlobalId) {
+					binary *b =3D NULL;
+					uint16 s =3D 0;
+					KaxSeekID &seek_id =3D static_cast<KaxSeekID &>(*l3);
+					seek_id.ReadData(m_InputStream.I_O(), SCOPE_ALL_DATA);
+					b =3D seek_id.GetBuffer();
+					s =3D (uint16)seek_id.GetSize();
+                    id.reset();
+					id =3D EbmlIdPtr(new EbmlId(b, s));
+
+				} else if (EbmlId(*l3) =3D=3D KaxSeekPosition::ClassInfos.GlobalId) =
{
+					KaxSeekPosition &seek_pos =3D static_cast<KaxSeekPosition &>(*l3);
+					seek_pos.ReadData(m_InputStream.I_O());			=09
+					lastSeekPos =3D uint64(seek_pos);
+					if (endSeekPos < lastSeekPos)
+						endSeekPos =3D uint64(seek_pos);
+
+					if (*id =3D=3D KaxCluster::ClassInfos.GlobalId) {
+						//NOTE1("Found Cluster Seek Entry Postion: %u", (unsigned long)las=
tSeekPos);
+						//uint64 orig_pos =3D inputFile.getFilePointer();
+						//MatroskaMetaSeekClusterEntry newCluster;
+                        cluster_entry_ptr newCluster(new MatroskaMetaSee=
kClusterEntry());
+						newCluster->timecode =3D MAX_UINT64;
+						newCluster->filePos =3D static_cast<KaxSegment *>(m_ElementLevel0.=
get())->GetGlobalPosition(lastSeekPos);
+						m_ClusterIndex.push_back(newCluster);
+
+					} else if (*id =3D=3D KaxSeekHead::ClassInfos.GlobalId) {
+						NOTE1("Found MetaSeek Seek Entry Postion: %u", (unsigned long)last=
SeekPos);
+						uint64 orig_pos =3D m_IOCallback.getFilePointer();
+						m_IOCallback.setFilePointer(static_cast<KaxSegment *>(m_ElementLev=
el0.get())->GetGlobalPosition(lastSeekPos));
+					=09
+						ElementPtr levelUnknown =3D ElementPtr(m_InputStream.FindNextID(Ka=
xSeekHead::ClassInfos, 0xFFFFFFFFFFFFFFFFL));									=09
+						Parse_MetaSeek(levelUnknown, bInfoOnly);
+
+						m_IOCallback.setFilePointer(orig_pos);
+					}
+
+				} else {
+
+				}
+				l3->SkipData(m_InputStream, l3->Generic().Context);
+				l3 =3D ElementPtr(m_InputStream.FindNextElement(l2->Generic().Contex=
t, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
+			}
+		} else {
+
+		}
+
+		if (UpperElementLevel > 0) {    // we're coming from l3
+			UpperElementLevel--;
+			l2 =3D l3;
+			if (UpperElementLevel > 0)
+				break;
+
+		} else {
+			l2->SkipData(m_InputStream, l2->Generic().Context);
+			l2 =3D ElementPtr(m_InputStream.FindNextElement(metaSeekElement->Gene=
ric().Context, UpperElementLevel, 0xFFFFFFFFFFFFFFFFL, true, 1));
+		}
+	}
+    _TIMER("Parse_MetaSeek");
+}
+
+#define IS_ELEMENT_ID(__x__) (Element->Generic().GlobalId =3D=3D __x__::=
ClassInfos.GlobalId)
+
+void MatroskaAudioParser::Parse_Chapter_Atom(KaxChapterAtom *ChapterAtom=
)
+{
+	Parse_Chapter_Atom(ChapterAtom, m_Chapters);
+}
+
+void MatroskaAudioParser::Parse_Chapter_Atom(KaxChapterAtom *ChapterAtom=
, std::vector<MatroskaChapterInfo> &p_chapters)
+{
+	int i, j;
+	EbmlElement *Element =3D NULL;
+	MatroskaChapterInfo newChapter;
+
+	NOTE("New chapter");
+
+	for (i =3D 0; i < ChapterAtom->ListSize(); i++)
+	{=09
+		Element =3D (*ChapterAtom)[i];
+			=09
+		if (IS_ELEMENT_ID(KaxChapterUID))
+		{
+			newChapter.chapterUID =3D uint64(*static_cast<EbmlUInteger *>(Element=
));
+			NOTE1("- UID : %I64d", newChapter.chapterUID);
+		}
+		else if(IS_ELEMENT_ID(KaxChapterTimeStart))
+		{						=09
+			newChapter.timeStart =3D uint64(*static_cast<EbmlUInteger *>(Element)=
); // it's in ns
+			NOTE1("- TimeStart : %I64d", newChapter.timeStart);
+		}
+		else if(IS_ELEMENT_ID(KaxChapterTimeEnd))
+		{
+			newChapter.timeEnd =3D uint64(*static_cast<EbmlUInteger *>(Element));=
 // it's in ns
+			NOTE1("- TimeEnd : %I64d", newChapter.timeEnd);
+		}
+		else if(IS_ELEMENT_ID(KaxChapterTrack))
+		{
+			KaxChapterTrack *ChapterTrack =3D (KaxChapterTrack *)Element;
+		=09
+			for (j =3D 0; j < ChapterTrack->ListSize(); j++)
+			{
+				Element =3D (*ChapterTrack)[j];
+				if(IS_ELEMENT_ID(KaxChapterTrackNumber))
+				{
+					uint64 chapTrackNo =3D uint64(*static_cast<EbmlUInteger *>(Element)=
);
+					newChapter.tracks.push_back(chapTrackNo);
+					NOTE1("- TrackNumber : %I64d", chapTrackNo);
+				}
+				else if(IS_ELEMENT_ID(KaxChapterAtom))
+				{								=09
+					// Ignore sub-chapter
+					NOTE("ignore sub-chapter");
+					//Parse_Chapter_Atom((KaxChapterAtom *)Element);
+				}
+			}
+		}
+		else if(IS_ELEMENT_ID(KaxChapterDisplay))
+		{
+			// A new chapter display string+lang+country
+			MatroskaChapterDisplayInfo newChapterDisplay;						=09
+			KaxChapterDisplay *ChapterDisplay =3D (KaxChapterDisplay *)Element;
+		=09
+			for (j =3D 0; j < ChapterDisplay->ListSize(); j++) {
+				Element =3D (*ChapterDisplay)[j];
+				if(IS_ELEMENT_ID(KaxChapterString))
+				{
+					newChapterDisplay.string =3D UTFstring(*static_cast <EbmlUnicodeStr=
ing *>(Element)).c_str();
+					NOTE1("- String : %s", newChapterDisplay.string.GetUTF8().c_str());
+				}
+				else if(IS_ELEMENT_ID(KaxChapterAtom))
+				{								=09
+					// Ignore sub-chapter
+					NOTE("ignore sub-chapter");
+					//Parse_Chapter_Atom((KaxChapterAtom *)Element);
+				}
+			}
+			// A emtpy string in a chapter display string is usless
+			if (newChapterDisplay.string.length() > 0)
+				newChapter.display.push_back(newChapterDisplay);
+		}
+		else if(IS_ELEMENT_ID(KaxChapterAtom))
+		{
+			/*
+			// Ignore sub-chapter
+			NOTE("ignore sub-chapter");
+			//Parse_Chapter_Atom((KaxChapterAtom *)Element);
+			*/
+			Parse_Chapter_Atom((KaxChapterAtom *)Element, newChapter.subChapters)=
;
+		}
+	}
+	if ((newChapter.chapterUID !=3D 0) && !FindChapterUID(newChapter.chapte=
rUID))
+		p_chapters.push_back(newChapter);
+}
+
+void MatroskaAudioParser::Parse_Chapters(KaxChapters *chaptersElement)
+{
+	int i, j;=09
+	EbmlElement *Element =3D NULL;=09
+	int UpperEltFound =3D 0;
+
+	NOTE("New edition");
+
+	if (chaptersElement =3D=3D NULL)
+		return;
+
+	chaptersElement->Read(m_InputStream, KaxChapters::ClassInfos.Context,
+		UpperEltFound, Element, true);
+
+	for (i =3D 0; i < chaptersElement->ListSize(); i++)
+	{
+		Element =3D (*chaptersElement)[i];
+		if(IS_ELEMENT_ID(KaxEditionEntry))
+		{
+			MatroskaEditionInfo newEdition;
+			KaxEditionEntry *edition =3D (KaxEditionEntry *)Element;
+			for (j =3D 0; j < edition->ListSize(); j++)
+			{
+				Element =3D (*edition)[j];
+				if(IS_ELEMENT_ID(KaxEditionUID))
+				{
+					// A new edition :)
+					newEdition.editionUID =3D uint64(*static_cast<EbmlUInteger *>(Eleme=
nt));
+					NOTE1("- UID : %I64d", newEdition.editionUID);
+				}
+				else if(IS_ELEMENT_ID(KaxChapterAtom))
+				{
+					// A new chapter :)
+					Parse_Chapter_Atom((KaxChapterAtom *)Element);
+				}
+			}
+			if ((newEdition.editionUID !=3D 0) && !FindEditionUID(newEdition.edit=
ionUID))
+				m_Editions.push_back(newEdition);
+		}
+	}
+	FixChapterEndTimes();
+}
+
+void MatroskaAudioParser::Parse_Tags(KaxTags *tagsElement)
+{
+	int i, j, k;
+	EbmlElement *Element =3D NULL;
+	int UpperEltFound =3D 0;
+
+	if (tagsElement =3D=3D NULL)
+		return;
+
+	m_TagPos =3D tagsElement->GetElementPosition();
+	m_TagSize =3D tagsElement->GetSize();
+
+	tagsElement->Read(m_InputStream, KaxTags::ClassInfos.Context, UpperEltF=
ound, Element, true);
+
+	for (i =3D 0; i < tagsElement->ListSize(); i++)
+	{
+		Element =3D (*tagsElement)[i];
+		if(IS_ELEMENT_ID(KaxTag))
+		{
+			MatroskaTagInfo newTag;
+			newTag.targetTypeValue =3D 50;
+			KaxTag *tagElement =3D (KaxTag*)Element;
+			NOTE("New Tag");
+			for (j =3D 0; j < tagElement->ListSize(); j++)
+			{
+				Element =3D (*tagElement)[j];
+				if(IS_ELEMENT_ID(KaxTagTargets))
+				{
+					KaxTagTargets *tagTargetsElement =3D (KaxTagTargets*)Element;				=09
+					for (k =3D 0; k < tagTargetsElement->ListSize(); k++)
+					{
+						Element =3D (*tagTargetsElement)[k];
+						if(IS_ELEMENT_ID(KaxTagTrackUID))
+						{
+							newTag.targetTrackUID =3D uint64(*static_cast<EbmlUInteger *>(Ele=
ment));
+							NOTE1("- TargetTrackUID : %I64d", newTag.targetTrackUID);
+						}
+						else if(IS_ELEMENT_ID(KaxTagEditionUID))
+						{
+							newTag.targetEditionUID =3D uint64(*static_cast<EbmlUInteger *>(E=
lement));
+							NOTE1("- TargetEditionUID : %I64d", newTag.targetEditionUID);
+						}
+						else if(IS_ELEMENT_ID(KaxTagChapterUID))
+						{
+							newTag.targetChapterUID =3D uint64(*static_cast<EbmlUInteger *>(E=
lement));
+							NOTE1("- TargetChapterUIDUID : %I64d", newTag.targetChapterUID);
+						}
+						else if(IS_ELEMENT_ID(KaxTagAttachmentUID))
+						{
+							newTag.targetAttachmentUID =3D uint64(*static_cast<EbmlUInteger *=
>(Element));
+							NOTE1("- TargetAttachmentUID : %I64d", newTag.targetAttachmentUID=
);
+						}
+						else if(IS_ELEMENT_ID(KaxTagTargetTypeValue))
+						{
+							newTag.targetTypeValue =3D uint32(*static_cast<EbmlUInteger *>(El=
ement));
+							NOTE1("- TargetTypeValue : %d", newTag.targetTypeValue);
+						}
+						else if(IS_ELEMENT_ID(KaxTagTargetType))
+						{
+							newTag.targetType =3D std::string(*static_cast<KaxTagTargetType *=
>(Element));
+							NOTE1("- TargetType : %s", newTag.targetType.c_str());
+						}
+					}
+				}
+				else if(IS_ELEMENT_ID(KaxTagSimple))
+				{
+					MatroskaSimpleTag newSimpleTag;
+					KaxTagSimple *tagSimpleElement =3D (KaxTagSimple*)Element;
+					NOTE("New SimpleTag");
+					for (k =3D 0; k < tagSimpleElement->ListSize(); k++)
+					{
+						Element =3D (*tagSimpleElement)[k];
+						if(IS_ELEMENT_ID(KaxTagName))
+						{
+							newSimpleTag.name =3D wcsupr((wchar_t *)UTFstring(*static_cast <E=
bmlUnicodeString *>(Element)).c_str());
+							NOTE1("- Name : %s", newSimpleTag.name.GetUTF8().c_str());
+						}
+						else if(IS_ELEMENT_ID(KaxTagString))
+						{
+							newSimpleTag.value =3D UTFstring(*static_cast <EbmlUnicodeString =
*>(Element)).c_str();
+							NOTE1("- Value : %s", newSimpleTag.value.GetUTF8().c_str());
+						}
+						else if(IS_ELEMENT_ID(KaxTagDefault))
+						{
+							newSimpleTag.defaultFlag =3D uint32(*static_cast<EbmlUInteger *>(=
Element));
+							NOTE1("- TargetTypeValue : %d", newSimpleTag.default);
+						}
+						else if(IS_ELEMENT_ID(KaxTagLangue))
+						{
+							newSimpleTag.language =3D std::string(*static_cast <KaxTagLangue =
*>(Element));
+							NOTE1("- Language : %s", newSimpleTag.language.c_str());
+						}
+						else if(IS_ELEMENT_ID(KaxTagSimple))
+						{
+							// ignore sub-tags
+							// if we want "sub-tags" put this loop in another
+							// function and call it recursively
+						}
+					}
+					newTag.tags.push_back(newSimpleTag);
+				}
+			}
+			m_Tags.push_back(newTag);
+		}
+	}
+};
+
+int MatroskaAudioParser::FillQueue()=20
+{
+	flush_queue();
+
+	NOTE("MatroskaAudioParser::FillQueue()");
+
+	int UpperElementLevel =3D 0;
+	bool bAllowDummy =3D false;
+	// Elements for different levels
+	ElementPtr ElementLevel1;
+	ElementPtr ElementLevel2;
+	ElementPtr ElementLevel3;
+	ElementPtr ElementLevel4;
+    ElementPtr ElementLevel5;
+	ElementPtr NullElement;
+	//m_framebuffer.set_size(0);
+
+	if (m_IOCallback.seekable()) {
+		cluster_entry_ptr currentCluster =3D FindCluster(m_CurrentTimecode);
+		if (currentCluster.get() =3D=3D NULL)
+			return 2;
+		int64 clusterFilePos =3D currentCluster->filePos;
+
+		//console::info(uStringPrintf("cluster %d", currentCluster->clusterNo)=
);
+
+		m_IOCallback.setFilePointer(clusterFilePos);
+		// Find the element data
+		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
+		if (ElementLevel1 =3D=3D NullElement)
+			return 1;
+
+		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
+			KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLevel=
1.get());
+			uint32 ClusterTimecode =3D 0;
+			MatroskaAudioFrame *prevFrame =3D NULL;
+
+			// read blocks and discard the ones we don't care about
+			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
bAllowDummy));
+			while (ElementLevel2 !=3D NullElement) {
+				if (UpperElementLevel > 0) {
+					break;
+				}
+				if (UpperElementLevel < 0) {
+					UpperElementLevel =3D 0;
+				}
+				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
+					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
+					ClusterTime.ReadData(m_InputStream.I_O());
+					ClusterTimecode =3D uint32(ClusterTime);
+					currentCluster->timecode =3D ClusterTimecode * m_TimecodeScale;
+					SegmentCluster->InitTimecode(ClusterTimecode, m_TimecodeScale);
+				} else  if (EbmlId(*ElementLevel2) =3D=3D KaxBlockGroup::ClassInfos.=
GlobalId) {
+					//KaxBlockGroup & aBlockGroup =3D *static_cast<KaxBlockGroup*>(Elem=
entLevel2);
+
+					// Create a new frame
+					MatroskaAudioFrame *newFrame =3D new MatroskaAudioFrame;
+
+					ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize()=
, bAllowDummy));
+					while (ElementLevel3 !=3D NullElement) {
+						if (UpperElementLevel > 0) {
+							break;
+						}
+						if (UpperElementLevel < 0) {
+							UpperElementLevel =3D 0;
+						}
+						if (EbmlId(*ElementLevel3) =3D=3D KaxBlock::ClassInfos.GlobalId) {=
							=09
+							KaxBlock & DataBlock =3D *static_cast<KaxBlock*>(ElementLevel3.ge=
t());													=09
+							DataBlock.ReadData(m_InputStream.I_O());
+							DataBlock.SetParent(*SegmentCluster);
+
+							//NOTE4("Track # %u / %u frame%s / Timecode %I64d", DataBlock.Tra=
ckNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"",=
 DataBlock.GlobalTimecode()/m_TimecodeScale);
+							if (DataBlock.TrackNum() =3D=3D m_Tracks.at(m_CurrentTrackNo).tra=
ckNumber) {										=09
+								newFrame->timecode =3D DataBlock.GlobalTimecode();
+
+								if (DataBlock.NumberFrames() > 1) {=09
+									// The evil lacing has been used
+									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation * DataBlock.NumberFrames();
+
+									newFrame->dataBuffer.resize(DataBlock.NumberFrames());
+									for (uint32 f =3D 0; f < DataBlock.NumberFrames(); f++) {
+										DataBuffer &buffer =3D DataBlock.GetBuffer(f);
+										newFrame->dataBuffer[f].resize(buffer.Size());							=09
+										memcpy(&newFrame->dataBuffer[f][0], buffer.Buffer(), buffer.Si=
ze());
+									}
+								} else {
+									// Non-lacing block	=09
+									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation;
+
+									newFrame->dataBuffer.resize(1);
+									DataBuffer &buffer =3D DataBlock.GetBuffer(0);
+									newFrame->dataBuffer.at(0).resize(buffer.Size());
+                                       =20
+									memcpy(&newFrame->dataBuffer.at(0).at(0), buffer.Buffer(), buff=
er.Size());
+								}
+							} else {
+								//newFrame->timecode =3D MAX_UINT64;
+							}
+						/*
+						} else if (EbmlId(*ElementLevel3) =3D=3D KaxReferenceBlock::ClassI=
nfos.GlobalId) {
+							KaxReferenceBlock & RefTime =3D *static_cast<KaxReferenceBlock*>(=
ElementLevel3);
+							RefTime.ReadData(m_InputStream.I_O());
+							newFrame->frameReferences.push_back(int32(RefTime));
+							//wxLogDebug("  Reference frame at scaled (%d) timecode %ld\n", i=
nt32(RefTime), int32(int64(RefTime) * TimecodeScale));
+							*/
+						} else if (EbmlId(*ElementLevel3) =3D=3D KaxBlockDuration::ClassIn=
fos.GlobalId) {
+							KaxBlockDuration & BlockDuration =3D *static_cast<KaxBlockDuratio=
n*>(ElementLevel3.get());
+							BlockDuration.ReadData(m_InputStream.I_O());
+							newFrame->duration =3D uint64(BlockDuration);
+                        } else if (EbmlId(*ElementLevel3) =3D=3D KaxBloc=
kAdditions::ClassInfos.GlobalId) {
+                            ElementLevel4 =3D ElementPtr(m_InputStream.F=
indNextElement(ElementLevel3->Generic().Context, UpperElementLevel, 0xFFF=
FFFFFL, bAllowDummy));
+                            while (ElementLevel4 !=3D NullElement) {
+                                if (UpperElementLevel > 0) {
+							        break;
+						        }
+						        if (UpperElementLevel < 0) {
+							        UpperElementLevel =3D 0;
+						        }
+                                if (EbmlId(*ElementLevel4) =3D=3D KaxBlo=
ckMore::ClassInfos.GlobalId) {
+                                    ElementLevel5 =3D ElementPtr(m_Input=
Stream.FindNextElement(ElementLevel4->Generic().Context, UpperElementLeve=
l, 0xFFFFFFFFL, bAllowDummy));
+                                    while (ElementLevel5 !=3D NullElemen=
t) {
+                                        if (UpperElementLevel > 0) {
+							                break;
+						                }
+						                if (UpperElementLevel < 0) {
+							                UpperElementLevel =3D 0;
+						                }
+                                        if (EbmlId(*ElementLevel5) =3D=3D=
 KaxBlockAddID::ClassInfos.GlobalId) {
+                                            KaxBlockAddID & AddId =3D *s=
tatic_cast<KaxBlockAddID*>(ElementLevel5.get());
+                                            AddId.ReadData(m_InputStream=
.I_O());
+                                            newFrame->add_id =3D uint64(=
AddId);
+                                        } else if (EbmlId(*ElementLevel5=
) =3D=3D KaxBlockAdditional::ClassInfos.GlobalId) {
+                                            KaxBlockAdditional & DataBlo=
ckAdditional =3D *static_cast<KaxBlockAdditional*>(ElementLevel5.get());	=
												=09
+							                DataBlockAdditional.ReadData(m_InputStream.I_O())=
;	=09
+                                            newFrame->additional_data_bu=
ffer.resize(DataBlockAdditional.GetSize());
+                                            if (!newFrame->add_id) {
+                                                newFrame->add_id =3D 1;
+                                            }
+                                            memcpy(&newFrame->additional=
_data_buffer.at(0), DataBlockAdditional.GetBuffer(), DataBlockAdditional.=
GetSize());
+                                        }
+                                        ElementLevel5->SkipData(m_InputS=
tream, ElementLevel5->Generic().Context);
+							            ElementLevel5 =3D ElementPtr(m_InputStream.FindNextEl=
ement(ElementLevel4->Generic().Context, UpperElementLevel, ElementLevel4-=
>ElementSize(), bAllowDummy));
+                                    }
+                                }
+                                if (UpperElementLevel > 0) {
+							        UpperElementLevel--;
+							        ElementLevel4 =3D ElementLevel5;
+							        if (UpperElementLevel > 0)
+								        break;
+						        } else {
+							        ElementLevel4->SkipData(m_InputStream, ElementLevel4->Gen=
eric().Context);
+							        ElementLevel4 =3D ElementPtr(m_InputStream.FindNextElemen=
t(ElementLevel3->Generic().Context, UpperElementLevel, ElementLevel3->Ele=
mentSize(), bAllowDummy));
+						        }
+                            }
+                        }
+						if (UpperElementLevel > 0) {
+							UpperElementLevel--;
+							ElementLevel3 =3D ElementLevel4;
+							if (UpperElementLevel > 0)
+								break;
+						} else {
+							ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().C=
ontext);
+
+							ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Elemen=
tLevel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize=
(), bAllowDummy));
+						}						=09
+						//newFrame =3D new MatroskaReadFrame();
+					}
+					if (newFrame->dataBuffer.size()>0) {
+						m_Queue.push(newFrame);
+						if (prevFrame !=3D NULL && prevFrame->duration =3D=3D 0) {
+							prevFrame->duration =3D newFrame->timecode - prevFrame->timecode;
+							//if (newFrame->duration =3D=3D 0)
+							//	newFrame->duration =3D prevFrame->duration;
+						}
+
+						// !!!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!!!!!!!!!!!
+						// This is an ugly hack to keep us from re-seeking to the same clu=
ster
+						m_CurrentTimecode =3D newFrame->timecode + (newFrame->duration * 2=
);
+						if (newFrame->duration =3D=3D 0) {
+							m_CurrentTimecode +=3D (int64)m_Tracks.at(m_CurrentTrackNo).defau=
ltDuration * 2;
+						}
+						// !!!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!!!!!!!!!!!
+
+						prevFrame =3D newFrame;
+                    } else {
+                        hprintf(L"newFrame =3D=3D!! delete!!\n");
+                        _DELETE(newFrame);
+                    }
+				}
+
+				if (UpperElementLevel > 0) {
+					UpperElementLevel--;
+					//delete ElementLevel2;
+					//_DELETE(ElementLevel2);
+					ElementLevel2 =3D ElementLevel3;
+					if (UpperElementLevel > 0)
+						break;
+				} else {
+					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
+					//if (ElementLevel2 !=3D pChecksum)
+					//	delete ElementLevel2;							=09
+					//ElementLevel2 =3D NULL;
+					//_DELETE(ElementLevel2);
+
+					ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize()=
, bAllowDummy));
+				}
+			}
+		}
+		//_DELETE(ElementLevel3);
+		//_DELETE(ElementLevel2);
+		//_DELETE(ElementLevel1);
+		//delete ElementLevel1;
+	=09
+		if (currentCluster->clusterNo < m_ClusterIndex.size()-1) {
+			if (m_ClusterIndex.at(currentCluster->clusterNo+1)->timecode =3D=3D M=
AX_UINT64)
+				m_ClusterIndex.at(currentCluster->clusterNo+1)->timecode =3D GetClus=
terTimecode(m_ClusterIndex.at(currentCluster->clusterNo+1)->filePos);
+			m_CurrentTimecode =3D m_ClusterIndex.at(currentCluster->clusterNo+1)-=
>timecode;
+			if(m_CurrentTimecode =3D=3D 0)
+			{
+				console::error(uStringPrintf("clusterNo : %d, m_ClusterIndex.size() =
: %d", currentCluster->clusterNo, m_ClusterIndex.size()));
+				console::info("m_CurrentTimecode =3D=3D 0 (a)");
+			}
+		} else {
+			m_CurrentTimecode =3D MAX_UINT64;
+		}
+	=09
+	} else {
+		// Find the element data
+		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
+		if (ElementLevel1 =3D=3D NullElement)
+			return 1;
+
+		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
+			KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLevel=
1.get());
+			uint32 ClusterTimecode =3D 0;
+
+			// read blocks and discard the ones we don't care about
+			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
bAllowDummy));
+			while (ElementLevel2 !=3D NullElement) {
+				if (UpperElementLevel > 0) {
+					break;
+				}
+				if (UpperElementLevel < 0) {
+					UpperElementLevel =3D 0;
+				}
+				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
+					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
+					ClusterTime.ReadData(m_InputStream.I_O());
+					ClusterTimecode =3D uint32(ClusterTime);
+					SegmentCluster->InitTimecode(ClusterTimecode, m_TimecodeScale);
+				} else  if (EbmlId(*ElementLevel2) =3D=3D KaxBlockGroup::ClassInfos.=
GlobalId) {
+					//KaxBlockGroup & aBlockGroup =3D *static_cast<KaxBlockGroup*>(Elem=
entLevel2);
+
+					// Create a new frame
+					MatroskaAudioFrame *newFrame =3D new MatroskaAudioFrame;			=09
+
+					ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize()=
, bAllowDummy));
+					while (ElementLevel3 !=3D NullElement) {
+						if (UpperElementLevel > 0) {
+							break;
+						}
+						if (UpperElementLevel < 0) {
+							UpperElementLevel =3D 0;
+						}
+						if (EbmlId(*ElementLevel3) =3D=3D KaxBlock::ClassInfos.GlobalId) {=
							=09
+							KaxBlock & DataBlock =3D *static_cast<KaxBlock*>(ElementLevel3.ge=
t());													=09
+							DataBlock.ReadData(m_InputStream.I_O());	=09
+							DataBlock.SetParent(*SegmentCluster);
+
+							//NOTE4("Track # %u / %u frame%s / Timecode %I64d", DataBlock.Tra=
ckNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"",=
 DataBlock.GlobalTimecode()/m_TimecodeScale);
+							if (DataBlock.TrackNum() =3D=3D m_Tracks.at(m_CurrentTrackNo).tra=
ckNumber) {										=09
+								newFrame->timecode =3D DataBlock.GlobalTimecode();						=09
+
+								if (DataBlock.NumberFrames() > 1) {=09
+									// The evil lacing has been used
+									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation * DataBlock.NumberFrames();
+
+									newFrame->dataBuffer.resize(DataBlock.NumberFrames());
+									for (uint32 f =3D 0; f < DataBlock.NumberFrames(); f++) {
+										DataBuffer &buffer =3D DataBlock.GetBuffer(f);
+										newFrame->dataBuffer[f].resize(buffer.Size());							=09
+										memcpy(&newFrame->dataBuffer[f][0], buffer.Buffer(), buffer.Si=
ze());
+									}
+								} else {
+									// Non-lacing block	=09
+									newFrame->duration =3D m_Tracks.at(m_CurrentTrackNo).defaultDur=
ation;
+								=09
+									newFrame->dataBuffer.resize(1);
+									DataBuffer &buffer =3D DataBlock.GetBuffer(0);
+									newFrame->dataBuffer.at(0).resize(buffer.Size());							=09
+									memcpy(&newFrame->dataBuffer[0][0], buffer.Buffer(), buffer.Siz=
e());
+								}
+							} else {
+								//newFrame->timecode =3D MAX_UINT64;
+							}
+						/*
+						} else if (EbmlId(*ElementLevel3) =3D=3D KaxReferenceBlock::ClassI=
nfos.GlobalId) {
+							KaxReferenceBlock & RefTime =3D *static_cast<KaxReferenceBlock*>(=
ElementLevel3);
+							RefTime.ReadData(m_InputStream.I_O());
+							newFrame->frameReferences.push_back(int32(RefTime));
+							//wxLogDebug("  Reference frame at scaled (%d) timecode %ld\n", i=
nt32(RefTime), int32(int64(RefTime) * TimecodeScale));
+							*/
+						} else if (EbmlId(*ElementLevel3) =3D=3D KaxBlockDuration::ClassIn=
fos.GlobalId) {
+							KaxBlockDuration & BlockDuration =3D *static_cast<KaxBlockDuratio=
n*>(ElementLevel3.get());
+							BlockDuration.ReadData(m_InputStream.I_O());
+							newFrame->duration =3D uint64(BlockDuration);
+						}
+						if (UpperElementLevel > 0) {
+							UpperElementLevel--;
+							//delete ElementLevel3;
+							//_DELETE(ElementLevel3);
+							ElementLevel3 =3D ElementLevel4;
+							if (UpperElementLevel > 0)
+								break;
+						} else {
+							ElementLevel3->SkipData(m_InputStream, ElementLevel3->Generic().C=
ontext);
+							//delete ElementLevel3;
+							//ElementLevel3 =3D NULL;
+							//_DELETE(ElementLevel3);
+
+							ElementLevel3 =3D ElementPtr(m_InputStream.FindNextElement(Elemen=
tLevel2->Generic().Context, UpperElementLevel, ElementLevel2->ElementSize=
(), bAllowDummy));
+						}						=09
+						//newFrame =3D new MatroskaReadFrame();
+					}
+					if (newFrame->dataBuffer.size()>0)
+						m_Queue.push(newFrame);
+				}
+
+				if (UpperElementLevel > 0) {
+					UpperElementLevel--;
+					//delete ElementLevel2;
+					//_DELETE(ElementLevel2);
+					ElementLevel2 =3D ElementLevel3;
+					if (UpperElementLevel > 0)
+						break;
+				} else {
+					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
+					//if (ElementLevel2 !=3D pChecksum)
+					//	delete ElementLevel2;							=09
+					//ElementLevel2 =3D NULL;
+					//_DELETE(ElementLevel2);
+
+					ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementL=
evel1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize()=
, bAllowDummy));
+				}
+			}
+		}
+		ElementLevel1->SkipData(m_InputStream, ElementLevel1->Generic().Contex=
t);
+		//_DELETE(ElementLevel3);
+		//_DELETE(ElementLevel2);
+		//_DELETE(ElementLevel1);
+		//delete ElementLevel1;
+	}
+	//NOTE1("MatroskaAudioParser::FillQueue() - Queue now has %u frames", m=
_Queue.size());
+	return 0;
+};
+
+uint64 MatroskaAudioParser::GetClusterTimecode(uint64 filePos) {=09
+	try {
+		uint64 ret =3D MAX_UINT64;
+
+		int UpperElementLevel =3D 0;
+		// Elements for different levels
+		ElementPtr ElementLevel1;
+		ElementPtr ElementLevel2;	=09
+		ElementPtr ElementLevel3;
+		ElementPtr NullElement;
+
+		m_IOCallback.setFilePointer(filePos);
+		// Find the element data
+		ElementLevel1 =3D ElementPtr(m_InputStream.FindNextID(KaxCluster::Clas=
sInfos, 0xFFFFFFFFFFFFFFFFL));
+		if (ElementLevel1 =3D=3D NullElement)
+			return MAX_UINT64;
+
+		if (EbmlId(*ElementLevel1) =3D=3D KaxCluster::ClassInfos.GlobalId) {
+			//KaxCluster *SegmentCluster =3D static_cast<KaxCluster *>(ElementLev=
el1);
+			//uint32 ClusterTimecode =3D 0;
+
+			// read blocks and discard the ones we don't care about
+			ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(ElementLev=
el1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(), =
false));
+			while (ElementLevel2 !=3D NullElement) {
+				if (UpperElementLevel > 0) {
+					break;
+				}
+				if (UpperElementLevel < 0) {
+					UpperElementLevel =3D 0;
+				}
+				if (EbmlId(*ElementLevel2) =3D=3D KaxClusterTimecode::ClassInfos.Glo=
balId) {					=09
+					KaxClusterTimecode & ClusterTime =3D *static_cast<KaxClusterTimecod=
e*>(ElementLevel2.get());
+					ClusterTime.ReadData(m_InputStream.I_O());
+					ret =3D uint64(ClusterTime) * m_TimecodeScale;
+				=09
+				}
+
+				if (UpperElementLevel > 0) {
+					UpperElementLevel--;
+					//delete ElementLevel2;
+					//_DELETE(ElementLevel2);
+					ElementLevel2 =3D ElementLevel3;
+					if (UpperElementLevel > 0)
+						break;
+				} else {
+					ElementLevel2->SkipData(m_InputStream, ElementLevel2->Generic().Con=
text);
+					//if (ElementLevel2 !=3D pChecksum)
+					//delete ElementLevel2;							=09
+					//ElementLevel2 =3D NULL;
+					//_DELETE(ElementLevel2);
+					ElementLevel2 =3D NullElement;
+					if (ret =3D=3D -1)
+						ElementLevel2 =3D ElementPtr(m_InputStream.FindNextElement(Element=
Level1->Generic().Context, UpperElementLevel, ElementLevel1->ElementSize(=
), false));
+				}
+			}
+		}
+		//_DELETE(ElementLevel3);
+		//_DELETE(ElementLevel2);
+		//_DELETE(ElementLevel1);
+		//delete ElementLevel1;
+
+		return ret;
+	} catch (...) {
+		return MAX_UINT64;
+	}=09
+};
+
+cluster_entry_ptr MatroskaAudioParser::FindCluster(uint64 timecode)
+{
+	try {
+		#ifdef _DEBUG_NO_SEEKING
+		static size_t callCount =3D 0;
+		if (callCount < m_ClusterIndex.size())
+			return &m_ClusterIndex[callCount++];
+		else return NULL;
+		#endif
+
+		if (timecode =3D=3D 0)
+			// Special case
+			return m_ClusterIndex.at(0);
+	=09
+		cluster_entry_ptr correctEntry;
+		double clusterDuration =3D (double)(int64)m_ClusterIndex.size() / m_Du=
ration;
+		size_t clusterIndex =3D clusterDuration * (double)(int64)timecode;
+		//int lookCount =3D 0;
+		if (clusterIndex > m_ClusterIndex.size())
+			clusterIndex =3D m_ClusterIndex.size()-1;
+
+		cluster_entry_ptr clusterEntry;
+		cluster_entry_ptr prevClusterEntry;
+		cluster_entry_ptr nextClusterEntry;
+		while (correctEntry =3D=3D NULL) {
+			clusterEntry =3D m_ClusterIndex.at(clusterIndex);	=09
+			if (clusterIndex > 0)
+				prevClusterEntry =3D m_ClusterIndex.at(clusterIndex-1);
+			if (clusterIndex+1 < m_ClusterIndex.size())
+				nextClusterEntry =3D m_ClusterIndex.at(clusterIndex+1);		=09
+		=09
+			// We need timecodes to do good seeking
+			if (clusterEntry->timecode =3D=3D MAX_UINT64) {			=09
+				clusterEntry->timecode =3D GetClusterTimecode(clusterEntry->filePos)=
;		=09
+			}
+			if (prevClusterEntry !=3D NULL && prevClusterEntry->timecode =3D=3D M=
AX_UINT64) {
+				prevClusterEntry->timecode =3D GetClusterTimecode(prevClusterEntry->=
filePos);		=09
+			}
+			if (nextClusterEntry !=3D NULL && nextClusterEntry->timecode =3D=3D M=
AX_UINT64) {			=09
+				nextClusterEntry->timecode =3D GetClusterTimecode(nextClusterEntry->=
filePos);		=09
+			}
+
+			if (clusterEntry->timecode =3D=3D timecode) {
+				// WOW, we are seeking directly to this cluster
+				correctEntry =3D clusterEntry;
+				break;
+			}
+
+			if (prevClusterEntry !=3D NULL) {
+				if (clusterEntry->timecode > timecode && timecode > prevClusterEntry=
->timecode) {
+					// We found it !!!
+					correctEntry =3D prevClusterEntry;
+					break;
+				}
+				if (prevClusterEntry->timecode =3D=3D timecode) {
+					// WOW, we are seeking directly to this cluster
+					correctEntry =3D prevClusterEntry;
+					break;
+				}
+				// Check if we overshot the needed cluster
+				if (timecode < prevClusterEntry->timecode) {
+					clusterIndex--;
+					//lookCount++; // This is how many times we have 'looked'
+					continue;
+				}
+			}
+		=09
+			if (nextClusterEntry !=3D NULL) {
+				if (clusterEntry->timecode < timecode && timecode < nextClusterEntry=
->timecode) {
+					// We found it !!!
+					correctEntry =3D clusterEntry;
+					break;
+				}		=09
+				if (nextClusterEntry->timecode =3D=3D timecode) {
+					// WOW, we are seeking directly to this cluster
+					correctEntry =3D nextClusterEntry;
+					break;
+				}
+				// Check if we undershot the needed cluster
+				if (timecode > nextClusterEntry->timecode) {
+					clusterIndex++;
+					//lookCount--;
+					continue;
+				}
+			}
+			// We should never get here, unless this is the last cluster
+			assert(clusterEntry !=3D NULL);=09
+			if (timecode <=3D m_Duration)
+				correctEntry =3D clusterEntry;
+			else
+				break;
+		}
+
+		if (correctEntry !=3D NULL)
+			NOTE3("MatroskaAudioParser::FindCluster(timecode =3D %u) seeking to c=
luster %i at %u", (uint32)(timecode / m_TimecodeScale), (uint32)correctEn=
try->clusterNo, (uint32)correctEntry->filePos);
+		else
+			NOTE1("MatroskaAudioParser::FindCluster(timecode =3D %u) seeking fail=
ed", (uint32)(timecode / m_TimecodeScale));
+
+		return correctEntry;
+	} catch (...) {
+        cluster_entry_ptr null_ptr;
+		return null_ptr;
+	}
+}
+
+void MatroskaAudioParser::CountClusters()=20
+{
+	for (uint32 c =3D 0; c < m_ClusterIndex.size(); c++) {
+		cluster_entry_ptr clusterEntry =3D m_ClusterIndex.at(c);	=09
+		clusterEntry->clusterNo =3D c;
+	}
+}
+
+void MatroskaAudioParser::FixChapterEndTimes()
+{
+	if (m_Chapters.size() > 0) {
+		MatroskaChapterInfo *nextChapter =3D &m_Chapters.at(m_Chapters.size()-=
1);
+		if (nextChapter->timeEnd =3D=3D 0) {
+			nextChapter->timeEnd =3D static_cast<uint64>(m_Duration);
+		}
+		for (uint32 c =3D 0; c < m_Chapters.size()-1; c++) {
+			MatroskaChapterInfo &currentChapter =3D m_Chapters.at(c);=09
+			nextChapter =3D &m_Chapters.at(c+1);
+			if (currentChapter.timeEnd =3D=3D 0) {
+				currentChapter.timeEnd =3D nextChapter->timeStart;
+			}
+		}
+		nextChapter =3D &m_Chapters.at(m_Chapters.size()-1);
+		if ((nextChapter->timeEnd =3D=3D 0) || (nextChapter->timeEnd =3D=3D ne=
xtChapter->timeStart)) {
+			nextChapter->timeEnd =3D static_cast<uint64>(m_Duration);
+		}
+	}=09
+}
+
+bool MatroskaAudioParser::FindEditionUID(uint64 uid)
+{
+	for (uint32 c =3D 0; c < m_Editions.size(); c++) {
+		MatroskaEditionInfo &currentEdition =3D m_Editions.at(c);=09
+		if (currentEdition.editionUID =3D=3D uid)
+			return true;
+	}=09
+	return false;
+}
+
+bool MatroskaAudioParser::FindChapterUID(uint64 uid)
+{
+	for (uint32 c =3D 0; c < m_Chapters.size(); c++) {
+		MatroskaChapterInfo &currentChapter =3D m_Chapters.at(c);=09
+		if (currentChapter.chapterUID =3D=3D uid)
+			return true;
+	}=09
+	return false;
+}
+
+void PrintChapters(std::vector<MatroskaChapterInfo> &theChapters)=20
+{
+	for (uint32 c =3D 0; c < theChapters.size(); c++) {
+		MatroskaChapterInfo &currentChapter =3D theChapters.at(c);=09
+		NOTE2("Chapter %u, UID: %u", c, (uint32)currentChapter.chapterUID);
+		NOTE1("\tStart Time: %u", (uint32)currentChapter.timeStart);
+		NOTE1("\tEnd Time: %u", (uint32)currentChapter.timeEnd);
+		for (uint32 d =3D 0; d < currentChapter.display.size(); d++) {
+			NOTE3("\tDisplay %u, String: %s Lang: %s", d, currentChapter.display.=
at(d).string.GetUTF8().c_str(), currentChapter.display.at(d).lang.c_str()=
);
+		}
+		for (uint32 t =3D 0; t < currentChapter.tracks.size(); t++) {
+			NOTE2("\tTrack %u, UID: %%u", t, (uint32)currentChapter.tracks.at(t))=
;
+		}
+
+	}
+};
+
+bool MatroskaSearch::Skip()
+{
+	int j;
+
+	for (j =3D 0; j < SEARCH_TABLE_SIZE; j++) skip[j] =3D SEARCH_PATTERN_SI=
ZE;
+	for (j =3D 0; j < SEARCH_PATTERN_SIZE - 1; j++)
+		skip[pattern[j] & 0x00ff] =3D SEARCH_PATTERN_SIZE-1-j;
+	return true;
+}
+
+bool MatroskaSearch::Next()
+{
+	int  j, k, s;
+	int  *g;
+
+	if ((g =3D (int *)malloc(sizeof(int)*SEARCH_PATTERN_SIZE)) =3D=3D NULL)=
 return false;
+	for (j =3D 0; j < SEARCH_PATTERN_SIZE; j++) next[j] =3D 2*SEARCH_PATTER=
N_SIZE - 1 - j;
+	j =3D SEARCH_PATTERN_SIZE;
+	for (k =3D SEARCH_PATTERN_SIZE - 1; k >=3D 0; k--) {
+		g[k] =3D j;
+		while (j !=3D SEARCH_PATTERN_SIZE && pattern[j] !=3D pattern[k]) {
+			next[j] =3D (next[j] <=3D SEARCH_PATTERN_SIZE-1-k) ? next[j] : SEARCH=
_PATTERN_SIZE-1-k;
+			j =3D g[j];
+		}
+		j--;
+	}
+	s =3D j;
+	for (j =3D 0; j < SEARCH_PATTERN_SIZE; j++) {
+		next[j] =3D (next[j] <=3D s+SEARCH_PATTERN_SIZE-j) ? next[j] : s+SEARC=
H_PATTERN_SIZE-j;
+		if (j >=3D s) s =3D g[s];
+	}
+	free(g);
+	return true;
+}
+
+int MatroskaSearch::Match(unsigned int start)
+{
+	int i, j;
+
+	i =3D SEARCH_PATTERN_SIZE - 1 + start;
+	while (i < SEARCH_SOURCE_SIZE) {
+		j =3D SEARCH_PATTERN_SIZE - 1;
+		while (j >=3D 0 && source[i] =3D=3D pattern[j]) {
+			i--;
+			j--;
+		}
+		if (j < 0) return i + 1;
+		if (skip[source[i] & 0x00ff] >=3D next[j])
+			i +=3D skip[source[i] & 0x00ff];
+		else i +=3D next[j];
+	}
+	return -1;
 };
\ No newline at end of file


Property changes on: trunk/foo_input_matroska/matroska_parser.cpp
___________________________________________________________________
Name: svn:eol-style
   + native