Parse headers outside of constructor

In several cases, the parser would parse a header
(say, a track header, or the segment info header)
in the constructor for the type.  The parser had
assumed (incorrectly) that the file was well-formed,
but this turned out to be an incorrect assumption.

The parse errors triggered some assertion failures,
but this is not acceptable in a production system.

The parser solved that problem by separating the
construction of the header object from the parsing
of the file.  There is now a separate parse method
to be called after construction of the object,
which returns a status whether the parse was
successful.

This change fixes the bugs from the following
tracker issues:

http://code.google.com/p/webm/issues/detail?id=399
http://code.google.com/p/webm/issues/detail?id=400

Change-Id: Idb09154ae7008429d8613ce3b3e8294f5a12de86
diff --git a/libwebm_2008.vcproj b/libwebm_2008.vcproj
index cd227df..54e943f 100644
--- a/libwebm_2008.vcproj
+++ b/libwebm_2008.vcproj
@@ -48,6 +48,7 @@
 				UsePrecompiledHeader="0"

 				WarningLevel="4"

 				DebugInformationFormat="1"

+				DisableSpecificWarnings="4996"

 			/>

 			<Tool

 				Name="VCManagedResourceCompilerTool"

diff --git a/mkvmuxer.cpp b/mkvmuxer.cpp
index 49a9d4e..66ef1b2 100644
--- a/mkvmuxer.cpp
+++ b/mkvmuxer.cpp
@@ -830,7 +830,7 @@
   if (number < 0)
     return false;
 
-  int32 track_num = number;
+  uint32 track_num = number;
 
   // Check to make sure a track does not already have |track_num|.
   for (uint32 i = 0; i < track_entries_size_; ++i) {
diff --git a/mkvparser.cpp b/mkvparser.cpp
index 646452b..e48343f 100644
--- a/mkvparser.cpp
+++ b/mkvparser.cpp
@@ -21,7 +21,7 @@
     major = 1;

     minor = 0;

     build = 0;

-    revision = 23;

+    revision = 24;

 }

 

 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)

@@ -137,64 +137,6 @@
     return 0;  //success

 }

 

-long long mkvparser::SyncReadUInt(

-    IMkvReader* pReader,

-    long long pos,

-    long long stop,

-    long& len)

-{

-    assert(pReader);

-

-    if (pos >= stop)

-        return E_FILE_FORMAT_INVALID;

-

-    unsigned char b;

-

-    long hr = pReader->Read(pos, 1, &b);

-

-    if (hr < 0)

-        return hr;

-

-    if (hr != 0L)

-        return E_BUFFER_NOT_FULL;

-

-    if (b == 0)  //we can't handle u-int values larger than 8 bytes

-        return E_FILE_FORMAT_INVALID;

-

-    unsigned char m = 0x80;

-    len = 1;

-

-    while (!(b & m))

-    {

-        m >>= 1;

-        ++len;

-    }

-

-    if ((pos + len) > stop)

-        return E_FILE_FORMAT_INVALID;

-

-    long long result = b & (~m);

-    ++pos;

-

-    for (int i = 1; i < len; ++i)

-    {

-        hr = pReader->Read(pos, 1, &b);

-

-        if (hr < 0)

-            return hr;

-

-        if (hr != 0L)

-            return E_BUFFER_NOT_FULL;

-

-        result <<= 8;

-        result |= b;

-

-        ++pos;

-    }

-

-    return result;

-}

-

 

 long long mkvparser::UnserializeUInt(

     IMkvReader* pReader,

@@ -203,8 +145,9 @@
 {

     assert(pReader);

     assert(pos >= 0);

-    assert(size > 0);

-    assert(size <= 8);

+

+    if ((size <= 0) || (size > 8))

+        return E_FILE_FORMAT_INVALID;

 

     long long result = 0;

 

@@ -227,209 +170,78 @@
 }

 

 

-float mkvparser::Unserialize4Float(

+long mkvparser::UnserializeFloat(

     IMkvReader* pReader,

-    long long pos)

+    long long pos,

+    long long size_,

+    double& result)

 {

     assert(pReader);

     assert(pos >= 0);

 

-#ifdef _DEBUG

-    {

-        long long total, available;

+    if ((size_ != 4) && (size_ != 8))

+        return E_FILE_FORMAT_INVALID;

 

-        const long status = pReader->Length(&total, &available);

-        assert(status >= 0);

-        assert((total < 0) || (available <= total));

-        assert((pos + 4) <= available);

+    const long size = static_cast<long>(size_);

+

+    unsigned char buf[8];

+

+    const int status = pReader->Read(pos, size, buf);

+

+    if (status < 0)  //error

+        return status;

+

+    if (size == 4)

+    {

+        union

+        {

+            float f;

+            unsigned long ff;

+        };

+

+        ff = 0;

+

+        for (int i = 0;;)

+        {

+            ff |= buf[i];

+

+            if (++i >= 4)

+                break;

+

+            ff <<= 8;

+        }

+

+        result = f;

     }

-#endif

-

-#if 0

-    float result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 4;

-

-    for (;;)

+    else

     {

-        hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

+        assert(size == 8);

 

-        if (q == p)

-            break;

+        union

+        {

+            double d;

+            unsigned long long dd;

+        };

 

-        ++pos;

+        dd = 0;

+

+        for (int i = 0;;)

+        {

+            dd |= buf[i];

+

+            if (++i >= 8)

+                break;

+

+            dd <<= 8;

+        }

+

+        result = d;

     }

-#else

-    union

-    {

-        float result;

-        unsigned long buf;

-    };

 

-    buf = 0;

-

-    for (int i = 0;;)

-    {

-        unsigned char b;

-

-        const int status = pReader->Read(pos++, 1, &b);

-

-        if (status < 0)  //error

-            return static_cast<float>(status);

-

-        buf |= b;

-

-        if (++i >= 4)

-            break;

-

-        buf <<= 8;

-    }

-#endif

-

-    return result;

+    return 0;

 }

 

 

-double mkvparser::Unserialize8Double(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-#if 0

-    double result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 8;

-

-    for (;;)

-    {

-        const long hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

-

-        if (q == p)

-            break;

-

-        ++pos;

-    }

-#else

-    union

-    {

-        double result;

-        long long buf;

-    };

-

-    buf = 0;

-

-    for (int i = 0;;)

-    {

-        unsigned char b;

-

-        const int status = pReader->Read(pos++, 1, &b);

-

-        if (status < 0)  //error

-            return static_cast<double>(status);

-

-        buf |= b;

-

-        if (++i >= 8)

-            break;

-

-        buf <<= 8;

-    }

-#endif

-

-    return result;

-}

-

-

-#if 0

-signed char mkvparser::Unserialize1SInt(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-#ifdef _DEBUG

-    {

-        long long total, available;

-

-        const long status = pReader->Length(&total, &available);

-        assert(status == 0);

-        assert((total < 0) || (available <= total));

-        assert(pos < available);

-    }

-#endif

-

-    signed char result;

-    unsigned char& b = reinterpret_cast<unsigned char&>(result);

-

-    const int status = pReader->Read(pos, 1, &b);

-    assert(status == 0);  //TODO: must be handled somehow

-

-    return result;

-}

-

-short mkvparser::Unserialize2SInt(

-    IMkvReader* pReader,

-    long long pos)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-#ifdef _DEBUG

-    {

-        long long total, available;

-

-        const long status = pReader->Length(&total, &available);

-        assert(status >= 0);

-        assert((total < 0) || (available <= total));

-        assert((pos + 2) <= available);

-    }

-#endif

-

-#if 0

-    short result;

-

-    unsigned char* const p = (unsigned char*)&result;

-    unsigned char* q = p + 2;

-

-    for (;;)

-    {

-        hr = pReader->Read(pos, 1, --q);

-        assert(hr == 0L);

-

-        if (q == p)

-            break;

-

-        ++pos;

-    }

-#else

-    short result = 0;

-

-    for (int i = 0;;)

-    {

-        unsigned char b;

-

-        const int status = pReader->Read(pos++, 1, &b);

-        assert(status == 0);  //TODO: must be handled somehow

-

-        result |= b;

-

-        if (++i >= 2)

-            break;

-

-        result <<= 8;

-    }

-#endif

-

-    return result;

-}

-#else

 long mkvparser::UnserializeInt(

     IMkvReader* pReader,

     long long pos,

@@ -471,7 +283,82 @@
 

     return 0;  //success

 }

-#endif

+

+

+long mkvparser::UnserializeString(

+    IMkvReader* pReader,

+    long long pos,

+    long long size_,

+    char*& str)

+{

+    delete[] str;

+    str = NULL;

+

+    if (size_ >= LONG_MAX)  //we need (size+1) chars

+        return E_FILE_FORMAT_INVALID;

+

+    const long size = static_cast<long>(size_);

+

+    str = new (std::nothrow) char[size+1];

+

+    if (str == NULL)

+        return -1;

+

+    unsigned char* const buf = reinterpret_cast<unsigned char*>(str);

+

+    const long status = pReader->Read(pos, size, buf);

+

+    if (status)

+    {

+        delete[] str;

+        str = NULL;

+

+        return status;

+    }

+

+    str[size] = '\0';

+

+    return 0;  //success

+}

+

+

+long mkvparser::ParseElementHeader(

+    IMkvReader* pReader,

+    long long& pos,

+    long long stop,

+    long long& id,

+    long long& size)

+{

+    if ((stop >= 0) && (pos >= stop))

+        return E_FILE_FORMAT_INVALID;

+

+    long len;

+

+    id = ReadUInt(pReader, pos, len);

+

+    if (id <= 0)

+        return E_FILE_FORMAT_INVALID;

+

+    pos += len;  //consume id

+

+    if ((stop >= 0) && (pos >= stop))

+        return E_FILE_FORMAT_INVALID;

+

+    size = ReadUInt(pReader, pos, len);

+

+    if (size < 0)

+        return E_FILE_FORMAT_INVALID;

+

+    pos += len;  //consume length of size

+

+    //pos now designates payload

+

+    if ((stop >= 0) && ((pos + size) > stop))

+        return E_FILE_FORMAT_INVALID;

+

+    return 0;  //success

+}

+

 

 bool mkvparser::Match(

     IMkvReader* pReader,

@@ -522,65 +409,6 @@
     IMkvReader* pReader,

     long long& pos,

     unsigned long id_,

-    char*& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long status = pReader->Length(&total, &available);

-    assert(status >= 0);

-    assert((total < 0) || (available <= total));

-

-    long len;

-

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size_ = ReadUInt(pReader, pos, len);

-    assert(size_ >= 0);

-    assert(len > 0);

-    assert(len <= 8);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-    assert((pos + size_) <= available);

-

-    const size_t size = static_cast<size_t>(size_);

-    val = new char[size+1];

-

-    for (size_t i = 0; i < size; ++i)

-    {

-        char c;

-

-        status = pReader->Read(pos + i, 1, (unsigned char*)&c);

-        assert(status == 0);  //TODO

-

-        val[i] = c;

-

-        if (c == '\0')

-            break;

-    }

-

-    val[size] = '\0';

-    pos += size_;  //consume size of payload

-

-    return true;

-}

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

     unsigned char*& buf,

     size_t& buflen)

 {

@@ -629,108 +457,6 @@
 }

 

 

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    double& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    const long status = pReader->Length(&total, &available);

-    assert(status >= 0);

-    assert((total < 0) || (available <= total));

-

-    long idlen;

-

-    const long long id = ReadUInt(pReader, pos, idlen);

-    assert(id >= 0);  //TODO

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    long sizelen;

-    const long long size = ReadUInt(pReader, pos + idlen, sizelen);

-

-    switch (size)

-    {

-        case 4:

-        case 8:

-            break;

-        default:

-            return false;

-    }

-

-    pos += idlen + sizelen;  //consume id and size fields

-    assert((pos + size) <= available);

-

-    if (size == 4)

-        val = Unserialize4Float(pReader, pos);

-    else

-    {

-        assert(size == 8);

-        val = Unserialize8Double(pReader, pos);

-    }

-

-    pos += size;  //consume size of payload

-

-    return true;

-}

-

-

-bool mkvparser::Match(

-    IMkvReader* pReader,

-    long long& pos,

-    unsigned long id_,

-    short& val)

-{

-    assert(pReader);

-    assert(pos >= 0);

-

-    long long total, available;

-

-    long status = pReader->Length(&total, &available);

-    assert(status >= 0);

-    assert((total < 0) || (available <= total));

-

-    long len;

-    const long long id = ReadUInt(pReader, pos, len);

-    assert(id >= 0);

-    assert((pos + len) <= available);

-

-    if ((unsigned long)id != id_)

-        return false;

-

-    pos += len;  //consume id

-

-    const long long size_ = ReadUInt(pReader, pos, len);

-    assert(size_ >= 1);

-    assert(size_ <= 2);

-    assert((pos + len) <= available);

-

-    pos += len;  //consume length of size of payload

-    assert((pos + size_) <= available);

-

-    const long size = static_cast<long>(size_);

-

-    long long value;

-

-    status = UnserializeInt(pReader, pos, size, value);

-    assert(status == 0);

-    assert(value >= SHRT_MIN);

-    assert(value <= SHRT_MAX);

-

-    val = static_cast<short>(value);

-

-    pos += size;  //consume size of payload

-

-    return true;

-}

-

-

 namespace mkvparser

 {

 

@@ -873,38 +599,75 @@
 

     while (pos < end)

     {

-        if (Match(pReader, pos, 0x0286, m_version))

-            ;

-        else if (Match(pReader, pos, 0x02F7, m_readVersion))

-            ;

-        else if (Match(pReader, pos, 0x02F2, m_maxIdLength))

-            ;

-        else if (Match(pReader, pos, 0x02F3, m_maxSizeLength))

-            ;

-        else if (Match(pReader, pos, 0x0282, m_docType))

-            ;

-        else if (Match(pReader, pos, 0x0287, m_docTypeVersion))

-            ;

-        else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion))

-            ;

-        else

+        long long id, size;

+

+        status = ParseElementHeader(

+                    pReader,

+                    pos,

+                    end,

+                    id,

+                    size);

+

+        if (status < 0) //error

+            return status;

+

+        if (size == 0)  //weird

+            return E_FILE_FORMAT_INVALID;

+

+        if (id == 0x0286)  //version

         {

-            result = ReadUInt(pReader, pos, len);

-            assert(result > 0);

-            assert(len > 0);

-            assert(len <= 8);

+            m_version = UnserializeUInt(pReader, pos, size);

 

-            pos += len;

-            assert(pos < end);

-

-            result = ReadUInt(pReader, pos, len);

-            assert(result >= 0);

-            assert(len > 0);

-            assert(len <= 8);

-

-            pos += len + result;

-            assert(pos <= end);

+            if (m_version <= 0)

+                return E_FILE_FORMAT_INVALID;

         }

+        else if (id == 0x02F7)  //read version

+        {

+            m_readVersion = UnserializeUInt(pReader, pos, size);

+

+            if (m_readVersion <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x02F2)  //max id length

+        {

+            m_maxIdLength = UnserializeUInt(pReader, pos, size);

+

+            if (m_maxIdLength <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x02F3)  //max size length

+        {

+            m_maxSizeLength = UnserializeUInt(pReader, pos, size);

+

+            if (m_maxSizeLength <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x0282)  //doctype

+        {

+            if (m_docType)

+                return E_FILE_FORMAT_INVALID;

+

+            status = UnserializeString(pReader, pos, size, m_docType);

+

+            if (status)  //error

+                return status;

+        }

+        else if (id == 0x0287)  //doctype version

+        {

+            m_docTypeVersion = UnserializeUInt(pReader, pos, size);

+

+            if (m_docTypeVersion <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x0285)  //doctype read version

+        {

+            m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);

+

+            if (m_docTypeReadVersion <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+

+        pos += size;

     }

 

     assert(pos == end);

@@ -1099,7 +862,10 @@
     long long total, available;

 

     const int status = m_pReader->Length(&total, &available);

-    assert(status == 0);

+

+    if (status < 0) //error

+        return status;

+

     assert((total < 0) || (available <= total));

 

     const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;

@@ -1185,55 +951,77 @@
 

         if (id == 0x0549A966)  //Segment Info ID

         {

-            assert(m_pInfo == NULL);

+            if (m_pInfo)

+                return E_FILE_FORMAT_INVALID;

 

-            m_pInfo = new SegmentInfo(this,

-                                      pos,

-                                      size,

-                                      element_start,

-                                      element_size);

-            assert(m_pInfo);  //TODO

+            m_pInfo = new (std::nothrow) SegmentInfo(

+                                          this,

+                                          pos,

+                                          size,

+                                          element_start,

+                                          element_size);

+

+            if (m_pInfo == NULL)

+                return -1;

+

+            const long status = m_pInfo->Parse();

+

+            if (status)

+                return status;

         }

         else if (id == 0x0654AE6B)  //Tracks ID

         {

-            assert(m_pTracks == NULL);

+            if (m_pTracks)

+                return E_FILE_FORMAT_INVALID;

 

-            m_pTracks = new Tracks(this,

-                                   pos,

-                                   size,

-                                   element_start,

-                                   element_size);

-            assert(m_pTracks);  //TODO

+            m_pTracks = new (std::nothrow) Tracks(this,

+                                                  pos,

+                                                  size,

+                                                  element_start,

+                                                  element_size);

+

+            if (m_pTracks == NULL)

+                return -1;

+

+            const long status = m_pTracks->Parse();

+

+            if (status)

+                return status;

         }

         else if (id == 0x0C53BB6B)  //Cues ID

         {

             if (m_pCues == NULL)

             {

-                m_pCues = new Cues(this,

-                                   pos,

-                                   size,

-                                   element_start,

-                                   element_size);

-                assert(m_pCues);  //TODO

+                m_pCues = new (std::nothrow) Cues(

+                                                this,

+                                                pos,

+                                                size,

+                                                element_start,

+                                                element_size);

+

+                if (m_pCues == NULL)

+                    return -1;

             }

         }

         else if (id == 0x014D9B74)  //SeekHead ID

         {

-#if 0

-            if (available >= total)

-                ParseSeekHead(pos, size);

-#else

             if (m_pSeekHead == NULL)

             {

-                m_pSeekHead = new SeekHead(this,

-                                           pos,

-                                           size,

-                                           element_start,

-                                           element_size);

+                m_pSeekHead = new (std::nothrow) SeekHead(

+                                                    this,

+                                                    pos,

+                                                    size,

+                                                    element_start,

+                                                    element_size);

 

-                assert(m_pSeekHead);  //TODO

+                if (m_pSeekHead == NULL)

+                    return -1;

+

+                const long status = m_pSeekHead->Parse();

+

+                if (status)

+                    return status;

             }

-#endif

         }

 

         m_pos = pos + size;  //consume payload

@@ -1251,248 +1039,6 @@
 }

 

 

-#if 0

-long Segment::FindNextCluster(long long& pos, size& len) const

-{

-    //Outermost (level 0) segment object has been constructed,

-    //and pos designates start of payload.  We need to find the

-    //inner (level 1) elements.

-    long long total, available;

-

-    const int status = m_pReader->Length(&total, &available);

-    assert(status == 0);

-    assert(total >= 0);

-    assert(available <= total);

-

-    const long long stop = m_start + m_size;

-    assert(stop <= total);

-    assert(m_pos <= stop);

-

-    pos = m_pos;

-

-    while (pos < stop)

-    {

-        long long result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)

-            return static_cast<long>(result);

-

-        if (result > 0)

-            return E_BUFFER_NOT_FULL;

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return E_BUFFER_NOT_FULL;

-

-        const long long idpos = pos;

-        const long long id = ReadUInt(m_pReader, idpos, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if (result > 0)

-            return E_BUFFER_NOT_FULL;

-

-        if ((pos + len) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + len) > available)

-            return E_BUFFER_NOT_FULL;

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos += len;  //consume length of size of element

-

-        //Pos now points to start of payload

-

-        if ((pos + size) > stop)

-            return E_FILE_FORMAT_INVALID;

-

-        if ((pos + size) > available)

-            return E_BUFFER_NOT_FULL;

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            len = static_cast<long>(size);

-            return 0;  //success

-        }

-

-        pos += size;  //consume payload

-    }

-

-    return E_FILE_FORMAT_INVALID;

-}

-#endif

-

-

-#if 0

-long Segment::ParseCluster(long long& off, long long& new_pos) const

-{

-    off = -1;

-    new_pos = -1;

-

-    const long long stop = m_start + m_size;

-    assert(m_pos <= stop);

-

-    long long pos = m_pos;

-

-    while (pos < stop)

-    {

-        long len;

-        const long long idpos = pos;

-

-        const long long id = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        if (id == 0)

-            return E_FILE_FORMAT_INVALID;

-

-        pos += len;  //consume id

-        assert(pos < stop);

-

-        const long long size = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        pos += len;  //consume size

-        assert(pos <= stop);

-

-        if (size == 0)  //weird

-            continue;

-

-        //pos now points to start of payload

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            const long long off_ = idpos - m_start;

-

-            if (Cluster::HasBlockEntries(this, off_))

-            {

-                off = off_;   // >= 0 means we found a cluster

-                break;

-            }

-        }

-    }

-

-    assert(pos <= stop);

-

-    //Indicate to caller how much of file has been consumed. This is

-    //used later in AddCluster to adjust the current parse position

-    //(the value cached in the segment object itself) to the

-    //file position value just past the cluster we parsed.

-

-    if (off < 0)  //we did not found any more clusters

-    {

-        new_pos = stop;  //pos >= 0 here means EOF (cluster is NULL)

-        return 0;        //TODO: confirm this return value

-    }

-

-    //We found a cluster.  Now read something, to ensure that it is

-    //fully loaded in the network cache.

-

-    if (pos >= stop)  //we parsed the entire segment

-    {

-        //We did find a cluster, but it was very last element in the segment.

-        //Our preference is that the loop above runs 1 1/2 times:

-        //the first pass finds the cluster, and the second pass

-        //finds the element the follows the cluster.  In this case, however,

-        //we reached the end of the file without finding another element,

-        //so we didn't actually read anything yet associated with "end of the

-        //cluster".  And we must perform an actual read, in order

-        //to guarantee that all of the data that belongs to this

-        //cluster has been loaded into the network cache.  So instead

-        //of reading the next element that follows the cluster, we

-        //read the last byte of the cluster (which is also the last

-        //byte in the file).

-

-        //Read the last byte of the file. (Reading 0 bytes at pos

-        //might work too -- it would depend on how the reader is

-        //implemented.  Here we take the more conservative approach,

-        //since this makes fewer assumptions about the network

-        //reader abstraction.)

-

-        unsigned char b;

-

-        const int result = m_pReader->Read(pos - 1, 1, &b);

-        assert(result == 0);

-

-        new_pos = stop;

-    }

-    else

-    {

-        long len;

-        const long long idpos = pos;

-

-        const long long id = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        if (id == 0)

-            return E_BUFFER_NOT_FULL;

-

-        pos += len;  //consume id

-        assert(pos < stop);

-

-        const long long size = SyncReadUInt(m_pReader, pos, stop, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        new_pos = idpos;

-    }

-

-    return 0;

-}

-

-

-bool Segment::AddCluster(long long off, long long pos)

-{

-    assert(pos >= m_start);

-

-    const long long stop = m_start + m_size;

-    assert(pos <= stop);

-

-    if (off >= 0)

-    {

-        Cluster* const pCluster = Cluster::Parse(this,

-                                                 m_clusterCount,

-                                                 off,

-                                                 0,

-                                                 0);

-        assert(pCluster);

-

-        AppendCluster(pCluster);

-        assert(m_clusters);

-        assert(m_clusterSize > pCluster->m_index);

-        assert(m_clusters[pCluster->m_index] == pCluster);

-    }

-

-    m_pos = pos;  //m_pos >= stop is now we know we have all clusters

-    return (pos >= stop);

-}

-#endif

-

-

 long Segment::LoadCluster(

     long long& pos,

     long& len)

@@ -2151,24 +1697,7 @@
 

     if (count >= size)

     {

-        long n;

-

-        if (size > 0)

-            n = 2 * size;

-        else if (m_pInfo == 0)

-            n = 2048;

-        else

-        {

-            const long long ns = m_pInfo->GetDuration();

-

-            if (ns <= 0)

-                n = 2048;

-            else

-            {

-                const long long sec = (ns + 999999999LL) / 1000000000LL;

-                n = static_cast<long>(sec);

-            }

-        }

+        const long n = (size <= 0) ? 2048 : 2*size;

 

         Cluster** const qq = new Cluster*[n];

         Cluster** q = qq;

@@ -2227,24 +1756,7 @@
 

     if (count >= size)

     {

-        long n;

-

-        if (size > 0)

-            n = 2 * size;

-        else if (m_pInfo == 0)

-            n = 2048;

-        else

-        {

-            const long long ns = m_pInfo->GetDuration();

-

-            if (ns <= 0)

-                n = 2048;

-            else

-            {

-                const long long sec = (ns + 999999999LL) / 1000000000LL;

-                n = static_cast<long>(sec);

-            }

-        }

+        const long n = (size <= 0) ? 2048 : 2*size;

 

         Cluster** const qq = new Cluster*[n];

         Cluster** q = qq;

@@ -2294,181 +1806,30 @@
     //and pos designates start of payload.  We need to find the

     //inner (level 1) elements.

 

-    long long total, avail;

+    const long long header_status = ParseHeaders();

 

-    long status = m_pReader->Length(&total, &avail);

+    if (header_status < 0)  //error

+        return static_cast<long>(header_status);

 

-    if (status < 0)  //error

-        return status;

+    if (header_status > 0)  //underflow

+        return E_BUFFER_NOT_FULL;

 

-    assert((total < 0) || (avail <= total));

-

-    const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;

+    assert(m_pInfo);

+    assert(m_pTracks);

 

     for (;;)

     {

-        long long pos = m_pos;

+        const int status = LoadCluster();

 

-        if ((total >= 0) && (pos >= total))

-            break;

+        if (status < 0)  //error

+            return status;

 

-        if ((segment_stop >= 0) && (pos >= segment_stop))

-            break;

-

-        const long long element_start = pos;

-

-        long len;

-

-        long long result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((segment_stop >= 0) && ((pos + len) > segment_stop))

-            return E_FILE_FORMAT_INVALID;

-

-        const long long idpos = pos;

-        const long long id = ReadUInt(m_pReader, idpos, len);

-

-        if (id < 0)  //error

-            return static_cast<long>(id);

-

-        pos += len;  //consume ID

-

-        //Read Size

-        result = GetUIntLength(m_pReader, pos, len);

-

-        if (result < 0)  //error

-            return static_cast<long>(result);

-

-        if ((segment_stop >= 0) && ((pos + len) > segment_stop))

-            return E_FILE_FORMAT_INVALID;

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-

-        if (size < 0)  //error

-            return static_cast<long>(size);

-

-        const long long unknown_size = (1LL << (7 * len)) - 1;

-

-        if (size == unknown_size)

-            return E_FILE_FORMAT_INVALID;

-

-        pos += len;  //consume length of size of element

-

-        //Pos now points to start of payload

-

-        const long long element_size = (pos - element_start) + size;

-

-        if ((segment_stop >= 0) && ((pos + size) > segment_stop))

-            return E_FILE_FORMAT_INVALID;

-

-        if (id == 0x0F43B675)  //Cluster ID

-        {

-            const long idx = m_clusterCount;

-            const long long off = idpos - m_start;

-

-            long long pos_;

-            long len_;

-

-            status = Cluster::HasBlockEntries(this, off, pos_, len_);

-

-            if (status < 0)  //weird: error or underflow

-                return status;

-

-            if (status > 0)  //have block entries

-            {

-                Cluster* const pCluster = Cluster::Create(this,

-                                                         idx,

-                                                         off);

-                                                         //element_size);

-                assert(pCluster);

-

-                AppendCluster(pCluster);

-                assert(m_clusters);

-                assert(m_clusterSize > idx);

-                assert(m_clusters[idx] == pCluster);

-            }

-        }

-        else if (id == 0x0C53BB6B)  //Cues ID

-        {

-            assert(m_pCues == NULL);

-

-            m_pCues = new Cues(this, pos, size, element_start, element_size);

-            assert(m_pCues);  //TODO

-        }

-        else if (id == 0x0549A966)  //SegmentInfo ID

-        {

-            assert(m_pInfo == NULL);

-

-            m_pInfo = new SegmentInfo(this,

-                                      pos,

-                                      size,

-                                      element_start,

-                                      element_size);

-            assert(m_pInfo);

-        }

-        else if (id == 0x0654AE6B)  //Tracks ID

-        {

-            assert(m_pTracks == NULL);

-

-            m_pTracks = new Tracks(this,

-                                   pos,

-                                   size,

-                                   element_start,

-                                   element_size);

-            assert(m_pTracks);  //TODO

-        }

-

-        m_pos = pos + size;  //consume payload

+        if (status >= 1)  //no more clusters

+            return 0;

     }

-

-    if (m_pInfo == NULL)

-        return E_FILE_FORMAT_INVALID;  //TODO: ignore this case?

-

-    if (m_pTracks == NULL)

-        return E_FILE_FORMAT_INVALID;

-

-    if (m_clusters == NULL)  //TODO: ignore this case?

-        return E_FILE_FORMAT_INVALID;

-

-    return 0;

 }

 

 

-#if 0

-void Segment::ParseSeekHead(long long start, long long size_)

-{

-    long long pos = start;

-    const long long stop = start + size_;

-

-    while (pos < stop)

-    {

-        long len;

-

-        const long long id = ReadUInt(m_pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(m_pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

-

-        if (id == 0x0DBB)  //SeekEntry ID

-            ParseSeekEntry(pos, size);

-

-        pos += size;  //consume payload

-        assert(pos <= stop);

-    }

-

-    assert(pos == stop);

-}

-#else

 SeekHead::SeekHead(

     Segment* pSegment,

     long long start,

@@ -2485,11 +1846,23 @@
     m_void_elements(0),

     m_void_element_count(0)

 {

-    long long pos = start;

-    const long long stop = start + size_;

+}

 

+

+SeekHead::~SeekHead()

+{

+    delete[] m_entries;

+    delete[] m_void_elements;

+}

+

+

+long SeekHead::Parse()

+{

     IMkvReader* const pReader = m_pSegment->m_pReader;

 

+    long long pos = m_start;

+    const long long stop = m_start + m_size;

+

     //first count the seek head entries

 

     int entry_count = 0;

@@ -2497,20 +1870,17 @@
 

     while (pos < stop)

     {

-        long len;

+        long long id, size;

 

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

 

-        pos += len;  //consume ID

-

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

-

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

+        if (status < 0)  //error

+            return status;

 

         if (id == 0x0DBB)  //SeekEntry ID

             ++entry_count;

@@ -2524,41 +1894,44 @@
     assert(pos == stop);

 

     m_entries = new (std::nothrow) Entry[entry_count];

-    assert(m_entries);  //TODO

+

+    if (m_entries == NULL)

+        return -1;

 

     m_void_elements = new (std::nothrow) VoidElement[void_element_count];

-    assert(m_void_elements);  //TODO

+

+    if (m_void_elements == NULL)

+        return -1;

 

     //now parse the entries and void elements

 

     Entry* pEntry = m_entries;

     VoidElement* pVoidElement = m_void_elements;

 

-    pos = start;

+    pos = m_start;

 

     while (pos < stop)

     {

-        long len;

-

         const long long idpos = pos;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO

-        assert((pos + len) <= stop);

 

-        pos += len;  //consume ID

+        long long id, size;

 

-        const long long size = ReadUInt(pReader, pos, len);

-        assert(size >= 0);

-        assert((pos + len) <= stop);

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

 

-        pos += len;  //consume Size field

-        assert((pos + size) <= stop);

+        if (status < 0)  //error

+            return status;

 

         if (id == 0x0DBB)  //SeekEntry ID

         {

             if (ParseEntry(pReader, pos, size, pEntry))

             {

                 Entry& e = *pEntry++;

+

                 e.element_start = idpos;

                 e.element_size = (pos + size) - idpos;

             }

@@ -2588,13 +1961,10 @@
     assert(count_ <= void_element_count);

 

     m_void_element_count = static_cast<int>(count_);

+

+    return 0;

 }

 

-SeekHead::~SeekHead()

-{

-    delete[] m_entries;

-    delete[] m_void_elements;

-}

 

 int SeekHead::GetCount() const

 {

@@ -2627,7 +1997,6 @@
 

     return m_void_elements + idx;

 }

-#endif

 

 

 #if 0

@@ -2871,6 +2240,9 @@
     long long size_,

     Entry* pEntry)

 {

+    if (size_ <= 0)

+        return false;

+

     long long pos = start;

     const long long stop = start + size_;

 

@@ -3066,29 +2438,7 @@
 

     if (m_preload_count >= cue_points_size)

     {

-        long n;

-

-        if (cue_points_size > 0)

-            n = 2 * cue_points_size;

-        else

-        {

-            const SegmentInfo* const pInfo = m_pSegment->GetInfo();

-

-            if (pInfo == NULL)

-                n = 2048;

-            else

-            {

-                const long long ns = pInfo->GetDuration();

-

-                if (ns <= 0)

-                    n = 2048;

-                else

-                {

-                    const long long sec = (ns + 999999999LL) / 1000000000LL;

-                    n = static_cast<long>(sec);

-                }

-            }

-        }

+        const long n = (cue_points_size <= 0) ? 2048 : 2*cue_points_size;

 

         CuePoint** const qq = new CuePoint*[n];

         CuePoint** q = qq;  //beginning of target

@@ -4887,75 +4237,113 @@
     m_pWritingAppAsUTF8(NULL),

     m_pTitleAsUTF8(NULL)

 {

+}

+

+SegmentInfo::~SegmentInfo()

+{

+    delete[] m_pMuxingAppAsUTF8;

+    m_pMuxingAppAsUTF8 = NULL;

+

+    delete[] m_pWritingAppAsUTF8;

+    m_pWritingAppAsUTF8 = NULL;

+

+    delete[] m_pTitleAsUTF8;

+    m_pTitleAsUTF8 = NULL;

+}

+

+

+long SegmentInfo::Parse()

+{

+    assert(m_pMuxingAppAsUTF8 == NULL);

+    assert(m_pWritingAppAsUTF8 == NULL);

+    assert(m_pTitleAsUTF8 == NULL);

+

     IMkvReader* const pReader = m_pSegment->m_pReader;

 

-    long long pos = start;

-    const long long stop = start + size_;

+    long long pos = m_start;

+    const long long stop = m_start + m_size;

 

     m_timecodeScale = 1000000;

     m_duration = -1;

 

     while (pos < stop)

     {

-        if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale))

-            assert(m_timecodeScale > 0);

+        long long id, size;

 

-        else if (Match(pReader, pos, 0x0489, m_duration))

-            assert(m_duration >= 0);

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

 

-        else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8))   //[4D][80]

-            assert(m_pMuxingAppAsUTF8);

+        if (status < 0)  //error

+            return status;

 

-        else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8))  //[57][41]

-            assert(m_pWritingAppAsUTF8);

-

-        else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8))       //[7B][A9]

-            assert(m_pTitleAsUTF8);

-

-        else

+        if (id == 0x0AD7B1)  //Timecode Scale

         {

-            long len;

+            m_timecodeScale = UnserializeUInt(pReader, pos, size);

 

-            const long long id = ReadUInt(pReader, pos, len);

-            //id;

-            assert(id >= 0);

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume id

-            assert((stop - pos) > 0);

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);

-            assert((pos + len) <= stop);

-

-            pos += len + size;  //consume size and payload

-            assert(pos <= stop);

+            if (m_timecodeScale <= 0)

+                return E_FILE_FORMAT_INVALID;

         }

+        else if (id == 0x0489)  //Segment duration

+        {

+            const long status = UnserializeFloat(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    m_duration);

+

+            if (status < 0)

+                return status;

+

+            if (m_duration < 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x0D80)  //MuxingApp

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    m_pMuxingAppAsUTF8);

+

+            if (status)

+                return status;

+        }

+        else if (id == 0x1741)  //WritingApp

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    m_pWritingAppAsUTF8);

+

+            if (status)

+                return status;

+        }

+        else if (id == 0x3BA9)  //Title

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    m_pTitleAsUTF8);

+

+            if (status)

+                return status;

+        }

+

+        pos += size;

+        assert(pos <= stop);

     }

 

     assert(pos == stop);

+

+    return 0;

 }

 

-SegmentInfo::~SegmentInfo()

-{

-    if (m_pMuxingAppAsUTF8)

-    {

-        delete[] m_pMuxingAppAsUTF8;

-        m_pMuxingAppAsUTF8 = NULL;

-    }

-

-    if (m_pWritingAppAsUTF8)

-    {

-        delete[] m_pWritingAppAsUTF8;

-        m_pWritingAppAsUTF8 = NULL;

-    }

-

-    if (m_pTitleAsUTF8)

-    {

-        delete[] m_pTitleAsUTF8;

-        m_pTitleAsUTF8 = NULL;

-    }

-}

 

 long long SegmentInfo::GetTimeCodeScale() const

 {

@@ -5266,13 +4654,11 @@
 

 Track::Track(

     Segment* pSegment,

-    const Info& i,

     long long element_start,

     long long element_size) :

     m_pSegment(pSegment),

     m_element_start(element_start),

     m_element_size(element_size),

-    m_info(i),

     content_encoding_entries_(NULL),

     content_encoding_entries_end_(NULL)

 {

@@ -5295,17 +4681,19 @@
 }

 

 Track::Info::Info():

-    type(-1),

-    number(-1),

-    uid(ULLONG_MAX),

     nameAsUTF8(NULL),

     codecId(NULL),

+    codecNameAsUTF8(NULL),

     codecPrivate(NULL),

-    codecPrivateSize(0),

-    codecNameAsUTF8(NULL)

+    codecPrivateSize(0)

 {

 }

 

+Track::Info::~Info()

+{

+    Clear();

+}

+

 void Track::Info::Clear()

 {

     delete[] nameAsUTF8;

@@ -5316,24 +4704,100 @@
 

     delete[] codecPrivate;

     codecPrivate = NULL;

-

     codecPrivateSize = 0;

 

     delete[] codecNameAsUTF8;

     codecNameAsUTF8 = NULL;

 }

 

+int Track::Info::CopyStr(char* Info::*str, Info& dst_) const

+{

+    if (str == static_cast<char* Info::*>(NULL))

+        return -1;

+

+    char*& dst = dst_.*str;

+

+    if (dst)  //should be NULL already

+        return -1;

+

+    const char* const src = this->*str;

+

+    if (src == NULL)

+        return 0;

+

+    const size_t len = strlen(src);

+

+    dst = new (std::nothrow) char[len+1];

+

+    if (dst == NULL)

+        return -1;

+

+    strcpy(dst, src);

+

+    return 0;

+}

+

+

+int Track::Info::Copy(Info& dst) const

+{

+    if (&dst == this)

+        return 0;

+

+    dst.type = type;

+    dst.number = number;

+    dst.uid = uid;

+    dst.lacing = lacing;

+    dst.settings = settings;

+

+    //We now copy the string member variables from src to dst.

+    //This involves memory allocation so in principle the operation

+    //can fail (indeed, that's why we have Info::Copy), so we must

+    //report this to the caller.  An error return from this function

+    //therefore implies that the copy was only partially successful.

+

+    if (int status = CopyStr(&Info::nameAsUTF8, dst))

+        return status;

+

+    if (int status = CopyStr(&Info::codecId, dst))

+        return status;

+

+    if (int status = CopyStr(&Info::codecNameAsUTF8, dst))

+        return status;

+

+    if (codecPrivateSize > 0)

+    {

+        if (codecPrivate == NULL)

+            return -1;

+

+        if (dst.codecPrivate)

+            return -1;

+

+        if (dst.codecPrivateSize != 0)

+            return -1;

+

+        dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];

+

+        if (dst.codecPrivate == NULL)

+            return -1;

+

+        memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);

+        dst.codecPrivateSize = codecPrivateSize;

+    }

