Commit message: None
CVE: CVE-2016-2464
CWE: CWE-20
Vulnerability description: libvpx in libwebm in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-06-01 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted mkv file, aka internal bug 23167726.

Project: Android
File: mkvparser.cc

bool Segment::AppendCluster(Cluster* pCluster) {
 if (pCluster == NULL || pCluster->m_index < 0)
 return false;

 const long count = m_clusterCount + m_clusterPreloadCount;

 long& size = m_clusterSize;
 const long idx = pCluster->m_index;

 if (size < count || idx != m_clusterCount)
 return false;

 if (count >= size) {
 const long n = (size <= 0) ? 2048 : 2 * size;

 Cluster** const qq = new (std::nothrow) Cluster*[n];
 if (qq == NULL)
 return false;

 Cluster** q = qq;
 Cluster** p = m_clusters;
 Cluster** const pp = p + count;

 while (p != pp)
 *q++ = *p++;

 delete[] m_clusters;

    m_clusters = qq;
    size = n;
 }

 if (m_clusterPreloadCount > 0) {
 Cluster** const p = m_clusters + m_clusterCount;
 if (*p == NULL || (*p)->m_index >= 0)
 return false;

 Cluster** q = p + m_clusterPreloadCount;
 if (q >= (m_clusters + size))
 return false;

 for (;;) {
 Cluster** const qq = q - 1;
 if ((*qq)->m_index >= 0)
 return false;

 *q = *qq;
      q = qq;

 if (q == p)
 break;
 }
 }

  m_clusters[idx] = pCluster;
 ++m_clusterCount;
 return true;
}

Project: Android
File: mkvparser.cc

void Tags::Tag::Clear() {
 while (m_simple_tags_count > 0) {
 SimpleTag& d = m_simple_tags[--m_simple_tags_count];
    d.Clear();
 }

 delete[] m_simple_tags;
  m_simple_tags = NULL;

  m_simple_tags_size = 0;
}

Project: Android
File: mkvparser.cc

void Tags::SimpleTag::Clear() {
 delete[] m_tag_name;
  m_tag_name = NULL;

 delete[] m_tag_string;
  m_tag_string = NULL;
}

Project: Android

int Track::Info::Copy(Info& dst) const {
 if (&dst == this)
 return 0;

  dst.type = type;
  dst.number = number;
  dst.defaultDuration = defaultDuration;
  dst.codecDelay = codecDelay;
  dst.seekPreRoll = seekPreRoll;
  dst.uid = uid;
  dst.lacing = lacing;
  dst.settings = settings;


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

 if (int status = CopyStr(&Info::language, 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 = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);

 if (dst.codecPrivate == NULL)
 return -1;

    memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
    dst.codecPrivateSize = codecPrivateSize;
 }

 return 0;
}

Project: Android
File: mkvparser.cc

Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
 if (!pSegment || off < 0)
 return NULL;

 const long long element_start = pSegment->m_start + off;

 Cluster* const pCluster =
 new (std::nothrow) Cluster(pSegment, idx, element_start);

 return pCluster;
}

Project: Android

long Cluster::CreateBlock(long long id,
 long long pos, // absolute pos of payload
 long long size, long long discard_padding) {
  assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock

 if (m_entries_count < 0) { // haven't parsed anything yet
    assert(m_entries == NULL);
    assert(m_entries_size == 0);

    m_entries_size = 1024;
    m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
 if (m_entries == NULL)
 return -1;

    m_entries_count = 0;
 } else {
    assert(m_entries);
    assert(m_entries_size > 0);
    assert(m_entries_count <= m_entries_size);

 if (m_entries_count >= m_entries_size) {
 const long entries_size = 2 * m_entries_size;

 BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
 if (entries == NULL)
 return -1;

 BlockEntry** src = m_entries;
 BlockEntry** const src_end = src + m_entries_count;

 BlockEntry** dst = entries;

 while (src != src_end)
 *dst++ = *src++;

 delete[] m_entries;

      m_entries = entries;
      m_entries_size = entries_size;
 }
 }

 if (id == 0x20) // BlockGroup ID
 return CreateBlockGroup(pos, size, discard_padding);
 else // SimpleBlock ID
 return CreateSimpleBlock(pos, size);
}

Project: Android

long Cluster::CreateBlockGroup(long long start_offset, long long size,
 long long discard_padding) {
  assert(m_entries);
  assert(m_entries_size > 0);
  assert(m_entries_count >= 0);
  assert(m_entries_count < m_entries_size);

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long pos = start_offset;
 const long long stop = start_offset + size;


 long long prev = 1; // nonce
 long long next = 0; // nonce
 long long duration = -1; // really, this is unsigned

 long long bpos = -1;
 long long bsize = -1;

 while (pos < stop) {
 long len;
 const long long id = ReadID(pReader, pos, len);
 if (id < 0 || (pos + len) > stop)
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume ID

 const long long size = ReadUInt(pReader, pos, len);
    assert(size >= 0); // TODO
    assert((pos + len) <= stop);

    pos += len; // consume size

 if (id == 0x21) { // Block ID
 if (bpos < 0) { // Block ID
        bpos = pos;
        bsize = size;
 }
 } else if (id == 0x1B) { // Duration ID
 if (size > 8)
 return E_FILE_FORMAT_INVALID;

      duration = UnserializeUInt(pReader, pos, size);

 if (duration < 0)
 return E_FILE_FORMAT_INVALID;
 } else if (id == 0x7B) { // ReferenceBlock
 if (size > 8 || size <= 0)
 return E_FILE_FORMAT_INVALID;
 const long size_ = static_cast<long>(size);

 long long time;

 long status = UnserializeInt(pReader, pos, size_, time);
      assert(status == 0);
 if (status != 0)
 return -1;

 if (time <= 0) // see note above
        prev = time;
 else // weird
        next = time;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }
 if (bpos < 0)
 return E_FILE_FORMAT_INVALID;

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
  assert(bsize >= 0);

 const long idx = m_entries_count;

 BlockEntry** const ppEntry = m_entries + idx;
 BlockEntry*& pEntry = *ppEntry;

  pEntry = new (std::nothrow)
 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);

 if (pEntry == NULL)
 return -1; // generic error

 BlockGroup* const p = static_cast<BlockGroup*>(pEntry);

 const long status = p->Parse();

 if (status == 0) { // success
 ++m_entries_count;
 return 0;
 }

 delete pEntry;
  pEntry = 0;

 return status;
}

Project: Android

long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
 Segment*& pSegment) {
 if (pReader == NULL || pos < 0)
 return E_PARSE_FAILED;

  pSegment = NULL;

 long long total, available;

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

 if (status < 0) // error
 return status;

 if (available < 0)
 return -1;

 if ((total >= 0) && (available > total))
 return -1;


 for (;;) {
 if ((total >= 0) && (pos >= total))
 return E_FILE_FORMAT_INVALID;

 long len;
 long long result = GetUIntLength(pReader, pos, len);

 if (result) // error, or too few available bytes
 return result;

 if ((total >= 0) && ((pos + len) > total))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > available)
 return pos + len;

 const long long idpos = pos;
 const long long id = ReadID(pReader, pos, len);

 if (id < 0)
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume ID


    result = GetUIntLength(pReader, pos, len);

 if (result) // error, or too few available bytes
 return result;

 if ((total >= 0) && ((pos + len) > total))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > available)
 return pos + len;

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

 if (size < 0) // error
 return size;

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


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

 if (id == 0x08538067) { // Segment ID
 if (size == unknown_size)
        size = -1;

 else if (total < 0)
        size = -1;

 else if ((pos + size) > total)
        size = -1;

      pSegment = new (std::nothrow) Segment(pReader, idpos,
                                            pos, size);

 if (pSegment == 0)
 return -1; // generic error

 return 0; // success
 }

 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && ((pos + size) > total))
 return E_FILE_FORMAT_INVALID;

 if ((pos + size) > available)
 return pos + size;

    pos += size; // consume payload
 }
}

Project: Android

long Segment::DoLoadCluster(long long& pos, long& len) {
 if (m_pos < 0)
 return DoLoadClusterUnknownSize(pos, len);

 long long total, avail;

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

 if (status < 0) // error
 return status;

 if (total >= 0 && avail > total)
 return E_FILE_FORMAT_INVALID;

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

 long long cluster_off = -1; // offset relative to start of segment
 long long cluster_size = -1; // size of cluster payload

 for (;;) {
 if ((total >= 0) && (m_pos >= total))
 return 1; // no more clusters

 if ((segment_stop >= 0) && (m_pos >= segment_stop))
 return 1; // no more clusters

    pos = m_pos;


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

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

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long idpos = pos;
 const long long id = ReadID(m_pReader, idpos, len);

 if (id < 0)
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume ID


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 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


 if (size == 0) { // weird
      m_pos = pos;
 continue;
 }

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

 if ((segment_stop >= 0) && (size != unknown_size) &&
 ((pos + size) > segment_stop)) {
 return E_FILE_FORMAT_INVALID;
 }

 if (id == 0x0C53BB6B) { // Cues ID
 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID; // TODO: liberalize

 if (m_pCues == NULL) {
 const long long element_size = (pos - idpos) + size;

        m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
 if (m_pCues == NULL)
 return -1;
 }

      m_pos = pos + size; // consume payload
 continue;
 }

 if (id != 0x0F43B675) { // Cluster ID
 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID; // TODO: liberalize

      m_pos = pos + size; // consume payload
 continue;
 }


    cluster_off = idpos - m_start; // relative pos

 if (size != unknown_size)
      cluster_size = size;

 break;
 }

 if (cluster_off < 0) {
 return E_FILE_FORMAT_INVALID;
 }

 long long pos_;
 long len_;

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

 if (status < 0) { // error, or underflow
    pos = pos_;
    len = len_;

 return status;
 }



 const long idx = m_clusterCount;

 if (m_clusterPreloadCount > 0) {
 if (idx >= m_clusterSize)
 return E_FILE_FORMAT_INVALID;

 Cluster* const pCluster = m_clusters[idx];
 if (pCluster == NULL || pCluster->m_index >= 0)
 return E_FILE_FORMAT_INVALID;

 const long long off = pCluster->GetPosition();
 if (off < 0)
 return E_FILE_FORMAT_INVALID;

 if (off == cluster_off) { // preloaded already
 if (status == 0) // no entries found
 return E_FILE_FORMAT_INVALID;

 if (cluster_size >= 0)
        pos += cluster_size;
 else {
 const long long element_size = pCluster->GetElementSize();

 if (element_size <= 0)
 return E_FILE_FORMAT_INVALID; // TODO: handle this case

        pos = pCluster->m_element_start + element_size;
 }

      pCluster->m_index = idx; // move from preloaded to loaded
 ++m_clusterCount;
 --m_clusterPreloadCount;

      m_pos = pos; // consume payload
 if (segment_stop >= 0 && m_pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 return 0; // success
 }
 }

 if (status == 0) { // no entries found
 if (cluster_size >= 0)
      pos += cluster_size;

 if ((total >= 0) && (pos >= total)) {
      m_pos = total;
 return 1; // no more clusters
 }

 if ((segment_stop >= 0) && (pos >= segment_stop)) {
      m_pos = segment_stop;
 return 1; // no more clusters
 }

    m_pos = pos;
 return 2; // try again
 }


 Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
 if (pCluster == NULL)
 return -1;

 if (!AppendCluster(pCluster)) {
 delete pCluster;
 return -1;
 }

 if (cluster_size >= 0) {
    pos += cluster_size;

    m_pos = pos;

 if (segment_stop > 0 && m_pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 return 0;
 }

  m_pUnknownSize = pCluster;
  m_pos = -pos;

 return 0; // partial success, since we have a new cluster

}

Project: Android
File: mkvparser.cc

long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
 if (m_pos >= 0 || m_pUnknownSize == NULL)
 return E_PARSE_FAILED;

 const long status = m_pUnknownSize->Parse(pos, len);

 if (status < 0) // error or underflow
 return status;

 if (status == 0) // parsed a block
 return 2; // continue parsing

 const long long start = m_pUnknownSize->m_element_start;
 const long long size = m_pUnknownSize->GetElementSize();

 if (size < 0)
 return E_FILE_FORMAT_INVALID;

  pos = start + size;
  m_pos = pos;

  m_pUnknownSize = 0;

 return 2; // continue parsing
}

Project: Android

long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
 long long total, avail;

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

 if (status < 0) // error
 return status;

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

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


 long long off_next = 0;
 long long cluster_size = -1;

 for (;;) {
 if ((total >= 0) && (pos >= total))
 return 1; // EOF

 if ((segment_stop >= 0) && (pos >= segment_stop))
 return 1; // EOF

 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

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

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long idpos = pos; // absolute
 const long long idoff = pos - m_start; // relative

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

 if (id < 0) // error
 return static_cast<long>(id);

 if (id == 0) // weird
 return -1; // generic error

    pos += len; // consume ID


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 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


 if (size == 0) // weird
 continue;

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

 if ((segment_stop >= 0) && (size != unknown_size) &&
 ((pos + size) > segment_stop)) {
 return E_FILE_FORMAT_INVALID;
 }

 if (id == 0x0C53BB6B) { // Cues ID
 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID;

 const long long element_stop = pos + size;

 if ((segment_stop >= 0) && (element_stop > segment_stop))
 return E_FILE_FORMAT_INVALID;

 const long long element_start = idpos;
 const long long element_size = element_stop - element_start;

 if (m_pCues == NULL) {
        m_pCues = new (std::nothrow)
 Cues(this, pos, size, element_start, element_size);
 if (m_pCues == NULL)
 return false;
 }

      pos += size; // consume payload
 if (segment_stop >= 0 && pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 continue;
 }

 if (id != 0x0F43B675) { // not a Cluster ID
 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID;

      pos += size; // consume payload
 if (segment_stop >= 0 && pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 continue;
 }

    off_next = idoff;

 if (size != unknown_size)
      cluster_size = size;

 break;
 }

  assert(off_next > 0); // have cluster


 Cluster** const ii = m_clusters + m_clusterCount;
 Cluster** i = ii;

 Cluster** const jj = ii + m_clusterPreloadCount;
 Cluster** j = jj;

 while (i < j) {

 Cluster** const k = i + (j - i) / 2;
    assert(k < jj);

 const Cluster* const pNext = *k;
    assert(pNext);
    assert(pNext->m_index < 0);

    pos = pNext->GetPosition();
    assert(pos >= 0);

 if (pos < off_next)
      i = k + 1;
 else if (pos > off_next)
      j = k;
 else {
      pResult = pNext;
 return 0; // success
 }
 }

  assert(i == j);

 long long pos_;
 long len_;

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

 if (status < 0) { // error or underflow
    pos = pos_;
    len = len_;

 return status;
 }

 if (status > 0) { // means "found at least one block entry"
 Cluster* const pNext = Cluster::Create(this,
 -1, // preloaded
                                           off_next);
 if (pNext == NULL)
 return -1;

 const ptrdiff_t idx_next = i - m_clusters; // insertion position

 if (!PreloadCluster(pNext, idx_next)) {
 delete pNext;
 return -1;
 }
    assert(m_clusters);
    assert(idx_next < m_clusterSize);
    assert(m_clusters[idx_next] == pNext);

    pResult = pNext;
 return 0; // success
 }


 if (cluster_size < 0) { // unknown size
 const long long payload_pos = pos; // absolute pos of cluster payload

 for (;;) { // determine cluster size
 if ((total >= 0) && (pos >= total))
 break;

 if ((segment_stop >= 0) && (pos >= segment_stop))
 break; // no more clusters


 if ((pos + 1) > avail) {
        len = 1;
 return E_BUFFER_NOT_FULL;
 }

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

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error (or underflow)
 return static_cast<long>(id);


 if (id == 0x0F43B675) // Cluster ID
 break;

 if (id == 0x0C53BB6B) // Cues ID
 break;

      pos += len; // consume ID (of sub-element)


 if ((pos + 1) > avail) {
        len = 1;
 return E_BUFFER_NOT_FULL;
 }

      result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 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 size field of element


 if (size == 0) // weird
 continue;

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

 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID; // not allowed for sub-elements

 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird
 return E_FILE_FORMAT_INVALID;

      pos += size; // consume payload of sub-element
 if (segment_stop >= 0 && pos > segment_stop)
 return E_FILE_FORMAT_INVALID;
 } // determine cluster size

    cluster_size = pos - payload_pos;
    assert(cluster_size >= 0); // TODO: handle cluster_size = 0

    pos = payload_pos; // reset and re-parse original cluster
 }

  pos += cluster_size; // consume payload
 if (segment_stop >= 0 && pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 return 2; // try to find a cluster that follows next
}

Project: Android
File: mkvparser.cc

bool Tags::Tag::ExpandSimpleTagsArray() {
 if (m_simple_tags_size > m_simple_tags_count)
 return true; // nothing else to do

 const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;

 SimpleTag* const displays = new (std::nothrow) SimpleTag[size];

 if (displays == NULL)
 return false;

 for (int idx = 0; idx < m_simple_tags_count; ++idx) {
    m_simple_tags[idx].ShallowCopy(displays[idx]);
 }

 delete[] m_simple_tags;
  m_simple_tags = displays;

  m_simple_tags_size = size;
 return true;
}

Project: Android

bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
 const CuePoint::TrackPosition*& pTP) const {
 if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
 return false;

 CuePoint** const ii = m_cue_points;
 CuePoint** i = ii;

 CuePoint** const jj = ii + m_count;
 CuePoint** j = jj;

  pCP = *i;
 if (pCP == NULL)
 return false;

 if (time_ns <= pCP->GetTime(m_pSegment)) {
    pTP = pCP->Find(pTrack);
 return (pTP != NULL);
 }

 while (i < j) {

 CuePoint** const k = i + (j - i) / 2;
 if (k >= jj)
 return false;

 CuePoint* const pCP = *k;
 if (pCP == NULL)
 return false;

 const long long t = pCP->GetTime(m_pSegment);

 if (t <= time_ns)
      i = k + 1;
 else
      j = k;

 if (i > j)
 return false;
 }

 if (i != j || i > jj || i <= ii)
 return false;

  pCP = *--i;

 if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
 return false;


  pTP = pCP->Find(pTrack);
 return (pTP != NULL);
}

Project: Android

const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
 if (requested_pos < 0)
 return 0;

 Cluster** const ii = m_clusters;
 Cluster** i = ii;

 const long count = m_clusterCount + m_clusterPreloadCount;

 Cluster** const jj = ii + count;
 Cluster** j = jj;

 while (i < j) {

 Cluster** const k = i + (j - i) / 2;
    assert(k < jj);

 Cluster* const pCluster = *k;
    assert(pCluster);


 const long long pos = pCluster->GetPosition();
    assert(pos >= 0);

 if (pos < requested_pos)
      i = k + 1;
 else if (pos > requested_pos)
      j = k;
 else
 return pCluster;
 }

  assert(i == j);

 Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
 if (pCluster == NULL)
 return NULL;

 const ptrdiff_t idx = i - m_clusters;

 if (!PreloadCluster(pCluster, idx)) {
 delete pCluster;
 return NULL;
 }
  assert(m_clusters);
  assert(m_clusterPreloadCount > 0);
  assert(m_clusters[idx] == pCluster);

 return pCluster;
}

Project: Android
File: mkvparser.cc

const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
 const CuePoint::TrackPosition* pTP) const {
 if (pCP == NULL || pTP == NULL)
 return NULL;

 return m_pSegment->GetBlock(*pCP, *pTP);
}

Project: Android

const BlockEntry* Segment::GetBlock(const CuePoint& cp,
 const CuePoint::TrackPosition& tp) {
 Cluster** const ii = m_clusters;
 Cluster** i = ii;

 const long count = m_clusterCount + m_clusterPreloadCount;

 Cluster** const jj = ii + count;
 Cluster** j = jj;

 while (i < j) {

 Cluster** const k = i + (j - i) / 2;
    assert(k < jj);

 Cluster* const pCluster = *k;
    assert(pCluster);


 const long long pos = pCluster->GetPosition();
    assert(pos >= 0);

 if (pos < tp.m_pos)
      i = k + 1;
 else if (pos > tp.m_pos)
      j = k;
 else
 return pCluster->GetEntry(cp, tp);
 }

  assert(i == j);

 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
 if (pCluster == NULL)
 return NULL;

 const ptrdiff_t idx = i - m_clusters;

 if (!PreloadCluster(pCluster, idx)) {
 delete pCluster;
 return NULL;
 }
  assert(m_clusters);
  assert(m_clusterPreloadCount > 0);
  assert(m_clusters[idx] == pCluster);

 return pCluster->GetEntry(cp, tp);
}

Project: Android
File: mkvparser.cc

long long VideoTrack::GetDisplayHeight() const {
 return m_display_height > 0 ? m_display_height : GetHeight();
}

Project: Android
File: mkvparser.cc

long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }

Project: Android
File: mkvparser.cc

long long VideoTrack::GetDisplayWidth() const {
 return m_display_width > 0 ? m_display_width : GetWidth();
}

Project: Android
File: mkvparser.cc

const BlockEntry* Cluster::GetEntry(const Track* pTrack,
 long long time_ns) const {
  assert(pTrack);

 if (m_pSegment == NULL) // this is the special EOS cluster
 return pTrack->GetEOS();

 const BlockEntry* pResult = pTrack->GetEOS();

 long index = 0;

 for (;;) {
 if (index >= m_entries_count) {
 long long pos;
 long len;

 const long status = Parse(pos, len);
      assert(status >= 0);

 if (status > 0) // completely parsed, and no more entries
 return pResult;

 if (status < 0) // should never happen
 return 0;

      assert(m_entries);
      assert(index < m_entries_count);
 }

 const BlockEntry* const pEntry = m_entries[index];
    assert(pEntry);
    assert(!pEntry->EOS());

 const Block* const pBlock = pEntry->GetBlock();
    assert(pBlock);

 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
 ++index;
 continue;
 }

 if (pTrack->VetEntry(pEntry)) {
 if (time_ns < 0) // just want first candidate block
 return pEntry;

 const long long ns = pBlock->GetTime(this);

 if (ns > time_ns)
 return pResult;

      pResult = pEntry; // have a candidate
 } else if (time_ns >= 0) {
 const long long ns = pBlock->GetTime(this);

 if (ns > time_ns)
 return pResult;
 }

 ++index;
 }
}

Project: Android
File: mkvparser.cc

const CuePoint* Cues::GetFirst() const {
 if (m_cue_points == NULL || m_count == 0)
 return NULL;

 CuePoint* const* const pp = m_cue_points;
 if (pp == NULL)
 return NULL;

 CuePoint* const pCP = pp[0];
 if (pCP == NULL || pCP->GetTimeCode() < 0)
 return NULL;

 return pCP;
}

Project: Android

long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
 const Cluster* pCluster = m_pSegment->GetFirst();

 for (int i = 0;;) {
 if (pCluster == NULL) {
      pBlockEntry = GetEOS();
 return 1;
 }

 if (pCluster->EOS()) {
 if (m_pSegment->DoneParsing()) {
        pBlockEntry = GetEOS();
 return 1;
 }

      pBlockEntry = 0;
 return E_BUFFER_NOT_FULL;
 }

 long status = pCluster->GetFirst(pBlockEntry);

 if (status < 0) // error
 return status;

 if (pBlockEntry == 0) { // empty cluster
      pCluster = m_pSegment->GetNext(pCluster);
 continue;
 }

 for (;;) {
 const Block* const pBlock = pBlockEntry->GetBlock();
      assert(pBlock);

 const long long tn = pBlock->GetTrackNumber();

 if ((tn == m_info.number) && VetEntry(pBlockEntry))
 return 0;

 const BlockEntry* pNextEntry;

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

 if (status < 0) // error
 return status;

 if (pNextEntry == 0)
 break;

      pBlockEntry = pNextEntry;
 }

 ++i;

 if (i >= 100)
 break;

    pCluster = m_pSegment->GetNext(pCluster);
 }


  pBlockEntry = GetEOS(); // so we can return a non-NULL value
 return 1;
}

Project: Android
File: mkvparser.cc

const CuePoint* Cues::GetLast() const {
 if (m_cue_points == NULL || m_count <= 0)
 return NULL;

 const long index = m_count - 1;

 CuePoint* const* const pp = m_cue_points;
 if (pp == NULL)
 return NULL;

 CuePoint* const pCP = pp[index];
 if (pCP == NULL || pCP->GetTimeCode() < 0)
 return NULL;

 return pCP;
}

Project: Android
File: mkvparser.cc

const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
 if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
      m_cue_points == NULL || m_count < 1) {
 return NULL;
 }

 long index = pCurr->m_index;
 if (index >= m_count)
 return NULL;

 CuePoint* const* const pp = m_cue_points;
 if (pp == NULL || pp[index] != pCurr)
 return NULL;

 ++index;

 if (index >= m_count)
 return NULL;

 CuePoint* const pNext = pp[index];

 if (pNext == NULL || pNext->GetTimeCode() < 0)
 return NULL;

 return pNext;
}

Project: Android

const Cluster* Segment::GetNext(const Cluster* pCurr) {
  assert(pCurr);
  assert(pCurr != &m_eos);
  assert(m_clusters);

 long idx = pCurr->m_index;

 if (idx >= 0) {
    assert(m_clusterCount > 0);
    assert(idx < m_clusterCount);
    assert(pCurr == m_clusters[idx]);

 ++idx;

 if (idx >= m_clusterCount)
 return &m_eos; // caller will LoadCluster as desired

 Cluster* const pNext = m_clusters[idx];
    assert(pNext);
    assert(pNext->m_index >= 0);
    assert(pNext->m_index == idx);

 return pNext;
 }

  assert(m_clusterPreloadCount > 0);

 long long pos = pCurr->m_element_start;

  assert(m_size >= 0); // TODO
 const long long stop = m_start + m_size; // end of segment

 {
 long len;

 long long result = GetUIntLength(m_pReader, pos, len);
    assert(result == 0);
    assert((pos + len) <= stop); // TODO
 if (result != 0)
 return NULL;

 const long long id = ReadID(m_pReader, pos, len);
 if (id != 0x0F43B675) // Cluster ID
 return NULL;

    pos += len; // consume ID

    result = GetUIntLength(m_pReader, pos, len);
    assert(result == 0); // TODO
    assert((pos + len) <= stop); // TODO

 const long long size = ReadUInt(m_pReader, pos, len);
    assert(size > 0); // TODO

    pos += len; // consume length of size of element
    assert((pos + size) <= stop); // TODO


    pos += size; // consume payload
 }

 long long off_next = 0;

 while (pos < stop) {
 long len;

 long long result = GetUIntLength(m_pReader, pos, len);
    assert(result == 0);
    assert((pos + len) <= stop); // TODO
 if (result != 0)
 return NULL;

 const long long idpos = pos; // pos of next (potential) cluster

 const long long id = ReadID(m_pReader, idpos, len);
 if (id < 0)
 return NULL;

    pos += len; // consume ID

    result = GetUIntLength(m_pReader, pos, len);
    assert(result == 0); // TODO
    assert((pos + len) <= stop); // TODO

 const long long size = ReadUInt(m_pReader, pos, len);
    assert(size >= 0); // TODO

    pos += len; // consume length of size of element
    assert((pos + size) <= stop); // TODO


 if (size == 0) // weird
 continue;

 if (id == 0x0F43B675) { // Cluster ID
 const long long off_next_ = idpos - m_start;

 long long pos_;
 long len_;

 const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);

      assert(status >= 0);

 if (status > 0) {
        off_next = off_next_;
 break;
 }
 }

    pos += size; // consume payload
 }

 if (off_next <= 0)
 return 0;

 Cluster** const ii = m_clusters + m_clusterCount;
 Cluster** i = ii;

 Cluster** const jj = ii + m_clusterPreloadCount;
 Cluster** j = jj;

 while (i < j) {

 Cluster** const k = i + (j - i) / 2;
    assert(k < jj);

 Cluster* const pNext = *k;
    assert(pNext);
    assert(pNext->m_index < 0);


    pos = pNext->GetPosition();

 if (pos < off_next)
      i = k + 1;
 else if (pos > off_next)
      j = k;
 else
 return pNext;
 }

  assert(i == j);

 Cluster* const pNext = Cluster::Create(this, -1, off_next);
 if (pNext == NULL)
 return NULL;

 const ptrdiff_t idx_next = i - m_clusters; // insertion position

 if (!PreloadCluster(pNext, idx_next)) {
 delete pNext;
 return NULL;
 }
  assert(m_clusters);
  assert(idx_next < m_clusterSize);
  assert(m_clusters[idx_next] == pNext);

 return pNext;
}

Project: Android

long Track::GetNext(const BlockEntry* pCurrEntry,
 const BlockEntry*& pNextEntry) const {
  assert(pCurrEntry);
  assert(!pCurrEntry->EOS()); //?

 const Block* const pCurrBlock = pCurrEntry->GetBlock();
  assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
 if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
 return -1;

 const Cluster* pCluster = pCurrEntry->GetCluster();
  assert(pCluster);
  assert(!pCluster->EOS());

 long status = pCluster->GetNext(pCurrEntry, pNextEntry);

 if (status < 0) // error
 return status;

 for (int i = 0;;) {
 while (pNextEntry) {
 const Block* const pNextBlock = pNextEntry->GetBlock();
      assert(pNextBlock);

 if (pNextBlock->GetTrackNumber() == m_info.number)
 return 0;

      pCurrEntry = pNextEntry;

      status = pCluster->GetNext(pCurrEntry, pNextEntry);

 if (status < 0) // error
 return status;
 }

    pCluster = m_pSegment->GetNext(pCluster);

 if (pCluster == NULL) {
      pNextEntry = GetEOS();
 return 1;
 }

 if (pCluster->EOS()) {
 if (m_pSegment->DoneParsing()) {
        pNextEntry = GetEOS();
 return 1;
 }


      pNextEntry = NULL;
 return E_BUFFER_NOT_FULL;
 }

    status = pCluster->GetFirst(pNextEntry);

 if (status < 0) // error
 return status;

 if (pNextEntry == NULL) // empty cluster
 continue;

 ++i;

 if (i >= 100)
 break;
 }


  pNextEntry = GetEOS(); // so we can return a non-NULL value
 return 1;
}

Project: Android
File: mkvparser.cc

const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
 if (index < 0)
 return NULL;

 if (index >= m_simple_tags_count)
 return NULL;

 return m_simple_tags + index;
}

Project: Android
File: mkvparser.cc

int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }

Project: Android
File: mkvparser.cc

long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }

Project: Android
File: mkvparser.cc

const Tags::Tag* Tags::GetTag(int idx) const {
 if (idx < 0)
 return NULL;

 if (idx >= m_tags_count)
 return NULL;

 return m_tags + idx;
}

Project: Android
File: mkvparser.cc

int Tags::GetTagCount() const { return m_tags_count; }

Project: Android
File: mkvparser.cc

const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }

Project: Android
File: mkvparser.cc

const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }

Project: Android
File: mkvparser.cc

const Tags* Segment::GetTags() const { return m_pTags; }

Project: Android
File: mkvparser.cc

long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
 if (!pReader || pos < 0)
 return E_FILE_FORMAT_INVALID;

 long long total, available;

 int status = pReader->Length(&total, &available);
 if (status < 0 || (total >= 0 && available > total))
 return E_FILE_FORMAT_INVALID;

  len = 1;

 if (pos >= available)
 return pos; // too few bytes available

 unsigned char b;

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

 if (status != 0)
 return status;

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

 unsigned char m = 0x80;

 while (!(b & m)) {
    m >>= 1;
 ++len;
 }

 return 0; // success
}

Project: Android
File: mkvparser.cc

void GetVersion(int& major, int& minor, int& build, int& revision) {
  major = 1;
  minor = 0;
  build = 0;
  revision = 30;
}

Project: Android

long Cluster::HasBlockEntries(
 const Segment* pSegment,
 long long off, // relative to start of segment payload
 long long& pos, long& len) {
  assert(pSegment);
  assert(off >= 0); // relative to segment

 IMkvReader* const pReader = pSegment->m_pReader;

 long long total, avail;

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

 if (status < 0) // error
 return status;

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

  pos = pSegment->m_start + off; // absolute

 if ((total >= 0) && (pos >= total))
 return 0; // we don't even have a complete cluster

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

 long long cluster_stop = -1; // interpreted later to mean "unknown size"

 {
 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // need more data
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && ((pos + len) > total))
 return 0;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error
 return static_cast<long>(id);

 if (id != 0x0F43B675) // weird: not cluster ID
 return -1; // generic error

    pos += len; // consume Cluster ID field


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && ((pos + len) > total))
 return 0;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (size < 0) // error
 return static_cast<long>(size);

 if (size == 0)
 return 0; // cluster does not have entries

    pos += len; // consume size field


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

 if (size != unknown_size) {
      cluster_stop = pos + size;
      assert(cluster_stop >= 0);

 if ((segment_stop >= 0) && (cluster_stop > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && (cluster_stop > total))
 return 0; // cluster does not have any entries
 }
 }

 for (;;) {
 if ((cluster_stop >= 0) && (pos >= cluster_stop))
 return 0; // no entries detected

 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // need more data
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error
 return static_cast<long>(id);


 if (id == 0x0F43B675) // Cluster ID
 return 0; // no entries found

 if (id == 0x0C53BB6B) // Cues ID
 return 0; // no entries found

    pos += len; // consume id field

 if ((cluster_stop >= 0) && (pos >= cluster_stop))
 return E_FILE_FORMAT_INVALID;


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // underflow
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (size < 0) // error
 return static_cast<long>(size);

    pos += len; // consume size field


 if ((cluster_stop >= 0) && (pos > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if (size == 0) // weird
 continue;

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

 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID; // not supported inside cluster

 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if (id == 0x20) // BlockGroup ID
 return 1; // have at least one entry

 if (id == 0x23) // SimpleBlock ID
 return 1; // have at least one entry

    pos += size; // consume payload
 if (cluster_stop >= 0 && pos > cluster_stop)
 return E_FILE_FORMAT_INVALID;
 }
}

Project: Android

bool Cues::Init() const {
 if (m_cue_points)
 return true;

 if (m_count != 0 || m_preload_count != 0)
 return false;

 IMkvReader* const pReader = m_pSegment->m_pReader;

 const long long stop = m_start + m_size;
 long long pos = m_start;

 long cue_points_size = 0;

 while (pos < stop) {
 const long long idpos = pos;

 long len;

 const long long id = ReadID(pReader, pos, len);
 if (id < 0 || (pos + len) > stop) {
 return false;
 }

    pos += len; // consume ID

 const long long size = ReadUInt(pReader, pos, len);
 if (size < 0 || (pos + len > stop)) {
 return false;
 }

    pos += len; // consume Size field
 if (pos + size > stop) {
 return false;
 }

 if (id == 0x3B) { // CuePoint ID
 if (!PreloadCuePoint(cue_points_size, idpos))
 return false;
 }

    pos += size; // skip payload
 }
 return true;
}

Project: Android
File: mkvparser.cc

void Tags::Tag::Init() {
  m_simple_tags = NULL;
  m_simple_tags_size = 0;
  m_simple_tags_count = 0;
}

Project: Android
File: mkvparser.cc

void Tags::SimpleTag::Init() {
  m_tag_name = NULL;
  m_tag_string = NULL;
}

Project: Android

long Segment::Load() {
  assert(m_clusters == NULL);
  assert(m_clusterSize == 0);
  assert(m_clusterCount == 0);


 const long long header_status = ParseHeaders();

 if (header_status < 0) // error
 return static_cast<long>(header_status);

 if (header_status > 0) // underflow
 return E_BUFFER_NOT_FULL;

 if (m_pInfo == NULL || m_pTracks == NULL)
 return E_FILE_FORMAT_INVALID;

 for (;;) {
 const int status = LoadCluster();

 if (status < 0) // error
 return status;

 if (status >= 1) // no more clusters
 return 0;
 }
}

Project: Android

bool CuePoint::Load(IMkvReader* pReader) {

 if (m_timecode >= 0) // already loaded
 return true;

  assert(m_track_positions == NULL);
  assert(m_track_positions_count == 0);

 long long pos_ = -m_timecode;
 const long long element_start = pos_;

 long long stop;

 {
 long len;

 const long long id = ReadID(pReader, pos_, len);
 if (id != 0x3B)
 return false;

    pos_ += len; // consume ID

 const long long size = ReadUInt(pReader, pos_, len);
    assert(size >= 0);

    pos_ += len; // consume Size field

    stop = pos_ + size;
 }

 const long long element_size = stop - element_start;

 long long pos = pos_;


 while (pos < stop) {
 long len;

 const long long id = ReadID(pReader, pos, len);
 if ((id < 0) || (pos + len > stop)) {
 return false;
 }

    pos += len; // consume ID

 const long long size = ReadUInt(pReader, pos, len);
 if ((size < 0) || (pos + len > stop)) {
 return false;
 }

    pos += len; // consume Size field
 if ((pos + size) > stop) {
 return false;
 }

 if (id == 0x33) // CueTime ID
      m_timecode = UnserializeUInt(pReader, pos, size);

 else if (id == 0x37) // CueTrackPosition(s) ID
 ++m_track_positions_count;

    pos += size; // consume payload
 }

 if (m_timecode < 0 || m_track_positions_count <= 0) {
 return false;
 }


  m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
 if (m_track_positions == NULL)
 return false;


 TrackPosition* p = m_track_positions;
  pos = pos_;

 while (pos < stop) {
 long len;

 const long long id = ReadID(pReader, pos, len);
 if (id < 0 || (pos + len) > stop)
 return false;

    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 (id == 0x37) { // CueTrackPosition(s) ID
 TrackPosition& tp = *p++;
 if (!tp.Parse(pReader, pos, size)) {
 return false;
 }
 }

    pos += size; // consume payload
 if (pos > stop)
 return false;
 }

  assert(size_t(p - m_track_positions) == m_track_positions_count);

  m_element_start = element_start;
  m_element_size = element_size;

 return true;
}

Project: Android

long Cluster::Load(long long& pos, long& len) const {
  assert(m_pSegment);
  assert(m_pos >= m_element_start);

 if (m_timecode >= 0) // at least partially loaded
 return 0;

  assert(m_pos == m_element_start);
  assert(m_element_size < 0);

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long total, avail;

 const int status = pReader->Length(&total, &avail);

 if (status < 0) // error
 return status;

  assert((total < 0) || (avail <= total));
  assert((total < 0) || (m_pos <= total)); // TODO: verify this

  pos = m_pos;

 long long cluster_size = -1;

 {
 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error or underflow
 return static_cast<long>(result);

 if (result > 0) // underflow (weird)
 return E_BUFFER_NOT_FULL;


 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long id_ = ReadUInt(pReader, pos, len);

 if (id_ < 0) // error
 return static_cast<long>(id_);

 if (id_ != 0x0F43B675) // Cluster ID
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume id


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;


 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (size < 0) // error
 return static_cast<long>(cluster_size);

 if (size == 0)
 return E_FILE_FORMAT_INVALID; // TODO: verify this

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

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

 if (size != unknown_size)
      cluster_size = size;
 }

 long long timecode = -1;
 long long new_pos = -1;
 bool bBlock = false;

 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;

 for (;;) {
 if ((cluster_stop >= 0) && (pos >= cluster_stop))
 break;


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error
 return static_cast<long>(id);

 if (id == 0)
 return E_FILE_FORMAT_INVALID;


 if (id == 0x0F43B675) // Cluster ID
 break;

 if (id == 0x0C53BB6B) // Cues ID
 break;

    pos += len; // consume ID field


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long size = ReadUInt(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 size field

 if ((cluster_stop >= 0) && (pos > cluster_stop))
 return E_FILE_FORMAT_INVALID;


 if (size == 0) // weird
 continue;

 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if (id == 0x67) { // TimeCode ID
      len = static_cast<long>(size);

 if ((pos + size) > avail)
 return E_BUFFER_NOT_FULL;

      timecode = UnserializeUInt(pReader, pos, size);

 if (timecode < 0) // error (or underflow)
 return static_cast<long>(timecode);

      new_pos = pos + size;

 if (bBlock)
 break;
 } else if (id == 0x20) { // BlockGroup ID
      bBlock = true;
 break;
 } else if (id == 0x23) { // SimpleBlock ID
      bBlock = true;
 break;
 }

    pos += size; // consume payload
 if (cluster_stop >= 0 && pos > cluster_stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (cluster_stop >= 0 && pos > cluster_stop)
 return E_FILE_FORMAT_INVALID;

 if (timecode < 0) // no timecode found
 return E_FILE_FORMAT_INVALID;

 if (!bBlock)
 return E_FILE_FORMAT_INVALID;

  m_pos = new_pos; // designates position just beyond timecode payload
  m_timecode = timecode; // m_timecode >= 0 means we're partially loaded

 if (cluster_size >= 0)
    m_element_size = cluster_stop - m_element_start;

 return 0;
}

Project: Android

bool Cues::LoadCuePoint() const {
 const long long stop = m_start + m_size;

 if (m_pos >= stop)
 return false; // nothing else to do

 if (!Init()) {
    m_pos = stop;
 return false;
 }

 IMkvReader* const pReader = m_pSegment->m_pReader;

 while (m_pos < stop) {
 const long long idpos = m_pos;

 long len;

 const long long id = ReadID(pReader, m_pos, len);
 if (id < 0 || (m_pos + len) > stop)
 return false;

    m_pos += len; // consume ID

 const long long size = ReadUInt(pReader, m_pos, len);
 if (size < 0 || (m_pos + len) > stop)
 return false;

    m_pos += len; // consume Size field
 if ((m_pos + size) > stop)
 return false;

 if (id != 0x3B) { // CuePoint ID
      m_pos += size; // consume payload
 if (m_pos > stop)
 return false;

 continue;
 }

 if (m_preload_count < 1)
 return false;

 CuePoint* const pCP = m_cue_points[m_count];
 if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
 return false;

 if (!pCP->Load(pReader)) {
      m_pos = stop;
 return false;
 }
 ++m_count;
 --m_preload_count;

    m_pos += size; // consume payload
 if (m_pos > stop)
 return false;

 return true; // yes, we loaded a cue point
 }

 return false; // no, we did not load a cue point
}

Project: Android
File: mkvparser.cc

bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
 long long& val) {
 if (!pReader || pos < 0)
 return false;

 long long total = 0;
 long long available = 0;

 const long status = pReader->Length(&total, &available);
 if (status < 0 || (total >= 0 && available > total))
 return false;

 long len = 0;

 const long long id = ReadID(pReader, pos, len);
 if (id < 0 || (available - pos) > len)
 return false;

 if (static_cast<unsigned long>(id) != expected_id)
 return false;

  pos += len; // consume id

 const long long size = ReadUInt(pReader, pos, len);
 if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
 return false;

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

  val = UnserializeUInt(pReader, pos, size);
 if (val < 0)
 return false;

  pos += size; // consume size of payload

 return true;
}

Project: Android

bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
 unsigned char*& buf, size_t& buflen) {
 if (!pReader || pos < 0)
 return false;

 long long total = 0;
 long long available = 0;

 long status = pReader->Length(&total, &available);
 if (status < 0 || (total >= 0 && available > total))
 return false;

 long len = 0;
 const long long id = ReadID(pReader, pos, len);
 if (id < 0 || (available - pos) > len)
 return false;

 if (static_cast<unsigned long>(id) != expected_id)
 return false;

  pos += len; // consume id

 const long long size = ReadUInt(pReader, pos, len);
 if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
 return false;

 unsigned long long rollover_check =
 static_cast<unsigned long long>(pos) + len;
 if (rollover_check > LONG_LONG_MAX)
 return false;

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

  rollover_check = static_cast<unsigned long long>(pos) + size;
 if (rollover_check > LONG_LONG_MAX)
 return false;

 if ((pos + size) > available)
 return false;

 if (size >= LONG_MAX)
 return false;

 const long buflen_ = static_cast<long>(size);

  buf = SafeArrayAlloc<unsigned char>(1, buflen_);
 if (!buf)
 return false;

  status = pReader->Read(pos, buflen_, buf);
 if (status != 0)
 return false;

  buflen = buflen_;

  pos += size; // consume size of payload
 return true;
}

Project: Android

long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
 if (!pReader)
 return E_FILE_FORMAT_INVALID;

 long long total, available;

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

 if (status < 0) // error
 return status;

  pos = 0;
 long long end = (available >= 1024) ? 1024 : available;

 for (;;) {
 unsigned char b = 0;

 while (pos < end) {
      status = pReader->Read(pos, 1, &b);

 if (status < 0) // error
 return status;

 if (b == 0x1A)
 break;

 ++pos;
 }

 if (b != 0x1A) {
 if (pos >= 1024)
 return E_FILE_FORMAT_INVALID; // don't bother looking anymore

 if ((total >= 0) && ((total - available) < 5))
 return E_FILE_FORMAT_INVALID;

 return available + 5; // 5 = 4-byte ID + 1st byte of size
 }

 if ((total >= 0) && ((total - pos) < 5))
 return E_FILE_FORMAT_INVALID;

 if ((available - pos) < 5)
 return pos + 5; // try again later

 long len;

 const long long result = ReadUInt(pReader, pos, len);

 if (result < 0) // error
 return result;

 if (result == 0x0A45DFA3) { // EBML Header ID
      pos += len; // consume ID
 break;
 }

 ++pos; // throw away just the 0x1A byte, and try again
 }



 long len;
 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return result;

 if (result > 0) // need more data
 return result;

 if (len < 1 || len > 8)
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && ((total - pos) < len))
 return E_FILE_FORMAT_INVALID;

 if ((available - pos) < len)
 return pos + len; // try again later


  result = ReadUInt(pReader, pos, len);

 if (result < 0) // error
 return result;

  pos += len; // consume size field


 if ((total >= 0) && ((total - pos) < result))
 return E_FILE_FORMAT_INVALID;

 if ((available - pos) < result)
 return pos + result;

  end = pos + result;

 Init();

 while (pos < end) {
 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
      m_version = UnserializeUInt(pReader, pos, size);

 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;
 }

 if (pos != end)
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android

long SeekHead::Parse() {
 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long pos = m_start;
 const long long stop = m_start + m_size;


 int entry_count = 0;
 int void_element_count = 0;

 while (pos < stop) {
 long long id, size;

 const long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (id == 0x0DBB) // SeekEntry ID
 ++entry_count;
 else if (id == 0x6C) // Void ID
 ++void_element_count;

    pos += size; // consume payload

 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

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

 if (m_entries == NULL)
 return -1;

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

 if (m_void_elements == NULL)
 return -1;


 Entry* pEntry = m_entries;
 VoidElement* pVoidElement = m_void_elements;

  pos = m_start;

 while (pos < stop) {
 const long long idpos = pos;

 long long id, size;

 const long status = ParseElementHeader(pReader, pos, stop, id, size);

 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;
 }
 } else if (id == 0x6C) { // Void ID
 VoidElement& e = *pVoidElement++;

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

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
  assert(count_ >= 0);
  assert(count_ <= entry_count);

  m_entry_count = static_cast<int>(count_);

  count_ = ptrdiff_t(pVoidElement - m_void_elements);
  assert(count_ >= 0);
  assert(count_ <= void_element_count);

  m_void_element_count = static_cast<int>(count_);

 return 0;
}

Project: Android

bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
 long long size_) {
 const long long stop = start_ + size_;
 long long pos = start_;

  m_track = -1;
  m_pos = -1;
  m_block = 1; // default

 while (pos < stop) {
 long len;

 const long long id = ReadID(pReader, pos, len);
 if ((id < 0) || ((pos + len) > stop)) {
 return false;
 }

    pos += len; // consume ID

 const long long size = ReadUInt(pReader, pos, len);
 if ((size < 0) || ((pos + len) > stop)) {
 return false;
 }

    pos += len; // consume Size field
 if ((pos + size) > stop) {
 return false;
 }

 if (id == 0x77) // CueTrack ID
      m_track = UnserializeUInt(pReader, pos, size);

 else if (id == 0x71) // CueClusterPos ID
      m_pos = UnserializeUInt(pReader, pos, size);

 else if (id == 0x1378) // CueBlockNumber
      m_block = UnserializeUInt(pReader, pos, size);

    pos += size; // consume payload
 }

 if ((m_pos < 0) || (m_track <= 0)) {
 return false;
 }

 return true;
}

Project: Android

long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
 long long size) {
 const long long stop = pos + size;

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (size == 0) // weird
 continue;

 if (id == 0x36) { // Atom ID
      status = ParseAtom(pReader, pos, size);

 if (status < 0) // error
 return status;
 }

    pos += size;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 return 0;
}

Project: Android

long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
 const long long stop = pos + size;

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (size == 0) // weird
 continue;

 if (id == 0x00) { // Display ID
      status = ParseDisplay(pReader, pos, size);

 if (status < 0) // error
 return status;
 } else if (id == 0x1654) { // StringUID ID
      status = UnserializeString(pReader, pos, size, m_string_uid);

 if (status < 0) // error
 return status;
 } else if (id == 0x33C4) { // UID ID
 long long val;
      status = UnserializeInt(pReader, pos, size, val);

 if (status < 0) // error
 return status;

      m_uid = static_cast<unsigned long long>(val);
 } else if (id == 0x11) { // TimeStart ID
 const long long val = UnserializeUInt(pReader, pos, size);

 if (val < 0) // error
 return static_cast<long>(val);

      m_start_timecode = val;
 } else if (id == 0x12) { // TimeEnd ID
 const long long val = UnserializeUInt(pReader, pos, size);

 if (val < 0) // error
 return static_cast<long>(val);

      m_stop_timecode = val;
 }

    pos += size;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 return 0;
}

Project: Android

long Tags::Parse() {
 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long pos = m_start; // payload start
 const long long stop = pos + m_size; // payload stop

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0)
 return status;

 if (size == 0) // 0 length tag, read another
 continue;

 if (id == 0x3373) { // Tag ID
      status = ParseTag(pos, size);

 if (status < 0)
 return status;
 }

    pos += size;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android

long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
 const long long stop = pos + size;

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0)
 return status;

 if (size == 0) // 0 length tag, read another
 continue;

 if (id == 0x27C8) { // SimpleTag ID
      status = ParseSimpleTag(pReader, pos, size);

 if (status < 0)
 return status;
 }

    pos += size;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 return 0;
}

Project: Android

long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
 long long size) {
 const long long stop = pos + size;

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (size == 0) // weird
 continue;

 if (id == 0x5A3) { // TagName ID
      status = UnserializeString(pReader, pos, size, m_tag_name);

 if (status)
 return status;
 } else if (id == 0x487) { // TagString ID
      status = UnserializeString(pReader, pos, size, m_tag_string);

 if (status)
 return status;
 }

    pos += size;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 return 0;
}

Project: Android

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 = m_start;
 const long long stop = m_start + m_size;

  m_timecodeScale = 1000000;
  m_duration = -1;

 while (pos < stop) {
 long long id, size;

 const long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (id == 0x0AD7B1) { // Timecode Scale
      m_timecodeScale = UnserializeUInt(pReader, pos, size);

 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;

 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 const double rollover_check = m_duration * m_timecodeScale;
 if (rollover_check > LONG_LONG_MAX)
 return E_FILE_FORMAT_INVALID;

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android

long VideoTrack::Parse(Segment* pSegment, const Info& info,
 long long element_start, long long element_size,
 VideoTrack*& pResult) {
 if (pResult)
 return -1;

 if (info.type != Track::kVideo)
 return -1;

 long long width = 0;
 long long height = 0;
 long long display_width = 0;
 long long display_height = 0;
 long long display_unit = 0;
 long long stereo_mode = 0;

 double rate = 0.0;

 IMkvReader* const pReader = pSegment->m_pReader;

 const Settings& s = info.settings;
  assert(s.start >= 0);
  assert(s.size >= 0);

 long long pos = s.start;
  assert(pos >= 0);

 const long long stop = pos + s.size;

 while (pos < stop) {
 long long id, size;

 const long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (id == 0x30) { // pixel width
      width = UnserializeUInt(pReader, pos, size);

 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 == 0x14B0) { // display width
      display_width = UnserializeUInt(pReader, pos, size);

 if (display_width <= 0)
 return E_FILE_FORMAT_INVALID;
 } else if (id == 0x14BA) { // display height
      display_height = UnserializeUInt(pReader, pos, size);

 if (display_height <= 0)
 return E_FILE_FORMAT_INVALID;
 } else if (id == 0x14B2) { // display unit
      display_unit = UnserializeUInt(pReader, pos, size);

 if (display_unit < 0)
 return E_FILE_FORMAT_INVALID;
 } else if (id == 0x13B8) { // stereo mode
      stereo_mode = UnserializeUInt(pReader, pos, size);

 if (stereo_mode < 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
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 VideoTrack* const pTrack =
 new (std::nothrow) VideoTrack(pSegment, element_start, element_size);

 if (pTrack == NULL)
 return -1; // generic error

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

 if (status) { // error
 delete pTrack;
 return status;
 }

  pTrack->m_width = width;
  pTrack->m_height = height;
  pTrack->m_display_width = display_width;
  pTrack->m_display_height = display_height;
  pTrack->m_display_unit = display_unit;
  pTrack->m_stereo_mode = stereo_mode;
  pTrack->m_rate = rate;

  pResult = pTrack;
 return 0; // success
}

Project: Android

long AudioTrack::Parse(Segment* pSegment, const Info& info,
 long long element_start, long long element_size,
 AudioTrack*& pResult) {
 if (pResult)
 return -1;

 if (info.type != Track::kAudio)
 return -1;

 IMkvReader* const pReader = pSegment->m_pReader;

 const Settings& s = info.settings;
  assert(s.start >= 0);
  assert(s.size >= 0);

 long long pos = s.start;
  assert(pos >= 0);

 const long long stop = pos + s.size;

 double rate = 8000.0; // MKV default
 long long channels = 1;
 long long bit_depth = 0;

 while (pos < stop) {
 long long id, size;

 long status = ParseElementHeader(pReader, pos, stop, id, size);

 if (status < 0) // error
 return status;

 if (id == 0x35) { // Sample Rate
      status = UnserializeFloat(pReader, pos, size, rate);

 if (status < 0)
 return status;

 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
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 AudioTrack* const pTrack =
 new (std::nothrow) AudioTrack(pSegment, element_start, element_size);

 if (pTrack == NULL)
 return -1; // generic error

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

 if (status) {
 delete pTrack;
 return status;
 }

  pTrack->m_rate = rate;
  pTrack->m_channels = channels;
  pTrack->m_bitDepth = bit_depth;

  pResult = pTrack;
 return 0; // success
}

Project: Android

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;

 int count = 0;
 long long pos = m_start;

 while (pos < 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
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 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;

 long long id, payload_size;

 const long status =
 ParseElementHeader(pReader, pos, stop, id, payload_size);

 if (status < 0) // error
 return status;

 if (payload_size == 0) // weird
 continue;

 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;
      pTrack = NULL;

 const long status = ParseTrackEntry(pos, payload_size, element_start,
                                          element_size, pTrack);

 if (status)
 return status;

 if (pTrack)
 ++m_trackEntriesEnd;
 }

    pos = payload_stop;
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 return 0; // success
}

Project: Android

long Cluster::Parse(long long& pos, long& len) const {
 long status = Load(pos, len);

 if (status < 0)
 return status;

  assert(m_pos >= m_element_start);
  assert(m_timecode >= 0);

 const long long cluster_stop =
 (m_element_size < 0) ? -1 : m_element_start + m_element_size;

 if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
 return 1; // nothing else to do

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long total, avail;

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

 if (status < 0) // error
 return status;

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

  pos = m_pos;

 for (;;) {
 if ((cluster_stop >= 0) && (pos >= cluster_stop))
 break;

 if ((total >= 0) && (pos >= total)) {
 if (m_element_size < 0)
        m_element_size = pos - m_element_start;

 break;
 }


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error
 return static_cast<long>(id);

 if (id == 0) // weird
 return E_FILE_FORMAT_INVALID;


 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID
 if (m_element_size < 0)
        m_element_size = pos - m_element_start;

 break;
 }

    pos += len; // consume ID field


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long size = ReadUInt(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 size field

 if ((cluster_stop >= 0) && (pos > cluster_stop))
 return E_FILE_FORMAT_INVALID;


 if (size == 0) // weird
 continue;

 const long long block_stop = pos + size;

 if (cluster_stop >= 0) {
 if (block_stop > cluster_stop) {
 if ((id == 0x20) || (id == 0x23))
 return E_FILE_FORMAT_INVALID;

        pos = cluster_stop;
 break;
 }
 } else if ((total >= 0) && (block_stop > total)) {
      m_element_size = total - m_element_start;
      pos = total;
 break;
 } else if (block_stop > avail) {
      len = static_cast<long>(size);
 return E_BUFFER_NOT_FULL;
 }

 Cluster* const this_ = const_cast<Cluster*>(this);

 if (id == 0x20) // BlockGroup
 return this_->ParseBlockGroup(size, pos, len);

 if (id == 0x23) // SimpleBlock
 return this_->ParseSimpleBlock(size, pos, len);

    pos += size; // consume payload
 if (cluster_stop >= 0 && pos > cluster_stop)
 return E_FILE_FORMAT_INVALID;
 }

  assert(m_element_size > 0);

  m_pos = pos;
 if (cluster_stop >= 0 && m_pos > cluster_stop)
 return E_FILE_FORMAT_INVALID;

 if (m_entries_count > 0) {
 const long idx = m_entries_count - 1;

 const BlockEntry* const pLast = m_entries[idx];
    assert(pLast);

 const Block* const pBlock = pLast->GetBlock();
    assert(pBlock);

 const long long start = pBlock->m_start;

 if ((total >= 0) && (start > total))
 return -1; // defend against trucated stream

 const long long size = pBlock->m_size;

 const long long stop = start + size;
    assert((cluster_stop < 0) || (stop <= cluster_stop));

 if ((total >= 0) && (stop > total))
 return -1; // defend against trucated stream
 }

 return 1; // no more entries
}

Project: Android

long Block::Parse(const Cluster* pCluster) {
 if (pCluster == NULL)
 return -1;

 if (pCluster->m_pSegment == NULL)
 return -1;

  assert(m_start >= 0);
  assert(m_size >= 0);
  assert(m_track <= 0);
  assert(m_frames == NULL);
  assert(m_frame_count <= 0);

 long long pos = m_start;
 const long long stop = m_start + m_size;

 long len;

 IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;

  m_track = ReadUInt(pReader, pos, len);

 if (m_track <= 0)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > stop)
 return E_FILE_FORMAT_INVALID;

  pos += len; // consume track number

 if ((stop - pos) < 2)
 return E_FILE_FORMAT_INVALID;

 long status;
 long long value;

  status = UnserializeInt(pReader, pos, 2, value);

 if (status)
 return E_FILE_FORMAT_INVALID;

 if (value < SHRT_MIN)
 return E_FILE_FORMAT_INVALID;

 if (value > SHRT_MAX)
 return E_FILE_FORMAT_INVALID;

  m_timecode = static_cast<short>(value);

  pos += 2;

 if ((stop - pos) <= 0)
 return E_FILE_FORMAT_INVALID;

  status = pReader->Read(pos, 1, &m_flags);

 if (status)
 return E_FILE_FORMAT_INVALID;

 const int lacing = int(m_flags & 0x06) >> 1;

 ++pos; // consume flags byte

 if (lacing == 0) { // no lacing
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;

    m_frame_count = 1;
    m_frames = new (std::nothrow) Frame[m_frame_count];
 if (m_frames == NULL)
 return -1;

 Frame& f = m_frames[0];
    f.pos = pos;

 const long long frame_size = stop - pos;

 if (frame_size > LONG_MAX || frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

    f.len = static_cast<long>(frame_size);

 return 0; // success
 }

 if (pos >= stop)
 return E_FILE_FORMAT_INVALID;

 unsigned char biased_count;

  status = pReader->Read(pos, 1, &biased_count);

 if (status)
 return E_FILE_FORMAT_INVALID;

 ++pos; // consume frame count
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;

  m_frame_count = int(biased_count) + 1;

  m_frames = new (std::nothrow) Frame[m_frame_count];
 if (m_frames == NULL)
 return -1;

 if (!m_frames)
 return E_FILE_FORMAT_INVALID;

 if (lacing == 1) { // Xiph
 Frame* pf = m_frames;
 Frame* const pf_end = pf + m_frame_count;

 long long size = 0;
 int frame_count = m_frame_count;

 while (frame_count > 1) {
 long frame_size = 0;

 for (;;) {
 unsigned char val;

 if (pos >= stop)
 return E_FILE_FORMAT_INVALID;

        status = pReader->Read(pos, 1, &val);

 if (status)
 return E_FILE_FORMAT_INVALID;

 ++pos; // consume xiph size byte

        frame_size += val;

 if (val < 255)
 break;
 }

 Frame& f = *pf++;
      assert(pf < pf_end);
 if (pf >= pf_end)
 return E_FILE_FORMAT_INVALID;

      f.pos = 0; // patch later

 if (frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

      f.len = frame_size;
      size += frame_size; // contribution of this frame

 --frame_count;
 }

 if (pf >= pf_end || pos > stop)
 return E_FILE_FORMAT_INVALID;

 {
 Frame& f = *pf++;

 if (pf != pf_end)
 return E_FILE_FORMAT_INVALID;

      f.pos = 0; // patch later

 const long long total_size = stop - pos;

 if (total_size < size)
 return E_FILE_FORMAT_INVALID;

 const long long frame_size = total_size - size;

 if (frame_size > LONG_MAX || frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

      f.len = static_cast<long>(frame_size);
 }

    pf = m_frames;
 while (pf != pf_end) {
 Frame& f = *pf++;
      assert((pos + f.len) <= stop);

 if ((pos + f.len) > stop)
 return E_FILE_FORMAT_INVALID;

      f.pos = pos;
      pos += f.len;
 }

    assert(pos == stop);
 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 } else if (lacing == 2) { // fixed-size lacing
 if (pos >= stop)
 return E_FILE_FORMAT_INVALID;

 const long long total_size = stop - pos;

 if ((total_size % m_frame_count) != 0)
 return E_FILE_FORMAT_INVALID;

 const long long frame_size = total_size / m_frame_count;

 if (frame_size > LONG_MAX || frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

 Frame* pf = m_frames;
 Frame* const pf_end = pf + m_frame_count;

 while (pf != pf_end) {
      assert((pos + frame_size) <= stop);
 if ((pos + frame_size) > stop)
 return E_FILE_FORMAT_INVALID;

 Frame& f = *pf++;

      f.pos = pos;
      f.len = static_cast<long>(frame_size);

      pos += frame_size;
 }

    assert(pos == stop);
 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 } else {
    assert(lacing == 3); // EBML lacing

 if (pos >= stop)
 return E_FILE_FORMAT_INVALID;

 long long size = 0;
 int frame_count = m_frame_count;

 long long frame_size = ReadUInt(pReader, pos, len);

 if (frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

 if (frame_size > LONG_MAX)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > stop)
 return E_FILE_FORMAT_INVALID;

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

 if ((pos + frame_size) > stop)
 return E_FILE_FORMAT_INVALID;

 Frame* pf = m_frames;
 Frame* const pf_end = pf + m_frame_count;

 {
 Frame& curr = *pf;

      curr.pos = 0; // patch later

      curr.len = static_cast<long>(frame_size);
      size += curr.len; // contribution of this frame
 }

 --frame_count;

 while (frame_count > 1) {
 if (pos >= stop)
 return E_FILE_FORMAT_INVALID;

      assert(pf < pf_end);
 if (pf >= pf_end)
 return E_FILE_FORMAT_INVALID;


 const Frame& prev = *pf++;
      assert(prev.len == frame_size);
 if (prev.len != frame_size)
 return E_FILE_FORMAT_INVALID;

      assert(pf < pf_end);
 if (pf >= pf_end)
 return E_FILE_FORMAT_INVALID;

 Frame& curr = *pf;

      curr.pos = 0; // patch later

 const long long delta_size_ = ReadUInt(pReader, pos, len);

 if (delta_size_ < 0)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > stop)
 return E_FILE_FORMAT_INVALID;

      pos += len; // consume length of (delta) size
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;

 const int exp = 7 * len - 1;
 const long long bias = (1LL << exp) - 1LL;
 const long long delta_size = delta_size_ - bias;

      frame_size += delta_size;

 if (frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

 if (frame_size > LONG_MAX)
 return E_FILE_FORMAT_INVALID;

      curr.len = static_cast<long>(frame_size);
      size += curr.len; // contribution of this frame

 --frame_count;
 }

 if (frame_count > 0) {
 if (pos > stop || pf >= pf_end)
 return E_FILE_FORMAT_INVALID;

 const Frame& prev = *pf++;
      assert(prev.len == frame_size);
 if (prev.len != frame_size)
 return E_FILE_FORMAT_INVALID;

 if (pf >= pf_end)
 return E_FILE_FORMAT_INVALID;

 Frame& curr = *pf++;
 if (pf != pf_end)
 return E_FILE_FORMAT_INVALID;

      curr.pos = 0; // patch later

 const long long total_size = stop - pos;

 if (total_size < size)
 return E_FILE_FORMAT_INVALID;

      frame_size = total_size - size;

 if (frame_size > LONG_MAX || frame_size <= 0)
 return E_FILE_FORMAT_INVALID;

      curr.len = static_cast<long>(frame_size);
 }

    pf = m_frames;
 while (pf != pf_end) {
 Frame& f = *pf++;
      assert((pos + f.len) <= stop);
 if ((pos + f.len) > stop)
 return E_FILE_FORMAT_INVALID;

      f.pos = pos;
      pos += f.len;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 }

 return 0; // success
}

Project: Android

long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
 long& len) {
 const long long payload_start = pos;
 const long long payload_stop = pos + payload_size;

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long total, avail;

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

 if (status < 0) // error
 return status;

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

 if ((total >= 0) && (payload_stop > total))
 return E_FILE_FORMAT_INVALID;

 if (payload_stop > avail) {
    len = static_cast<long>(payload_size);
 return E_BUFFER_NOT_FULL;
 }

 long long discard_padding = 0;

 while (pos < payload_stop) {

 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((pos + len) > payload_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id < 0) // error
 return static_cast<long>(id);

 if (id == 0) // not a value ID
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume ID field


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((pos + len) > payload_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (size < 0) // error
 return static_cast<long>(size);

    pos += len; // consume size field


 if (pos > payload_stop)
 return E_FILE_FORMAT_INVALID;

 if (size == 0) // weird
 continue;

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

 if (size == unknown_size)
 return E_FILE_FORMAT_INVALID;

 if (id == 0x35A2) { // DiscardPadding
      status = UnserializeInt(pReader, pos, size, discard_padding);

 if (status < 0) // error
 return status;
 }

 if (id != 0x21) { // sub-part of BlockGroup is not a Block
      pos += size; // consume sub-part of block group

 if (pos > payload_stop)
 return E_FILE_FORMAT_INVALID;

 continue;
 }

 const long long block_stop = pos + size;

 if (block_stop > payload_stop)
 return E_FILE_FORMAT_INVALID;


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((pos + len) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long track = ReadUInt(pReader, pos, len);

 if (track < 0) // error
 return static_cast<long>(track);

 if (track == 0)
 return E_FILE_FORMAT_INVALID;

    pos += len; // consume track number

 if ((pos + 2) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + 2) > avail) {
      len = 2;
 return E_BUFFER_NOT_FULL;
 }

    pos += 2; // consume timecode

 if ((pos + 1) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

 unsigned char flags;

    status = pReader->Read(pos, 1, &flags);

 if (status < 0) { // error or underflow
      len = 1;
 return status;
 }

 ++pos; // consume flags byte
    assert(pos <= avail);

 if (pos >= block_stop)
 return E_FILE_FORMAT_INVALID;

 const int lacing = int(flags & 0x06) >> 1;

 if ((lacing != 0) && (block_stop > avail)) {
      len = static_cast<long>(block_stop - pos);
 return E_BUFFER_NOT_FULL;
 }

    pos = block_stop; // consume block-part of block group
 if (pos > payload_stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != payload_stop)
 return E_FILE_FORMAT_INVALID;

  status = CreateBlock(0x20, // BlockGroup ID
                       payload_start, payload_size, discard_padding);
 if (status != 0)
 return status;

  m_pos = payload_stop;

 return 0; // success
}

Project: Android

long ContentEncoding::ParseCompressionEntry(long long start, long long size,
 IMkvReader* pReader,
 ContentCompression* compression) {
  assert(pReader);
  assert(compression);

 long long pos = start;
 const long long stop = start + size;

 bool valid = false;

 while (pos < stop) {
 long long id, size;
 const long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x254) {
 long long algo = UnserializeUInt(pReader, pos, size);
 if (algo < 0)
 return E_FILE_FORMAT_INVALID;
      compression->algo = algo;
      valid = true;
 } else if (id == 0x255) {
 if (size <= 0)
 return E_FILE_FORMAT_INVALID;

 const size_t buflen = static_cast<size_t>(size);
 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
 if (buf == NULL)
 return -1;

 const int read_status =
          pReader->Read(pos, static_cast<long>(buflen), buf);
 if (read_status) {
 delete[] buf;
 return status;
 }

      compression->settings = buf;
      compression->settings_len = buflen;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (!valid)
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android

long ContentEncoding::ParseContentEncAESSettingsEntry(
 long long start, long long size, IMkvReader* pReader,
 ContentEncAESSettings* aes) {
  assert(pReader);
  assert(aes);

 long long pos = start;
 const long long stop = start + size;

 while (pos < stop) {
 long long id, size;
 const long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x7E8) {
      aes->cipher_mode = UnserializeUInt(pReader, pos, size);
 if (aes->cipher_mode != 1)
 return E_FILE_FORMAT_INVALID;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 return 0;
}

Project: Android

long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
 IMkvReader* pReader) {
  assert(pReader);

 long long pos = start;
 const long long stop = start + size;

 int compression_count = 0;
 int encryption_count = 0;

 while (pos < stop) {
 long long id, size;
 const long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x1034) // ContentCompression ID
 ++compression_count;

 if (id == 0x1035) // ContentEncryption ID
 ++encryption_count;

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (compression_count <= 0 && encryption_count <= 0)
 return -1;

 if (compression_count > 0) {
    compression_entries_ =
 new (std::nothrow) ContentCompression*[compression_count];
 if (!compression_entries_)
 return -1;
    compression_entries_end_ = compression_entries_;
 }

 if (encryption_count > 0) {
    encryption_entries_ =
 new (std::nothrow) ContentEncryption*[encryption_count];
 if (!encryption_entries_) {
 delete[] compression_entries_;
 return -1;
 }
    encryption_entries_end_ = encryption_entries_;
 }

  pos = start;
 while (pos < stop) {
 long long id, size;
 long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x1031) {
      encoding_order_ = UnserializeUInt(pReader, pos, size);
 } else if (id == 0x1032) {
      encoding_scope_ = UnserializeUInt(pReader, pos, size);
 if (encoding_scope_ < 1)
 return -1;
 } else if (id == 0x1033) {
      encoding_type_ = UnserializeUInt(pReader, pos, size);
 } else if (id == 0x1034) {
 ContentCompression* const compression =
 new (std::nothrow) ContentCompression();
 if (!compression)
 return -1;

      status = ParseCompressionEntry(pos, size, pReader, compression);
 if (status) {
 delete compression;
 return status;
 }
 *compression_entries_end_++ = compression;
 } else if (id == 0x1035) {
 ContentEncryption* const encryption =
 new (std::nothrow) ContentEncryption();
 if (!encryption)
 return -1;

      status = ParseEncryptionEntry(pos, size, pReader, encryption);
 if (status) {
 delete encryption;
 return status;
 }
 *encryption_entries_end_++ = encryption;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;
 return 0;
}

Project: Android

long Track::ParseContentEncodingsEntry(long long start, long long size) {
 IMkvReader* const pReader = m_pSegment->m_pReader;
  assert(pReader);

 long long pos = start;
 const long long stop = start + size;

 int count = 0;
 while (pos < stop) {
 long long id, size;
 const long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x2240) // ContentEncoding ID
 ++count;

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (count <= 0)
 return -1;

  content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
 if (!content_encoding_entries_)
 return -1;

  content_encoding_entries_end_ = content_encoding_entries_;

  pos = start;
 while (pos < stop) {
 long long id, size;
 long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x2240) { // ContentEncoding ID
 ContentEncoding* const content_encoding =
 new (std::nothrow) ContentEncoding();
 if (!content_encoding)
 return -1;

      status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
 if (status) {
 delete content_encoding;
 return status;
 }

 *content_encoding_entries_end_++ = content_encoding;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != stop)
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android

long Segment::ParseCues(long long off, long long& pos, long& len) {
 if (m_pCues)
 return 0; // success

 if (off < 0)
 return -1;

 long long total, avail;

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

 if (status < 0) // error
 return status;

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

  pos = m_start + off;

 if ((total < 0) || (pos >= total))
 return 1; // don't bother parsing cues

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

 if ((pos + 1) > avail) {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

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

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // underflow (weird)
 {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long idpos = pos;

 const long long id = ReadID(m_pReader, idpos, len);

 if (id != 0x0C53BB6B) // Cues ID
 return E_FILE_FORMAT_INVALID;

  pos += len; // consume ID
  assert((segment_stop < 0) || (pos <= segment_stop));


 if ((pos + 1) > avail) {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

  result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // underflow (weird)
 {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (size < 0) // error
 return static_cast<long>(size);

 if (size == 0) // weird, although technically not illegal
 return 1; // done

  pos += len; // consume length of size of element
  assert((segment_stop < 0) || (pos <= segment_stop));


 const long long element_stop = pos + size;

 if ((segment_stop >= 0) && (element_stop > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((total >= 0) && (element_stop > total))
 return 1; // don't bother parsing anymore

  len = static_cast<long>(size);

 if (element_stop > avail)
 return E_BUFFER_NOT_FULL;

 const long long element_size = element_stop - element_start;

  m_pCues =
 new (std::nothrow) Cues(this, pos, size, element_start, element_size);
 if (m_pCues == NULL)
 return -1;

 return 0; // success
}

Project: Android

long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
 IMkvReader* pReader,
 ContentEncryption* encryption) {
  assert(pReader);
  assert(encryption);

 long long pos = start;
 const long long stop = start + size;

 while (pos < stop) {
 long long id, size;
 const long status = ParseElementHeader(pReader, pos, stop, id, size);
 if (status < 0) // error
 return status;

 if (id == 0x7E1) {
      encryption->algo = UnserializeUInt(pReader, pos, size);
 if (encryption->algo != 5)
 return E_FILE_FORMAT_INVALID;
 } else if (id == 0x7E2) {
 delete[] encryption->key_id;
      encryption->key_id = NULL;
      encryption->key_id_len = 0;

 if (size <= 0)
 return E_FILE_FORMAT_INVALID;

 const size_t buflen = static_cast<size_t>(size);
 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
 if (buf == NULL)
 return -1;

 const int read_status =
          pReader->Read(pos, static_cast<long>(buflen), buf);
 if (read_status) {
 delete[] buf;
 return status;
 }

      encryption->key_id = buf;
      encryption->key_id_len = buflen;
 } else if (id == 0x7E3) {
 delete[] encryption->signature;
      encryption->signature = NULL;
      encryption->signature_len = 0;

 if (size <= 0)
 return E_FILE_FORMAT_INVALID;

 const size_t buflen = static_cast<size_t>(size);
 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
 if (buf == NULL)
 return -1;

 const int read_status =
          pReader->Read(pos, static_cast<long>(buflen), buf);
 if (read_status) {
 delete[] buf;
 return status;
 }

      encryption->signature = buf;
      encryption->signature_len = buflen;
 } else if (id == 0x7E4) {
 delete[] encryption->sig_key_id;
      encryption->sig_key_id = NULL;
      encryption->sig_key_id_len = 0;

 if (size <= 0)
 return E_FILE_FORMAT_INVALID;

 const size_t buflen = static_cast<size_t>(size);
 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
 if (buf == NULL)
 return -1;

 const int read_status =
          pReader->Read(pos, static_cast<long>(buflen), buf);
 if (read_status) {
 delete[] buf;
 return status;
 }

      encryption->sig_key_id = buf;
      encryption->sig_key_id_len = buflen;
 } else if (id == 0x7E5) {
      encryption->sig_algo = UnserializeUInt(pReader, pos, size);
 } else if (id == 0x7E6) {
      encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
 } else if (id == 0x7E7) {
 const long status = ParseContentEncAESSettingsEntry(
          pos, size, pReader, &encryption->aes_settings);
 if (status)
 return status;
 }

    pos += size; // consume payload
 if (pos > stop)
 return E_FILE_FORMAT_INVALID;
 }

 return 0;
}

Project: Android

long long Segment::ParseHeaders() {
 long long total, available;

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

 if (status < 0) // error
 return status;

 if (total > 0 && available > total)
 return E_FILE_FORMAT_INVALID;

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

 if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
 (segment_stop >= 0 && m_pos > segment_stop)) {
 return E_FILE_FORMAT_INVALID;
 }

 for (;;) {
 if ((total >= 0) && (m_pos >= total))
 break;

 if ((segment_stop >= 0) && (m_pos >= segment_stop))
 break;

 long long pos = m_pos;
 const long long element_start = pos;

 unsigned long long rollover_check = pos + 1ULL;
 if (rollover_check > LONG_LONG_MAX)
 return E_FILE_FORMAT_INVALID;

 if ((pos + 1) > available)
 return (pos + 1);

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

 if (result < 0) // error
 return result;

 if (result > 0) {
 return (pos + 1);
 }

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > available)
 return pos + len;

 const long long idpos = pos;
 const long long id = ReadID(m_pReader, idpos, len);

 if (id < 0)
 return E_FILE_FORMAT_INVALID;

 if (id == 0x0F43B675) // Cluster ID
 break;

    pos += len; // consume ID

 if ((pos + 1) > available)
 return (pos + 1);

    result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return result;

 if (result > 0) {
 return (pos + 1);
 }

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > available)
 return pos + len;

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

 if (size < 0 || len < 1 || len > 8) {
 return size;
 }

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

    rollover_check = static_cast<unsigned long long>(pos) + size;
 if (rollover_check > LONG_LONG_MAX)
 return E_FILE_FORMAT_INVALID;

 const long long element_size = size + pos - element_start;


 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
 return E_FILE_FORMAT_INVALID;


 if ((pos + size) > available)
 return pos + size;

 if (id == 0x0549A966) { // Segment Info ID
 if (m_pInfo)
 return E_FILE_FORMAT_INVALID;

      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
 if (m_pTracks)
 return E_FILE_FORMAT_INVALID;

      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 (std::nothrow)
 Cues(this, pos, size, element_start, element_size);

 if (m_pCues == NULL)
 return -1;
 }
 } else if (id == 0x014D9B74) { // SeekHead ID
 if (m_pSeekHead == NULL) {
        m_pSeekHead = new (std::nothrow)
 SeekHead(this, pos, size, element_start, element_size);

 if (m_pSeekHead == NULL)
 return -1;

 const long status = m_pSeekHead->Parse();

 if (status)
 return status;
 }
 } else if (id == 0x0043A770) { // Chapters ID
 if (m_pChapters == NULL) {
        m_pChapters = new (std::nothrow)
 Chapters(this, pos, size, element_start, element_size);

 if (m_pChapters == NULL)
 return -1;

 const long status = m_pChapters->Parse();

 if (status)
 return status;
 }
 } else if (id == 0x0254C367) { // Tags ID
 if (m_pTags == NULL) {
        m_pTags = new (std::nothrow)
 Tags(this, pos, size, element_start, element_size);

 if (m_pTags == NULL)
 return -1;

 const long status = m_pTags->Parse();

 if (status)
 return status;
 }
 }

    m_pos = pos + size; // consume payload
 }

 if (segment_stop >= 0 && m_pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 if (m_pInfo == NULL) // TODO: liberalize this behavior
 return E_FILE_FORMAT_INVALID;

 if (m_pTracks == NULL)
 return E_FILE_FORMAT_INVALID;

 return 0; // success
}

Project: Android

long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
 long long& pos, long& len) {
  assert(pCurr);
  assert(!pCurr->EOS());
  assert(m_clusters);

  pResult = 0;

 if (pCurr->m_index >= 0) { // loaded (not merely preloaded)
    assert(m_clusters[pCurr->m_index] == pCurr);

 const long next_idx = pCurr->m_index + 1;

 if (next_idx < m_clusterCount) {
      pResult = m_clusters[next_idx];
 return 0; // success
 }


 const long result = LoadCluster(pos, len);

 if (result < 0) // error or underflow
 return result;

 if (result > 0) // no more clusters
 {
 return 1;
 }

    pResult = GetLast();
 return 0; // success
 }

  assert(m_pos > 0);

 long long total, avail;

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

 if (status < 0) // error
 return status;

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

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


  pos = pCurr->m_element_start;

 if (pCurr->m_element_size >= 0)
    pos += pCurr->m_element_size;
 else {
 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

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

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

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

 if (id != 0x0F43B675) // weird: not Cluster ID
 return -1;

    pos += len; // consume ID


 if ((pos + 1) > avail) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result = GetUIntLength(m_pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 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 size field

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

 if (size == unknown_size) // TODO: should never happen
 return E_FILE_FORMAT_INVALID; // TODO: resolve this


 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
 return E_FILE_FORMAT_INVALID;


    pos += size; // consume payload (that is, the current cluster)
 if (segment_stop >= 0 && pos > segment_stop)
 return E_FILE_FORMAT_INVALID;

 }


 for (;;) {
 const long status = DoParseNext(pResult, pos, len);

 if (status <= 1)
 return status;
 }
}

Project: Android

long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
 long& len) {
 const long long block_start = pos;
 const long long block_stop = pos + block_size;

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long total, avail;

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

 if (status < 0) // error
 return status;

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


 if ((pos + 1) > avail) {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

 long long result = GetUIntLength(pReader, pos, len);

 if (result < 0) // error
 return static_cast<long>(result);

 if (result > 0) // weird
 return E_BUFFER_NOT_FULL;

 if ((pos + len) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + len) > avail)
 return E_BUFFER_NOT_FULL;

 const long long track = ReadUInt(pReader, pos, len);

 if (track < 0) // error
 return static_cast<long>(track);

 if (track == 0)
 return E_FILE_FORMAT_INVALID;

  pos += len; // consume track number

 if ((pos + 2) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + 2) > avail) {
    len = 2;
 return E_BUFFER_NOT_FULL;
 }

  pos += 2; // consume timecode

 if ((pos + 1) > block_stop)
 return E_FILE_FORMAT_INVALID;

 if ((pos + 1) > avail) {
    len = 1;
 return E_BUFFER_NOT_FULL;
 }

 unsigned char flags;

  status = pReader->Read(pos, 1, &flags);

 if (status < 0) { // error or underflow
    len = 1;
 return status;
 }

 ++pos; // consume flags byte
  assert(pos <= avail);

 if (pos >= block_stop)
 return E_FILE_FORMAT_INVALID;

 const int lacing = int(flags & 0x06) >> 1;

 if ((lacing != 0) && (block_stop > avail)) {
    len = static_cast<long>(block_stop - pos);
 return E_BUFFER_NOT_FULL;
 }

  status = CreateBlock(0x23, // simple block id
                       block_start, block_size,
 0); // DiscardPadding

 if (status != 0)
 return status;

  m_pos = block_stop;

 return 0; // success
}

Project: Android
File: mkvparser.cc

long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
 long long size) {
 if (!ExpandSimpleTagsArray())
 return -1;

 SimpleTag& st = m_simple_tags[m_simple_tags_count++];
  st.Init();

 return st.Parse(pReader, pos, size);
}

Project: Android
File: mkvparser.cc

long Tags::ParseTag(long long pos, long long size) {
 if (!ExpandTagsArray())
 return -1;

 Tag& t = m_tags[m_tags_count++];
  t.Init();

 return t.Parse(m_pSegment->m_pReader, pos, size);
}

Project: Android

long Tracks::ParseTrackEntry(long long track_start, long long track_size,
 long long element_start, long long element_size,
 Track*& pResult) const {
 if (pResult)
 return -1;

 IMkvReader* const pReader = m_pSegment->m_pReader;

 long long pos = track_start;
 const long long track_stop = track_start + track_size;

 Track::Info info;

  info.type = 0;
  info.number = 0;
  info.uid = 0;
  info.defaultDuration = 0;

 Track::Settings v;
  v.start = -1;
  v.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 < track_stop) {
 long long id, size;

 const long status = ParseElementHeader(pReader, pos, track_stop, id, size);

 if (status < 0) // error
 return status;

 if (size < 0)
 return E_FILE_FORMAT_INVALID;

 const long long start = pos;

 if (id == 0x60) { // VideoSettings ID
      v.start = start;
      v.size = size;
 } else if (id == 0x61) { // AudioSettings ID
      a.start = start;
      a.size = size;
 } else if (id == 0x2D80) { // ContentEncodings ID
      e.start = start;
      e.size = size;
 } else if (id == 0x33C5) { // Track UID
 if (size > 8)
 return E_FILE_FORMAT_INVALID;

      info.uid = 0;

 long long pos_ = start;
 const long long pos_end = start + size;

 while (pos_ != pos_end) {
 unsigned char b;

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

 if (status)
 return status;

        info.uid <<= 8;
        info.uid |= b;

 ++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;

      info.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;

      info.type = static_cast<long>(type);
 } else if (id == 0x136E) { // Track Name
 const long status =
 UnserializeString(pReader, pos, size, info.nameAsUTF8);

 if (status)
 return status;
 } else if (id == 0x02B59C) { // Track Language
 const long status = UnserializeString(pReader, pos, size, info.language);

 if (status)
 return status;
 } else if (id == 0x03E383) { // Default Duration
 const long long duration = UnserializeUInt(pReader, pos, size);

 if (duration < 0)
 return E_FILE_FORMAT_INVALID;

      info.defaultDuration = static_cast<unsigned long long>(duration);
 } else if (id == 0x06) { // CodecID
 const long status = UnserializeString(pReader, pos, size, info.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[] info.codecPrivate;
      info.codecPrivate = NULL;
      info.codecPrivateSize = 0;

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

 if (buflen) {
 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);

 if (buf == NULL)
 return -1;

 const int status = pReader->Read(pos, static_cast<long>(buflen), buf);

 if (status) {
 delete[] buf;
 return status;
 }

        info.codecPrivate = buf;
        info.codecPrivateSize = buflen;
 }
 } else if (id == 0x058688) { // Codec Name
 const long status =
 UnserializeString(pReader, pos, size, info.codecNameAsUTF8);

 if (status)
 return status;
 } else if (id == 0x16AA) { // Codec Delay
      info.codecDelay = UnserializeUInt(pReader, pos, size);
 } else if (id == 0x16BB) { // Seek Pre Roll
      info.seekPreRoll = UnserializeUInt(pReader, pos, size);
 }

    pos += size; // consume payload
 if (pos > track_stop)
 return E_FILE_FORMAT_INVALID;
 }

 if (pos != track_stop)
 return E_FILE_FORMAT_INVALID;

 if (info.number <= 0) // not specified
 return E_FILE_FORMAT_INVALID;

 if (GetTrackByNumber(info.number))
 return E_FILE_FORMAT_INVALID;

 if (info.type <= 0) // not specified
 return E_FILE_FORMAT_INVALID;

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

 if (info.type == Track::kVideo) {
 if (v.start < 0)
 return E_FILE_FORMAT_INVALID;

 if (a.start >= 0)
 return E_FILE_FORMAT_INVALID;

    info.settings = v;

 VideoTrack* pTrack = NULL;

 const long status = VideoTrack::Parse(m_pSegment, info, element_start,
                                          element_size, pTrack);

 if (status)
 return status;

    pResult = pTrack;
    assert(pResult);

 if (e.start >= 0)
      pResult->ParseContentEncodingsEntry(e.start, e.size);
 } else if (info.type == Track::kAudio) {
 if (a.start < 0)
 return E_FILE_FORMAT_INVALID;

 if (v.start >= 0)
 return E_FILE_FORMAT_INVALID;

    info.settings = a;

 AudioTrack* pTrack = NULL;

 const long status = AudioTrack::Parse(m_pSegment, info, element_start,
                                          element_size, pTrack);

 if (status)
 return status;

    pResult = pTrack;
    assert(pResult);

 if (e.start >= 0)
      pResult->ParseContentEncodingsEntry(e.start, e.size);
 } else {

 if (a.start >= 0)
 return E_FILE_FORMAT_INVALID;

 if (v.start >= 0)
 return E_FILE_FORMAT_INVALID;

 if (info.type == Track::kMetadata && e.start >= 0)
 return E_FILE_FORMAT_INVALID;

    info.settings.start = -1;
    info.settings.size = 0;

 Track* pTrack = NULL;

 const long status =
 Track::Create(m_pSegment, info, element_start, element_size, pTrack);

 if (status)
 return status;

    pResult = pTrack;
    assert(pResult);
 }

 return 0; // success
}

Project: Android

bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
  assert(pCluster);
  assert(pCluster->m_index < 0);
  assert(idx >= m_clusterCount);

 const long count = m_clusterCount + m_clusterPreloadCount;

 long& size = m_clusterSize;
  assert(size >= count);

 if (count >= size) {
 const long n = (size <= 0) ? 2048 : 2 * size;

 Cluster** const qq = new (std::nothrow) Cluster*[n];
 if (qq == NULL)
 return false;
 Cluster** q = qq;

 Cluster** p = m_clusters;
 Cluster** const pp = p + count;

 while (p != pp)
 *q++ = *p++;

 delete[] m_clusters;

    m_clusters = qq;
    size = n;
 }

  assert(m_clusters);

 Cluster** const p = m_clusters + idx;

 Cluster** q = m_clusters + count;
  assert(q >= p);
  assert(q < (m_clusters + size));

 while (q > p) {
 Cluster** const qq = q - 1;
    assert((*qq)->m_index < 0);

 *q = *qq;
    q = qq;
 }

  m_clusters[idx] = pCluster;
 ++m_clusterPreloadCount;
 return true;
}

Project: Android
File: mkvparser.cc

bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
 if (m_count != 0)
 return false;

 if (m_preload_count >= cue_points_size) {
 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;

 CuePoint** const qq = new (std::nothrow) CuePoint*[n];
 if (qq == NULL)
 return false;

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

 CuePoint** p = m_cue_points; // beginning of source
 CuePoint** const pp = p + m_preload_count; // end of source

 while (p != pp)
 *q++ = *p++;

 delete[] m_cue_points;

    m_cue_points = qq;
    cue_points_size = n;
 }

 CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
 if (pCP == NULL)
 return false;

  m_cue_points[m_preload_count++] = pCP;
 return true;
}

Project: Android

long long ReadID(IMkvReader* pReader, long long pos, long& len) {
 const long long id = ReadUInt(pReader, pos, len);
 if (id < 0 || len < 1 || len > 4) {
 return E_FILE_FORMAT_INVALID;
 }
 return id;
}

Project: Android
File: mkvparser.cc

long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
 if (!pReader || pos < 0)
 return E_FILE_FORMAT_INVALID;

  len = 1;
 unsigned char b;
 int status = pReader->Read(pos, 1, &b);

 if (status < 0) // error or underflow
 return status;

 if (status > 0) // interpreted as "underflow"
 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;

 while (!(b & m)) {
    m >>= 1;
 ++len;
 }

 long long result = b & (~m);
 ++pos;

 for (int i = 1; i < len; ++i) {
    status = pReader->Read(pos, 1, &b);

 if (status < 0) {
      len = 1;
 return status;
 }

 if (status > 0) {
      len = 1;
 return E_BUFFER_NOT_FULL;
 }

    result <<= 8;
    result |= b;

 ++pos;
 }

 return result;
}

Project: Android

template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
 unsigned long long element_size) {
 if (num_elements == 0 || element_size == 0)
 return NULL;

 const size_t kMaxAllocSize = 0x80000000; // 2GiB
 const unsigned long long num_bytes = num_elements * element_size;
 if (element_size > (kMaxAllocSize / num_elements))
 return NULL;

 return new (std::nothrow) Type[num_bytes];
}

Project: Android

long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
 const long status = GetFirst(pResult);

 if (status < 0) // buffer underflow, etc
 return status;

  assert(pResult);

 if (pResult->EOS())
 return 0;

 const Cluster* pCluster = pResult->GetCluster();
  assert(pCluster);
  assert(pCluster->GetIndex() >= 0);

 if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
 return 0;

 Cluster** const clusters = m_pSegment->m_clusters;
  assert(clusters);

 const long count = m_pSegment->GetCount(); // loaded only, not pre-loaded
  assert(count > 0);

 Cluster** const i = clusters + pCluster->GetIndex();
  assert(i);
  assert(*i == pCluster);
  assert(pCluster->GetTime() <= time_ns);

 Cluster** const j = clusters + count;

 Cluster** lo = i;
 Cluster** hi = j;

 while (lo < hi) {

 Cluster** const mid = lo + (hi - lo) / 2;
    assert(mid < hi);

    pCluster = *mid;
    assert(pCluster);
    assert(pCluster->GetIndex() >= 0);
    assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));

 const long long t = pCluster->GetTime();

 if (t <= time_ns)
      lo = mid + 1;
 else
      hi = mid;

    assert(lo <= hi);
 }

  assert(lo == hi);
  assert(lo > i);
  assert(lo <= j);

  pCluster = *--lo;
  assert(pCluster);
  assert(pCluster->GetTime() <= time_ns);

  pResult = pCluster->GetEntry(this, time_ns);

 if ((pResult != 0) && !pResult->EOS()) // found a keyframe
 return 0;

 while (lo != i) {
    pCluster = *--lo;
    assert(pCluster);
    assert(pCluster->GetTime() <= time_ns);

    pResult = pCluster->GetEntry(this, time_ns);

 if ((pResult != 0) && !pResult->EOS())
 return 0;
 }


  pResult = GetEOS();
 return 0;
}

Project: Android

Segment::Segment(IMkvReader* pReader, long long elem_start,
 long long start, long long size)
 : m_pReader(pReader),
      m_element_start(elem_start),
      m_start(start),
      m_size(size),
      m_pos(start),
      m_pUnknownSize(0),
      m_pSeekHead(NULL),
      m_pInfo(NULL),
      m_pTracks(NULL),
      m_pCues(NULL),
      m_pChapters(NULL),
      m_pTags(NULL),
      m_clusters(NULL),
      m_clusterCount(0),
      m_clusterPreloadCount(0),
      m_clusterSize(0) {}

Project: Android
File: mkvparser.cc

void Tags::Tag::ShallowCopy(Tag& rhs) const {
  rhs.m_simple_tags = m_simple_tags;
  rhs.m_simple_tags_size = m_simple_tags_size;
  rhs.m_simple_tags_count = m_simple_tags_count;
}

Project: Android
File: mkvparser.cc

Tags::SimpleTag::SimpleTag() {}

Project: Android
File: mkvparser.cc

Tags::Tag::Tag() {}

Project: Android

long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
 double& result) {
 if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
 return E_FILE_FORMAT_INVALID;

 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;
 } else {
 union {
 double d;
 unsigned long long dd;
 };

    dd = 0;

 for (int i = 0;;) {
      dd |= buf[i];

 if (++i >= 8)
 break;

      dd <<= 8;
 }

    result = d;
 }

 if (std::isinf(result) || std::isnan(result))
 return E_FILE_FORMAT_INVALID;

 return 0;
}

Project: Android
File: mkvparser.cc

long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
 long long& result_ref) {
 if (!pReader || pos < 0 || size < 1 || size > 8)
 return E_FILE_FORMAT_INVALID;

 signed char first_byte = 0;
 const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);

 if (status < 0)
 return status;

 unsigned long long result = first_byte;
 ++pos;

 for (long i = 1; i < size; ++i) {
 unsigned char b;

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

 if (status < 0)
 return status;

    result <<= 8;
    result |= b;

 ++pos;
 }

  result_ref = static_cast<long long>(result);
 return 0;
}

Project: Android

long UnserializeString(IMkvReader* pReader, long long pos, long long size,
 char*& str) {
 delete[] str;
  str = NULL;

 if (size >= LONG_MAX || size < 0)
 return E_FILE_FORMAT_INVALID;

 const long required_size = static_cast<long>(size) + 1;

  str = SafeArrayAlloc<char>(1, required_size);
 if (str == NULL)
 return E_FILE_FORMAT_INVALID;

 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[required_size - 1] = '\0';
 return 0;
}

Project: Android
File: mkvparser.cc

long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
 if (!pReader || pos < 0 || (size <= 0) || (size > 8))
 return E_FILE_FORMAT_INVALID;

 long long result = 0;

 for (long long i = 0; i < size; ++i) {
 unsigned char b;

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

 if (status < 0)
 return status;

    result <<= 8;
    result |= b;

 ++pos;
 }

 return result;
}

Project: Android

IMkvReader::~IMkvReader() {}

Project: Android
File: mkvparser.cc

Segment::~Segment() {
 const long count = m_clusterCount + m_clusterPreloadCount;

 Cluster** i = m_clusters;
 Cluster** j = m_clusters + count;

 while (i != j) {
 Cluster* const p = *i++;
 delete p;
 }

 delete[] m_clusters;

 delete m_pTracks;
 delete m_pInfo;
 delete m_pCues;
 delete m_pChapters;
 delete m_pTags;
 delete m_pSeekHead;
}

Project: Android
File: mkvparser.cc

Tags::SimpleTag::~SimpleTag() {}

Project: Android
File: mkvparser.cc

Tags::Tag::~Tag() {}

Project: Android
File: mkvparser.cc

Tags::~Tags() {
 while (m_tags_count > 0) {
 Tag& t = m_tags[--m_tags_count];
    t.Clear();
 }
 delete[] m_tags;
}