// File: /workspace/github_cpp_makefile_star2_O1/mmoanis[P]mpegts_demux/MpegTsDemux.cpp
// Function: MpegTsDemuxer::ReadPMT(unsigned char const*&, unsigned char const*)
bool MpegTsDemuxer::ReadPMT(Packet::const_iterator &p, Packet::const_iterator e)
{
    /// FIXME: Similar to ReadPAT, can it be grouped together.

    const uint8_t pointer = *p++;
    p += pointer; // Jump to table at pointer offset

    bool done = false;

    // Tables can be repeated.
    while (p < e) {
        if (p[0] == MPEGTS_STUFFING_BYTE) {
            if (!done) {
                cerr << "[ERROR]: PKT#" << m_pnum << " No data in PMT table." << endl;
                return false;
            }
            return true;
        }
        const uint8_t id = *p++;
        if (id == MPEGTS_TABLE_NIL) {
            if (!done) {
                cerr << "[ERROR]: PKT#" << m_pnum <<" PMT packet has no associated PSI." << endl;
                return false;
            }
            return true;
        } else if (id != MPEGTS_TABLE_PMS) {
            // can happen! Just ignore.
            cout << "[WARNING]: PKT#" << m_pnum << "Expected PMT SECTION=" << MPEGTS_TABLE_PMS << " found " << id << endl;
            return true;
        }

        const bool ssi = static_cast<bool> (*p&0x80); // PAT/PMT/CAT == 1
        if (!ssi) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT section syntax indicator not set." << endl;
            return false;
        }

        const bool pb = static_cast<bool> (*p&0x40); // PAT/PMT/CAT == 0
        if (pb) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT private bit is set." << endl;
            return false;
        }

        if (((*p&0x30)>>4) != 0x03 ) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT PSI reserved bits not set." << endl;
            return false;
        }

        if (p + 1 >= e) {
            cerr << "[ERROR]: PKT#" << m_pnum << " Not enough data in PMT table." << endl;
            return false;
        }
        const uint16_t slength = uint16_t((p[0]&0x03)<<10) | uint16_t(p[1]);
        p += 2;
        if (p + slength >= e) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT bad section length." << endl;
            return false;
        }

        PacketSection section;
        if (!ReadSection(p, e, section))
            return false;

        // Get the program this PMT referring to
        Programs::const_iterator prog = m_programs.find(section.id);
        if (prog == m_programs.end()) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT references non existing PROGRAM=" << section.id << endl;
            return false;
        }

        if (((*p&0xE0)>>5) != 0x07) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT reserved bits not set." << endl;
            return false;
        }

        if (p + 1 >= e) {
            cerr << "[ERROR]: PKT#" << m_pnum << " Not enough data in PMT table." << endl;
            return false;
        }
        //PID pcrid = uint16_t((p[0]&0x1F)<<8) | uint16_t(p[1]); // clock frequency
        p += 2;

        // expect PES packet with clock frequency
        //m_filters.insert(make_pair(pcrid, DEMUXER_EVENT_PCR));

        if (((*p&0xF0)>>4) != 0x0F) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT reserved bits not set." << endl;
            return false;
        }

        // program descriptors
        if (p + 1 >= e) {
            cerr << "[ERROR]: PKT#" << m_pnum << " Not enough data in PMT table." << endl;
            return false;
        }
        const uint16_t pinfol = uint16_t((p[0]&0x03)<<8) | uint16_t(p[1]);
        p += 2;

        if (p + pinfol >= e) {
            cerr << "[ERROR]: PKT#" << m_pnum <<" PMT bad program info length." << endl;
            return false;
        }
        p += pinfol;

        // read data stream info
        if (!ReadESD(p, e, (*prog).second))
            return false;

        // End of the section
        //uint32_t crc = uint32_t(p[0]<<24) | uint32_t(p[1]<<16) | uint32_t(p[2]<<8) | uint32_t(p[3]);
        p += 4;
        //cout << "CRC: " << hex << crc << dec << endl;
        done = true;
    }

    return done;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %rbx