+

+    return 0;

+}

+

 const BlockEntry* Track::GetEOS() const

 {

     return &m_eos;

 }

 

-long long Track::GetType() const

+long Track::GetType() const

 {

     return m_info.type;

 }

 

-long long Track::GetNumber() const

+long Track::GetNumber() const

 {

     return m_info.number;

 }

@@ -5667,16 +5131,29 @@
 

 VideoTrack::VideoTrack(

     Segment* pSegment,

-    const Info& i,

     long long element_start,

     long long element_size) :

-    Track(pSegment, i, element_start, element_size),

-    m_width(-1),

-    m_height(-1),

-    m_rate(-1)

+    Track(pSegment, element_start, element_size)

 {

-    assert(i.type == 1);

-    assert(i.number > 0);

+}

+

+

+long VideoTrack::Parse(

+    Segment* pSegment,

+    const Info& i,

+    long long elem_st,

+    long long elem_sz,

+    VideoTrack*& pTrack)

+{

+    if (pTrack)

+        return -1;

+

+    if (i.type != Track::kVideo)

+        return -1;

+

+    long long width = 0;

+    long long height = 0;

+    double rate = 0.0;

 

     IMkvReader* const pReader = pSegment->m_pReader;

 

@@ -5691,42 +5168,68 @@
 

     while (pos < stop)

     {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO: handle error case

-        assert((pos + len) <= stop);

-#endif

-        if (Match(pReader, pos, 0x30, m_width))

-            ;

-        else if (Match(pReader, pos, 0x3A, m_height))

-            ;

-        else if (Match(pReader, pos, 0x0383E3, m_rate))

-            ;

-        else

+        long long id, size;

+

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

+

+        if (status < 0)  //error

+            return status;

+

+        if (id == 0x30)  //pixel width

         {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

+            width = UnserializeUInt(pReader, pos, size);

 

-            pos += len;  //consume id

-

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume length of size

-            assert((pos + size) <= stop);

-

-            //pos now designates start of payload

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

+            if (width <= 0)

+                return E_FILE_FORMAT_INVALID;

         }

+        else if (id == 0x3A)  //pixel height

+        {

+            height = UnserializeUInt(pReader, pos, size);

+

+            if (height <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x0383E3)  //frame rate

+        {

+            const long status = UnserializeFloat(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    rate);

+

+            if (status < 0)

+                return status;

+

+            if (rate <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+

+        pos += size;  //consume payload

+        assert(pos <= stop);

     }

 

-    return;

+    assert(pos == stop);

+

+    pTrack = new (std::nothrow) VideoTrack(pSegment, elem_st, elem_sz);

+

+    if (pTrack == NULL)

+        return -1;  //generic error

+

+    const int status = i.Copy(pTrack->m_info);

+

+    if (status)

+        return status;

+

+    pTrack->m_width = width;

+    pTrack->m_height = height;

+    pTrack->m_rate = rate;

+

+    return 0;  //success

 }

 

 

@@ -5866,16 +5369,25 @@
 

 AudioTrack::AudioTrack(

     Segment* pSegment,

-    const Info& i,

     long long element_start,

     long long element_size) :

-    Track(pSegment, i, element_start, element_size),

-    m_rate(0.0),

-    m_channels(0),

-    m_bitDepth(-1)

+    Track(pSegment, element_start, element_size)

 {

-    assert(i.type == 2);

-    assert(i.number > 0);

+}

+

+

+long AudioTrack::Parse(

+    Segment* pSegment,

+    const Info& i,

+    long long elem_st,

+    long long elem_sz,

+    AudioTrack*& pTrack)

+{

+    if (pTrack)

+        return -1;

+

+    if (i.type != Track::kAudio)

+        return -1;

 

     IMkvReader* const pReader = pSegment->m_pReader;

 

@@ -5888,47 +5400,70 @@
 

     const long long stop = pos + s.size;

 

+    double rate = 8000.0;

+    long long channels = 1;

+    long long bit_depth = 0;

+

     while (pos < stop)

     {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);  //TODO: handle error case

-        assert((pos + len) <= stop);

-#endif

-        if (Match(pReader, pos, 0x35, m_rate))

-            ;

-        else if (Match(pReader, pos, 0x1F, m_channels))

-            ;

-        else if (Match(pReader, pos, 0x2264, m_bitDepth))

-            ;

-        else

+        long long id, size;

+

+        long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

+

+        if (status < 0)  //error

+            return status;

+

+        if (id == 0x35)  //Sample Rate

         {

-            long len;

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

+            status = UnserializeFloat(pReader, pos, size, rate);

 

-            pos += len;  //consume id

+            if (status < 0)

+                return status;

 

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

-

-            pos += len;  //consume length of size

-            assert((pos + size) <= stop);

-

-            //pos now designates start of payload

-

-            pos += size;  //consume payload

-            assert(pos <= stop);

+            if (rate <= 0)

+                return E_FILE_FORMAT_INVALID;

         }

+        else if (id == 0x1F)  //Channel Count

+        {

+            channels = UnserializeUInt(pReader, pos, size);

+

+            if (channels <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x2264)  //Bit Depth

+        {

+            bit_depth = UnserializeUInt(pReader, pos, size);

+

+            if (bit_depth <= 0)

+                return E_FILE_FORMAT_INVALID;

+        }

+

+        pos += size;  //consume payload

+        assert(pos <= stop);

     }

 

-    if (m_channels <= 0)

-        m_channels = 1;  //Matroska spec says this is the default

+    assert(pos == stop);

 

-    return;

+    pTrack = new (std::nothrow) AudioTrack(pSegment, elem_st, elem_sz);

+

+    if (pTrack == NULL)

+        return -1;  //generic error

+

+    const int status = i.Copy(pTrack->m_info);

+

+    if (status)

+        return status;

+

+    pTrack->m_rate = rate;

+    pTrack->m_channels = channels;

+    pTrack->m_bitDepth = bit_depth;

+

+    return 0;  //success

 }

 

 

@@ -6059,76 +5594,108 @@
     m_trackEntries(NULL),

     m_trackEntriesEnd(NULL)

 {

-    long long stop = m_start + m_size;

+}

+

+

+long Tracks::Parse()

+{

+    assert(m_trackEntries == NULL);

+    assert(m_trackEntriesEnd == NULL);

+

+    const long long stop = m_start + m_size;

     IMkvReader* const pReader = m_pSegment->m_pReader;

 

-    long long pos1 = m_start;

     int count = 0;

-

-    while (pos1 < stop)

-    {

-        long len;

-        const long long id = ReadUInt(pReader, pos1, len);

-        assert(id >= 0);

-        assert((pos1 + len) <= stop);

-

-        pos1 += len;  //consume id

-

-        const long long size = ReadUInt(pReader, pos1, len);

-        assert(size >= 0);

-        assert((pos1 + len) <= stop);

-

-        pos1 += len;  //consume length of size

-

-        //pos now desinates start of element

-        if (id == 0x2E)  //TrackEntry ID

-            ++count;

-

-        pos1 += size;  //consume payload

-        assert(pos1 <= stop);

-    }

-

-    if (count <= 0)

-        return;

-

-    m_trackEntries = new Track*[count];

-    m_trackEntriesEnd = m_trackEntries;

-

     long long pos = m_start;

 

     while (pos < stop)

     {

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        assert(id >= 0);

-        assert((pos + len) <= stop);

+        long long id, size;

 

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                size);

+

+        if (status < 0)  //error

+            return status;

+

+        if (size == 0)  //weird

+            continue;

+

+        if (id == 0x2E)  //TrackEntry ID

+            ++count;

+

+        pos += size;  //consume payload

+        assert(pos <= stop);

+    }

+

+    assert(pos == stop);

+

+    if (count <= 0)

+        return 0;  //success

+

+    m_trackEntries = new (std::nothrow) Track*[count];

+

+    if (m_trackEntries == NULL)

+        return -1;

+

+    m_trackEntriesEnd = m_trackEntries;

+

+    pos = m_start;

+

+    while (pos < stop)

+    {

         const long long element_start = pos;

 

-        pos += len;  //consume id

+        long long id, payload_size;

 

-        const long long size1 = ReadUInt(pReader, pos, len);

-        assert(size1 >= 0);

-        assert((pos + len) <= stop);

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                stop,

+                                id,

+                                payload_size);

 

-        pos += len;  //consume length of size

+        if (status < 0)  //error

+            return status;

 

-        //pos now desinates start of element

+        if (payload_size == 0)  //weird

+            continue;

 

-        const long long element_size = size1 + pos - element_start;

+        const long long payload_stop = pos + payload_size;

+        assert(payload_stop <= stop);  //checked in ParseElement

+

+        const long long element_size = payload_stop - element_start;

 

         if (id == 0x2E)  //TrackEntry ID

         {

             Track*& pTrack = *m_trackEntriesEnd;

-            ParseTrackEntry(pos, size1, pTrack, element_start, element_size);

+            pTrack = NULL;

+

+            const long status = ParseTrackEntry(

+                                    pos,

+                                    payload_size,

+                                    element_start,

+                                    element_size,

+                                    pTrack);

+

+            if (status)

+                return status;

 

             if (pTrack)

                 ++m_trackEntriesEnd;

         }

 

-        pos += size1;  //consume payload

+        pos = payload_stop;

         assert(pos <= stop);

     }

+

+    assert(pos == stop);

+

+    return 0;  //success

 }

 

 

@@ -6140,181 +5707,264 @@
     return static_cast<unsigned long>(result);

 }

 

-void Tracks::ParseTrackEntry(

-    long long start,

-    long long size,

-    Track*& pTrack,

-    long long element_start,

-    long long element_size)

+long Tracks::ParseTrackEntry(

+    long long track_start,

+    long long track_size,

+    long long elem_st,

+    long long elem_sz,

+    Track*& pTrack) const

 {

+    if (pTrack)

+        return -1;

+

     IMkvReader* const pReader = m_pSegment->m_pReader;

 

-    long long pos = start;

-    const long long stop = start + size;

+    long long pos = track_start;

+    const long long track_stop = track_start + track_size;

 

     Track::Info i;

 

-    Track::Settings videoSettings;

-    videoSettings.start = -1;

-    videoSettings.size = -1;

+    i.type = 0;

+    i.number = 0;

+    i.uid = 0;

 

-    Track::Settings audioSettings;

-    audioSettings.start = -1;

-    audioSettings.size = -1;

+    Track::Settings v;

+    v.start = -1;

+    v.size = -1;

 

-    Track::Settings content_encodings_settings;

-    content_encodings_settings.start = -1;

-    content_encodings_settings.size = -1;

+    Track::Settings a;

+    a.start = -1;

+    a.size = -1;

+

+    Track::Settings e;  //content_encodings_settings;

+    e.start = -1;

+    e.size = -1;

 

     long long lacing = 1;  //default is true

 

-    while (pos < stop)

+    while (pos < track_stop)

     {

-#ifdef _DEBUG

-        long len;

-        const long long id = ReadUInt(pReader, pos, len);

-        len;

-        id;

-#endif

-        if (Match(pReader, pos, 0x57, i.number))

-            assert(i.number > 0);

-        //else if (Match(pReader, pos, 0x33C5, i.uid))

-        //    ;

-        else if (Match(pReader, pos, 0x03, i.type))

-            ;

-        else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))

-            assert(i.nameAsUTF8);

-        else if (Match(pReader, pos, 0x06, i.codecId))

-            ;

-        else if (Match(pReader, pos, 0x1C, lacing))

-            assert(lacing <= 1);

-        else if (Match(pReader,

-                       pos,

-                       0x23A2,

-                       i.codecPrivate,

-                       i.codecPrivateSize))

-            ;

-        else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))

-            assert(i.codecNameAsUTF8);

-        else

+        long long id, size;

+

+        const long status = ParseElementHeader(

+                                pReader,

+                                pos,

+                                track_stop,

+                                id,

+                                size);

+

+        if (status < 0)  //error

+            return status;

+

+        const long long start = pos;

+

+        if (id == 0x60)  // VideoSettings ID

         {

-            long len;

+            if (size <= 0)

+                return E_FILE_FORMAT_INVALID;

 

-            const long long idpos = pos;

-            (void)idpos;

+            v.start = start;

+            v.size = size;

+        }

+        else if (id == 0x61)  // AudioSettings ID

+        {

+            if (size <= 0)

+                return E_FILE_FORMAT_INVALID;

 

-            const long long id = ReadUInt(pReader, pos, len);

-            assert(id >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

+            a.start = start;

+            a.size = size;

+        }

+        else if (id == 0x2D80) // ContentEncodings ID

+        {

+            if (size <= 0)

+                return E_FILE_FORMAT_INVALID;

 

-            pos += len;  //consume id

+            e.start = start;

+            e.size = size;

+        }

+        else if (id == 0x33C5)  //Track UID

+        {

+            if ((size <= 0) || (size > 8))

+                return E_FILE_FORMAT_INVALID;

 

-            const long long size = ReadUInt(pReader, pos, len);

-            assert(size >= 0);  //TODO: handle error case

-            assert((pos + len) <= stop);

+            i.uid = 0;

 

-            pos += len;  //consume length of size

-            const long long start = pos;

+            long long pos_ = start;

+            const long long pos_end = start + size;

 

-            pos += size;  //consume payload

-            assert(pos <= stop);

-

-            if (id == 0x60)

+            while (pos_ != pos_end)

             {

-                videoSettings.start = start;

-                videoSettings.size = size;

-            }

-            else if (id == 0x61)

-            {

-                audioSettings.start = start;

-                audioSettings.size = size;

-            }

-            else if (id == 0x2D80) // ContentEncodings id

-            {

-                content_encodings_settings.start = start;

-                content_encodings_settings.size = size;

-            }

-            else if (id == 0x33C5)  //Track UID

-            {

-                assert(size <= 8);

+                unsigned char b;

 

-                i.uid = 0;

-                long long pos_ = start;

-                const long long pos_end = start + size;

+                const int status = pReader->Read(pos_, 1, &b);

 

-                while (pos_ != pos_end)

-                {

-                    unsigned char b;

+                if (status)

+                    return status;

 

-                    const long status = pReader->Read(pos_, 1, &b);

-                    assert(status == 0);

+                i.uid <<= 8;

+                i.uid |= b;

 

-                    i.uid <<= 8;

-                    i.uid |= b;

-

-                    ++pos_;

-                }

+                ++pos_;

             }

         }

+        else if (id == 0x57)  //Track Number

+        {

+            const long long num = UnserializeUInt(pReader, pos, size);

+

+            if ((num <= 0) || (num > 127))

+                return E_FILE_FORMAT_INVALID;

+

+            i.number = static_cast<long>(num);

+        }

+        else if (id == 0x03)  //Track Type

+        {

+            const long long type = UnserializeUInt(pReader, pos, size);

+

+            if ((type <= 0) || (type > 254))

+                return E_FILE_FORMAT_INVALID;

+

+            i.type = static_cast<long>(type);

+        }

+        else if (id == 0x136E)  //Track Name

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    i.nameAsUTF8);

+

+            if (status)

+                return status;

+        }

+        else if (id == 0x06)  //CodecID

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    i.codecId);

+

+            if (status)

+                return status;

+        }

+        else if (id == 0x1C)  //lacing

+        {

+            lacing = UnserializeUInt(pReader, pos, size);

+

+            if ((lacing < 0) || (lacing > 1))

+                return E_FILE_FORMAT_INVALID;

+        }

+        else if (id == 0x23A2)  //Codec Private

+        {

+            delete[] i.codecPrivate;

+            i.codecPrivate = NULL;

+            i.codecPrivateSize = 0;

+

+            if (size <= 0)

+                return E_FILE_FORMAT_INVALID;

+

+            const size_t buflen = static_cast<size_t>(size);

+

+            typedef unsigned char* buf_t;

+

+            const buf_t buf = new (std::nothrow) unsigned char[buflen];

+

+            if (buf == NULL)

+                return -1;

+

+            const int status = pReader->Read(pos, buflen, buf);

+

+            if (status)

+            {

+                delete[] buf;

+                return status;

+            }

+

+            i.codecPrivate = buf;

+            i.codecPrivateSize = buflen;

+        }

+        else if (id == 0x058688)  //Codec Name

+        {

+            const long status = UnserializeString(

+                                    pReader,

+                                    pos,

+                                    size,

+                                    i.codecNameAsUTF8);

+

+            if (status)

+                return status;

+        }

+

+        pos += size;  //consume payload

+        assert(pos <= track_stop);

     }

 

-    assert(pos == stop);

-    //TODO: propertly vet info.number, to ensure both its existence,

-    //and that it is unique among all tracks.

-    assert(i.number > 0);

+    assert(pos == track_stop);

+

+    if (i.number <= 0)  //not specified

+        return E_FILE_FORMAT_INVALID;

+

+    if (GetTrackByNumber(i.number))

+        return E_FILE_FORMAT_INVALID;

+

+    if (i.type <= 0)  //not specified

+        return E_FILE_FORMAT_INVALID;

+

+    if ((i.type != Track::kVideo) && (i.type != Track::kAudio))

+    {

+        //TODO(matthewjheaney): go ahead and create a "generic" track

+        //object, so that GetTrackByXXX always returns something, even

+        //if the object it returns has a type that is not kVideo or kAudio.

+

+        return 0;  //no error

+    }

 

     i.lacing = (lacing > 0) ? true : false;

 

-    //TODO: vet settings, to ensure that video settings (0x60)

-    //were specified when type = 1, and that audio settings (0x61)

-    //were specified when type = 2.

-    if (i.type == 1)  //video

+    long status;

+

+    if (i.type == Track::kVideo)

     {

-        assert(audioSettings.start < 0);

-        assert(videoSettings.start >= 0);

+        if (v.start < 0)

+            return E_FILE_FORMAT_INVALID;

 

-        i.settings = videoSettings;

+        if (a.start >= 0)

+            return E_FILE_FORMAT_INVALID;

 

-        VideoTrack* const t = new VideoTrack(

-            m_pSegment,

-            i,

-            element_start,

-            element_size);

-        assert(t);  //TODO

-        pTrack = t;

-    }

-    else if (i.type == 2)  //audio

-    {

-        assert(videoSettings.start < 0);

-        assert(audioSettings.start >= 0);

+        i.settings = v;

 

-        i.settings = audioSettings;

+        VideoTrack* p = NULL;

 

-        AudioTrack* const t = new  AudioTrack(

-            m_pSegment,

-            i,

-            element_start,

-            element_size);

-        assert(t);  //TODO

-        pTrack = t;

+        status = VideoTrack::Parse(m_pSegment, i, elem_st, elem_sz, p);

+        pTrack = p;

     }

     else

     {

-        // for now we do not support other track types yet.

-        // TODO: support other track types

-        i.Clear();

+        assert(i.type == Track::kAudio);

 

-        pTrack = NULL;

+        if (a.start < 0)

+            return E_FILE_FORMAT_INVALID;

+

+        if (v.start >= 0)

+            return E_FILE_FORMAT_INVALID;

+

+        i.settings = a;

+

+        AudioTrack* p = NULL;

+

+        status = AudioTrack::Parse(m_pSegment, i, elem_st, elem_sz, p);

+        pTrack = p;

     }

 

-    if (content_encodings_settings.start > 0) {

-        assert(content_encodings_settings.size > 0);

-        assert(pTrack);

-        pTrack->ParseContentEncodingsEntry(content_encodings_settings.start,

-                                           content_encodings_settings.size);

-    }

+    if (status)

+        return status;

 

-    return;

+    assert(pTrack);

+

+    if (e.start >= 0)

+        pTrack->ParseContentEncodingsEntry(e.start, e.size);

+

+    return 0;  //success

 }

 

 

@@ -6332,9 +5982,10 @@
     delete[] m_trackEntries;

 }

 

-const Track* Tracks::GetTrackByNumber(unsigned long tn_) const

+const Track* Tracks::GetTrackByNumber(long tn) const

 {

-    const long long tn = tn_;

+    if (tn < 0)

+        return NULL;

 

     Track** i = m_trackEntries;

     Track** const j = m_trackEntriesEnd;

@@ -6881,6 +6532,25 @@
     if (track == 0)

         return E_FILE_FORMAT_INVALID;

 

+#if 0

+    //TODO(matthewjheaney)

+    //This turned out to be too conservative.  The problem is that

+    //if we see a track header in the tracks element with an unsupported

+    //track type, we throw that track header away, so it is not present

+    //in the track map.  But even though we don't understand the track

+    //header, there are still blocks in the cluster with that track

+    //number.  It was our decision to ignore that track header, so it's

+    //up to us to deal with blocks associated with that track -- we

+    //cannot simply report an error since technically there's nothing

+    //wrong with the file.

+    //

+    //For now we go ahead and finish the parse, creating a block entry

+    //for this block.  This is somewhat wasteful, because without a

+    //track header there's nothing you can do with the block. What

+    //we really need here is a special return value that indicates to

+    //the caller that he should ignore this particular block, and

+    //continue parsing.

+

     const Tracks* const pTracks = m_pSegment->GetTracks();

     assert(pTracks);

 

@@ -6890,6 +6560,7 @@
 

     if (pTrack == NULL)

         return E_FILE_FORMAT_INVALID;

+#endif

 

     pos += len;  //consume track number

 

@@ -7097,6 +6768,25 @@
         if (track == 0)

             return E_FILE_FORMAT_INVALID;

 

+#if 0

+        //TODO(matthewjheaney)

+        //This turned out to be too conservative.  The problem is that

+        //if we see a track header in the tracks element with an unsupported

+        //track type, we throw that track header away, so it is not present

+        //in the track map.  But even though we don't understand the track

+        //header, there are still blocks in the cluster with that track

+        //number.  It was our decision to ignore that track header, so it's

+        //up to us to deal with blocks associated with that track -- we

+        //cannot simply report an error since technically there's nothing

+        //wrong with the file.

+        //

+        //For now we go ahead and finish the parse, creating a block entry

+        //for this block.  This is somewhat wasteful, because without a

+        //track header there's nothing you can do with the block. What

+        //we really need here is a special return value that indicates to

+        //the caller that he should ignore this particular block, and

+        //continue parsing.

+

         const Tracks* const pTracks = m_pSegment->GetTracks();

         assert(pTracks);

 

@@ -7106,6 +6796,7 @@
 

         if (pTrack == NULL)

             return E_FILE_FORMAT_INVALID;

+#endif

 

         pos += len;  //consume track number

 

@@ -7591,16 +7282,13 @@
 

 long long Cluster::GetTimeCode() const

 {

-#if 0

-    Load();

-#else

     long long pos;

     long len;

 

     const long status = Load(pos, len);

-    status;

-    assert(status == 0);

-#endif

+

+    if (status < 0) //error

+        return status;

 

     return m_timecode;

 }

@@ -7609,7 +7297,9 @@
 long long Cluster::GetTime() const

 {

     const long long tc = GetTimeCode();

-    assert(tc >= 0);

+

+    if (tc < 0)

+        return tc;

 

     const SegmentInfo* const pInfo = m_pSegment->GetInfo();

     assert(pInfo);

@@ -8211,9 +7901,6 @@
 

         while (index >= m_entries_count)

         {

-            const long old_entries_count = m_entries_count;

-            old_entries_count;

-

             long long pos;

             long len;

 

@@ -8224,9 +7911,6 @@
 

             if (status > 0)  //nothing remains to be parsed

                 return NULL;

-

-            assert(m_entries);

-            assert(m_entries_count > old_entries_count);

         }

 

         const BlockEntry* const pEntry = m_entries[index];

diff --git a/mkvparser.hpp b/mkvparser.hpp
index 63a4d16..7e4abec 100644
--- a/mkvparser.hpp
+++ b/mkvparser.hpp
@@ -30,23 +30,26 @@
 

 long long GetUIntLength(IMkvReader*, long long, long&);

 long long ReadUInt(IMkvReader*, long long, long&);

-long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);

 long long UnserializeUInt(IMkvReader*, long long pos, long long size);

-float Unserialize4Float(IMkvReader*, long long);

-double Unserialize8Double(IMkvReader*, long long);

 

-#if 0

-short Unserialize2SInt(IMkvReader*, long long);

-signed char Unserialize1SInt(IMkvReader*, long long);

-#else

+long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);

 long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);

-#endif

+

+long UnserializeString(

+        IMkvReader*,

+        long long pos,

+        long long size,

+        char*& str);

+

+long ParseElementHeader(

+    IMkvReader* pReader,

+    long long& pos,  //consume id and size fields

+    long long stop,  //if you know size of element's parent

+    long long& id,

+    long long& size);

 

 bool Match(IMkvReader*, long long&, unsigned long, long long&);

-bool Match(IMkvReader*, long long&, unsigned long, char*&);

 bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);

-bool Match(IMkvReader*, long long&, unsigned long, double&);

-bool Match(IMkvReader*, long long&, unsigned long, short&);

 

 void GetVersion(int& major, int& minor, int& build, int& revision);

 

@@ -289,13 +292,15 @@
     Track& operator=(const Track&);

 

 public:

+    enum Type { kVideo = 1, kAudio = 2 };

+

     Segment* const m_pSegment;

     const long long m_element_start;

     const long long m_element_size;

     virtual ~Track();

 

-    long long GetType() const;

-    long long GetNumber() const;

+    long GetType() const;

+    long GetNumber() const;

     unsigned long long GetUid() const;

     const char* GetNameAsUTF8() const;

     const char* GetCodecNameAsUTF8() const;

@@ -311,21 +316,29 @@
         long long size;

     };

 

-    struct Info

+    class Info

     {

-        long long type;

-        long long number;

+    public:

+        Info();

+        ~Info();

+        int Copy(Info&) const;

+        void Clear();

+    private:

+        Info(const Info&);

+        Info& operator=(const Info&);

+    public:

+        long type;

+        long number;

         unsigned long long uid;

         char* nameAsUTF8;

         char* codecId;

+        char* codecNameAsUTF8;

         unsigned char* codecPrivate;

         size_t codecPrivateSize;

-        char* codecNameAsUTF8;

         bool lacing;

         Settings settings;

-

-        Info();

-        void Clear();

+    private:

+        int CopyStr(char* Info::*str, Info&) const;

     };

 

     long GetFirst(const BlockEntry*&) const;

@@ -341,10 +354,10 @@
 protected:

     Track(

         Segment*,

-        const Info&,

         long long element_start,

         long long element_size);

-    const Info m_info;

+

+    Info m_info;

 

     class EOSBlock : public BlockEntry

     {

@@ -368,12 +381,19 @@
     VideoTrack(const VideoTrack&);

     VideoTrack& operator=(const VideoTrack&);

 

-public:

     VideoTrack(

         Segment*,

+        long long element_start,

+        long long element_size);

+

+public:

+    static long Parse(

+        Segment*,

         const Info&,

         long long element_start,

-        long long element_size);

+        long long element_size,

+        VideoTrack*&);

+

     long long GetWidth() const;

     long long GetHeight() const;

     double GetFrameRate() const;

@@ -394,12 +414,18 @@
     AudioTrack(const AudioTrack&);

     AudioTrack& operator=(const AudioTrack&);

 

-public:

     AudioTrack(

         Segment*,

+        long long element_start,

+        long long element_size);

+public:

+    static long Parse(

+        Segment*,

         const Info&,

         long long element_start,

-        long long element_size);

+        long long element_size,

+        AudioTrack*&);

+

     double GetSamplingRate() const;

     long long GetChannels() const;

     long long GetBitDepth() const;

@@ -431,24 +457,27 @@
         long long size,

         long long element_start,

         long long element_size);

-    virtual ~Tracks();

 

-    const Track* GetTrackByNumber(unsigned long tn) const;

+    ~Tracks();

+

+    long Parse();

+

+    unsigned long GetTracksCount() const;

+

+    const Track* GetTrackByNumber(long tn) const;

     const Track* GetTrackByIndex(unsigned long idx) const;

 

 private:

     Track** m_trackEntries;

     Track** m_trackEntriesEnd;

 

-    void ParseTrackEntry(

-        long long,

-        long long,

-        Track*&,

+    long ParseTrackEntry(

+        long long payload_start,

+        long long payload_size,

         long long element_start,

-        long long element_size);

+        long long element_size,

+        Track*&) const;

 

-public:

-    unsigned long GetTracksCount() const;

 };

 

 

@@ -473,6 +502,8 @@
 

     ~SegmentInfo();

 

+    long Parse();

+

     long long GetTimeCodeScale() const;

     long long GetDuration() const;  //scaled

     const char* GetMuxingAppAsUTF8() const;

@@ -509,6 +540,8 @@
 

     ~SeekHead();

 

+    long Parse();

+

     struct Entry

     {

         //the SeekHead entry payload

diff --git a/sample.cpp b/sample.cpp
index 28abb5d..710fb60 100644
--- a/sample.cpp
+++ b/sample.cpp
@@ -11,6 +11,7 @@
 

 #include "mkvreader.hpp"

 #include "mkvparser.hpp"

+#include <memory>

 

 #ifdef _MSC_VER

 // Silences these warnings:

@@ -83,15 +84,18 @@
     printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);

     printf("\t\tPos\t\t\t: %lld\n", pos);

 

-    mkvparser::Segment* pSegment;

+    typedef mkvparser::Segment seg_t;

+    seg_t* pSegment_;

 

-    long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);

+    long long ret = seg_t::CreateInstance(&reader, pos, pSegment_);

     if (ret)

     {

         printf("\n Segment::CreateInstance() failed.");

         return -1;

     }

 

+    const std::auto_ptr<seg_t> pSegment(pSegment_);

+

     ret  = pSegment->Load();

     if (ret < 0)

     {

@@ -157,8 +161,6 @@
     unsigned long i = 0;

     const unsigned long j = pTracks->GetTracksCount();

 

-    enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };

-

     printf("\n\t\t\t   Track Info\n");

 

     while (i != j)

@@ -168,13 +170,13 @@
         if (pTrack == NULL)

             continue;

 

-        const long long trackType = pTrack->GetType();

-        const long long trackNumber = pTrack->GetNumber();

+        const long trackType = pTrack->GetType();

+        const long trackNumber = pTrack->GetNumber();

         const unsigned long long trackUid = pTrack->GetUid();

         const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());

 

-        printf("\t\tTrack Type\t\t: %lld\n", trackType);

-        printf("\t\tTrack Number\t\t: %lld\n", trackNumber);

+        printf("\t\tTrack Type\t\t: %ld\n", trackType);

+        printf("\t\tTrack Number\t\t: %ld\n", trackNumber);

         printf("\t\tTrack Uid\t\t: %lld\n", trackUid);

 

         if (pTrackName == NULL)

@@ -203,7 +205,7 @@
             delete [] pCodecName;

         }

 

-        if (trackType == VIDEO_TRACK)

+        if (trackType == mkvparser::Track::kVideo)

         {

             const VideoTrack* const pVideoTrack =

                 static_cast<const VideoTrack*>(pTrack);

@@ -218,7 +220,7 @@
             printf("\t\tVideo Rate\t\t: %f\n",rate);

         }

 

-        if (trackType == AUDIO_TRACK)

+        if (trackType == mkvparser::Track::kAudio)

         {

             const AudioTrack* const pAudioTrack =

                 static_cast<const AudioTrack*>(pTrack);

@@ -242,7 +244,6 @@
     if (clusterCount == 0)

     {

         printf("\t\tSegment has no clusters.\n");

-        delete pSegment;

         return -1;

     }

 

@@ -264,7 +265,7 @@
         {

             printf("\t\tError parsing first block of cluster\n");

             fflush(stdout);

-            goto done;

+            return -1;

         }

 

         while ((pBlockEntry != NULL) && !pBlockEntry->EOS())

@@ -273,21 +274,27 @@
             const long long trackNum = pBlock->GetTrackNumber();

             const unsigned long tn = static_cast<unsigned long>(trackNum);

             const Track* const pTrack = pTracks->GetTrackByNumber(tn);

-            const long long trackType = pTrack->GetType();

-            const int frameCount = pBlock->GetFrameCount();

-            const long long time_ns = pBlock->GetTime(pCluster);

 

-            printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",

-                   (trackType == VIDEO_TRACK) ? "V" : "A",

-                   pBlock->IsKey() ? "I" : "P",

-                   time_ns);

-

-            for (int i = 0; i < frameCount; ++i)

+            if (pTrack == NULL)

+                printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");

+            else

             {

-                const Block::Frame& theFrame = pBlock->GetFrame(i);

-                const long size = theFrame.len;

-                const long long offset = theFrame.pos;

-                printf("\t\t\t %15ld,%15llx\n", size, offset);

+                const long long trackType = pTrack->GetType();

+                const int frameCount = pBlock->GetFrameCount();

+                const long long time_ns = pBlock->GetTime(pCluster);

+

+                printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",

+                       (trackType == mkvparser::Track::kVideo) ? "V" : "A",

+                       pBlock->IsKey() ? "I" : "P",

+                       time_ns);

+

+                for (int i = 0; i < frameCount; ++i)

+                {

+                    const Block::Frame& theFrame = pBlock->GetFrame(i);

+                    const long size = theFrame.len;

+                    const long long offset = theFrame.pos;

+                    printf("\t\t\t %15ld,%15llx\n", size, offset);

+                }

             }

 

             status = pCluster->GetNext(pBlockEntry, pBlockEntry);

@@ -296,15 +303,13 @@
             {

                 printf("\t\t\tError parsing next block of cluster\n");

                 fflush(stdout);

-                goto done;

+                return -1;

             }

         }

 

         pCluster = pSegment->GetNext(pCluster);

     }

 

-done:

-    delete pSegment;

+    fflush(stdout);

     return 0;

-

 }