movq (%rsi), %rax
leaq 0x1(%rax), %rcx
movq %rcx, (%rsi)
movzbl (%rax), %ecx
leaq 0x1(%rax,%rcx), %rax
movq %rax, (%rsi)
leaq 0x8(%rdi), %rax
movq %rax, 0x10(%rsp)
movl $0x0, 0x4(%rsp)
movq 0x4dc0(%rip), %r12      # 0x7ff0
movq (%r15), %rax
cmpq %r14, %rax
jae 0x3704
cmpb $-0x1, (%rax)
je 0x370b
leaq 0x1(%rax), %rcx
movq %rcx, (%r15)
movzbl (%rax), %ebp
cmpl $0x2, %ebp
je 0x32a5
cmpl $0xff, %ebp
jne 0x32ea
testb $0x1, 0x4(%rsp)
jne 0x3390
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1ffc(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x22, %edx
movq %rax, %rdi
leaq 0x20ee(%rip), %rsi      # 0x538e
jmp 0x35bb
movzbl (%rcx), %ecx
testb %cl, %cl
js 0x339a
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1fb7(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x26, %edx
movq %rax, %rdi
leaq 0x20f2(%rip), %rsi      # 0x53d7
jmp 0x35bb
movl $0xf, %edx
movq 0x4cda(%rip), %r13      # 0x7fd0
movq %r13, %rdi
leaq 0x20b1(%rip), %rsi      # 0x53b1
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r13, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x15, %edx
movq %rax, %rdi
leaq 0x209b(%rip), %rsi      # 0x53c1
callq 0x2170
movq %r13, %rdi
movl $0x2, %esi
callq 0x21f0
movq %rax, %r13
movl $0x7, %edx
movq %rax, %rdi
leaq 0x1e79(%rip), %rsi      # 0x51c3
callq 0x2170
movb %bpl, 0x3(%rsp)
movl $0x1, %edx
movq %r13, %rdi
leaq 0x3(%rsp), %rsi
callq 0x2170
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2130
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movb $0x1, %r13b
xorl %eax, %eax
jmp 0x35ed
testb $0x40, %cl
jne 0x34de
movl %ecx, %edx
notl %edx
testb $0x30, %dl
jne 0x3518
leaq 0x2(%rax), %rdx
cmpq %r14, %rdx
jae 0x354f
andl $0x3, %ecx
shll $0xa, %ecx
movzbl 0x2(%rax), %edx
orq %rcx, %rdx
leaq 0x3(%rax), %rcx
movq %rcx, (%r15)
addq %rdx, %rax
addq $0x3, %rax
cmpq %r14, %rax
jae 0x3586
movq %rbx, %rdi
movq %r15, %rsi
movq %r14, %rdx
leaq 0xa(%rsp), %rcx
callq 0x3b1e
testb %al, %al
je 0x35e8
movq 0x10(%rbx), %rcx
movq 0x10(%rsp), %rdi
movq %rdi, %rax
testq %rcx, %rcx
je 0x342d
movzwl 0xa(%rsp), %edx
movq %rdi, %rax
xorl %esi, %esi
cmpw %dx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x3415
movq %rdi, %rcx
cmpq %rdi, %rax
je 0x3445
movzwl 0xa(%rsp), %ecx
cmpw 0x20(%rax), %cx
cmovbq %rdi, %rax
movq %rax, %rcx
cmpq %rdi, %rcx
je 0x3634
movq (%r15), %rax
cmpb $-0x21, (%rax)
jbe 0x35fa
leaq 0x1(%rax), %rdx
cmpq %r14, %rdx
jae 0x3686
leaq 0x2(%rax), %rdx
movq %rdx, (%r15)
movzbl 0x2(%rax), %edx
cmpq $0xef, %rdx
jbe 0x35fa
leaq 0x3(%rax), %rsi
cmpq %r14, %rsi
jae 0x3686
andl $0x3, %edx
shll $0x8, %edx
movzbl 0x3(%rax), %esi
orq %rdx, %rsi
leaq 0x4(%rax), %rdx
movq %rdx, (%r15)
addq %rsi, %rax
addq $0x4, %rax
cmpq %r14, %rax
jae 0x36cd
movq %rax, (%r15)
addq $0x22, %rcx
movq %rbx, %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x4006
testb %al, %al
je 0x35e8
addq $0x4, (%r15)
movb $0x1, %al
movb $0x1, %cl
movl %ecx, 0x4(%rsp)
jmp 0x35ed
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1d89(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x18, %edx
movq %rax, %rdi
leaq 0x1eeb(%rip), %rsi      # 0x53fe
jmp 0x35bb
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1d4f(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x1f, %edx
movq %rax, %rdi
leaq 0x1eca(%rip), %rsi      # 0x5417
jmp 0x35bb
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1d18(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x1e, %edx
movq %rax, %rdi
leaq 0x1eb3(%rip), %rsi      # 0x5437
jmp 0x35bb
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1ce1(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x18, %edx
movq %rax, %rdi
leaq 0x1e9b(%rip), %rsi      # 0x5456
callq 0x2170
movq (%r13), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2130
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
xorl %eax, %eax
xorl %r13d, %r13d
testb %al, %al
jne 0x3230
jmp 0x3780
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1c6d(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x1b, %edx
movq %rax, %rdi
leaq 0x1e66(%rip), %rsi      # 0x5495
jmp 0x36bb
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1c33(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x25, %edx
movq %rax, %rdi
leaq 0x1e06(%rip), %rsi      # 0x546f
callq 0x2170
movzwl 0xa(%rsp), %esi
movq %r13, %rdi
callq 0x20c0
movq %rax, %r13
movq (%rax), %rax
jmp 0x35c4
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1be1(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x1e, %edx
movq %rax, %rdi
leaq 0x1d7c(%rip), %rsi      # 0x5437
callq 0x2170
movq %r13, %rdi
callq 0x20a0
jmp 0x35e8
movl $0xd, %edx
movq %r12, %rdi
leaq 0x1b9a(%rip), %rsi      # 0x5276
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r12, %rdi
callq 0x20c0
movq %rax, %r13
movl $0x1d, %edx
movq %rax, %rdi
leaq 0x1daf(%rip), %rsi      # 0x54b1
jmp 0x36bb
movl 0x4(%rsp), %r13d
jmp 0x3780
movb $0x1, %r13b
testb $0x1, 0x4(%rsp)
jne 0x3780
movq 0x48d4(%rip), %r14      # 0x7ff0
leaq 0x1b53(%rip), %rsi      # 0x5276
movl $0xd, %edx
movq %r14, %rdi
callq 0x2170
movq 0x90(%rbx), %rsi
movq %r14, %rdi
callq 0x20c0
movq %rax, %rbx
leaq 0x1c2e(%rip), %rsi      # 0x5377
movl $0x16, %edx
movq %rax, %rdi
callq 0x2170
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2130
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
xorl %r13d, %r13d
andb $0x1, %r13b
movl %r13d, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq