// File: 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:
subq $0x78, %rsp
movq %rdi, 0x68(%rsp)
movq %rsi, 0x60(%rsp)
movq %rdx, 0x58(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x60(%rsp), %rcx
movq (%rcx), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, (%rcx)
movb (%rax), %al
movb %al, 0x57(%rsp)
movzbl 0x57(%rsp), %edx
movq 0x60(%rsp), %rax
movq (%rax), %rcx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, (%rax)
movb $0x0, 0x56(%rsp)
movq 0x60(%rsp), %rax
movq (%rax), %rax
cmpq 0x58(%rsp), %rax
jae 0x3f84
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
cmpl $0xff, %eax
jne 0x38a5
testb $0x1, 0x56(%rsp)
jne 0x389b
movq 0x979d(%rip), %rdi      # 0xcff0
leaq 0x5a1c(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5b1d(%rip), %rsi      # 0x939a
callq 0x2140
movq %rax, %rdi
movq 0x9734(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movb $0x1, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rcx
movq (%rcx), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, (%rcx)
movb (%rax), %al
movb %al, 0x55(%rsp)
movzbl 0x55(%rsp), %eax
cmpl $0xff, %eax
jne 0x3929
testb $0x1, 0x56(%rsp)
jne 0x391f
movq 0x9719(%rip), %rdi      # 0xcff0
leaq 0x5998(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5ab0(%rip), %rsi      # 0x93b1
callq 0x2140
movq %rax, %rdi
movq 0x96b0(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movb $0x1, 0x77(%rsp)
jmp 0x3f8e
movzbl 0x55(%rsp), %eax
cmpl $0x2, %eax
je 0x39ab
movq 0x9696(%rip), %rdi      # 0xcfd0
leaq 0x5a93(%rip), %rsi      # 0x93d4
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5a80(%rip), %rsi      # 0x93e4
callq 0x2140
movq %rax, %rdi
movl $0x2, %esi
callq 0x2210
movq %rax, %rdi
leaq 0x5843(%rip), %rsi      # 0x91c3
callq 0x2140
movq %rax, %rdi
movzbl 0x55(%rsp), %esi
callq 0x21c0
movq %rax, %rdi
movq 0x9624(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x1, 0x77(%rsp)
jmp 0x3f8e
jmp 0x39ad
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0x80, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, 0x54(%rsp)
testb $0x1, 0x54(%rsp)
jne 0x3a1f
movq 0x9619(%rip), %rdi      # 0xcff0
leaq 0x5898(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x59f9(%rip), %rsi      # 0x93fa
callq 0x2140
movq %rax, %rdi
movq 0x95b0(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0x40, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, 0x53(%rsp)
testb $0x1, 0x53(%rsp)
je 0x3a8f
movq 0x95a9(%rip), %rdi      # 0xcff0
leaq 0x5828(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x59b0(%rip), %rsi      # 0x9421
callq 0x2140
movq %rax, %rdi
movq 0x9540(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0x30, %eax
sarl $0x4, %eax
cmpl $0x3, %eax
je 0x3af4
movq 0x9544(%rip), %rdi      # 0xcff0
leaq 0x57c3(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5964(%rip), %rsi      # 0x943a
callq 0x2140
movq %rax, %rdi
movq 0x94db(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
addq $0x1, %rax
cmpq 0x58(%rsp), %rax
jb 0x3b56
movq 0x94e2(%rip), %rdi      # 0xcff0
leaq 0x5761(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5922(%rip), %rsi      # 0x945a
callq 0x2140
movq %rax, %rdi
movq 0x9479(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0x3, %eax
shll $0xa, %eax
movzwl %ax, %eax
movq 0x60(%rsp), %rcx
movq (%rcx), %rcx
movzbl 0x1(%rcx), %ecx
movzwl %cx, %ecx
orl %ecx, %eax
movw %ax, 0x50(%rsp)
movq 0x60(%rsp), %rax
movq (%rax), %rcx
addq $0x2, %rcx
movq %rcx, (%rax)
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzwl 0x50(%rsp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
cmpq 0x58(%rsp), %rax
jb 0x3bf8
movq 0x9440(%rip), %rdi      # 0xcff0
leaq 0x56bf(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x589f(%rip), %rsi      # 0x9479
callq 0x2140
movq %rax, %rdi
movq 0x93d7(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x18(%rsp), %rdi
movq 0x60(%rsp), %rsi
movq 0x58(%rsp), %rdx
leaq 0x4a(%rsp), %rcx
callq 0x44a0
testb $0x1, %al
jne 0x3c1f
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x18(%rsp), %rdi
leaq 0x4a(%rsp), %rsi
callq 0x5810
movq %rax, 0x38(%rsp)
leaq 0x40(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x5840
movq 0x18(%rsp), %rdi
callq 0x5880
movq %rax, 0x28(%rsp)
leaq 0x30(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x5840
leaq 0x40(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x5860
testb $0x1, %al
jne 0x3c75
jmp 0x3cd1
movq 0x9374(%rip), %rdi      # 0xcff0
leaq 0x55f3(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x57ec(%rip), %rsi      # 0x9492
callq 0x2140
movq %rax, %rdi
movzwl 0x4a(%rsp), %esi
callq 0x2200
movq %rax, %rdi
movq 0x92fe(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0xe0, %eax
sarl $0x5, %eax
cmpl $0x7, %eax
je 0x3d38
movq 0x9300(%rip), %rdi      # 0xcff0
leaq 0x557f(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x579e(%rip), %rsi      # 0x94b8
callq 0x2140
movq %rax, %rdi
movq 0x9297(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
addq $0x1, %rax
cmpq 0x58(%rsp), %rax
jb 0x3d9a
movq 0x929e(%rip), %rdi      # 0xcff0
leaq 0x551d(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x56de(%rip), %rsi      # 0x945a
callq 0x2140
movq %rax, %rdi
movq 0x9235(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rcx
addq $0x2, %rcx
movq %rcx, (%rax)
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0xf0, %eax
sarl $0x4, %eax
cmpl $0xf, %eax
je 0x3e10
movq 0x9228(%rip), %rdi      # 0xcff0
leaq 0x54a7(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x56c6(%rip), %rsi      # 0x94b8
callq 0x2140
movq %rax, %rdi
movq 0x91bf(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
addq $0x1, %rax
cmpq 0x58(%rsp), %rax
jb 0x3e72
movq 0x91c6(%rip), %rdi      # 0xcff0
leaq 0x5445(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x5606(%rip), %rsi      # 0x945a
callq 0x2140
movq %rax, %rdi
movq 0x915d(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzbl (%rax), %eax
andl $0x3, %eax
shll $0x8, %eax
movzwl %ax, %eax
movq 0x60(%rsp), %rcx
movq (%rcx), %rcx
movzbl 0x1(%rcx), %ecx
movzwl %cx, %ecx
orl %ecx, %eax
movw %ax, 0x26(%rsp)
movq 0x60(%rsp), %rax
movq (%rax), %rcx
addq $0x2, %rcx
movq %rcx, (%rax)
movq 0x60(%rsp), %rax
movq (%rax), %rax
movzwl 0x26(%rsp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
cmpq 0x58(%rsp), %rax
jb 0x3f11
movq 0x9124(%rip), %rdi      # 0xcff0
leaq 0x53a3(%rip), %rsi      # 0x9276
callq 0x2140
movq %rax, %rdi
movq 0x18(%rsp), %rax
movq 0x90(%rax), %rsi
callq 0x2040
movq %rax, %rdi
leaq 0x55de(%rip), %rsi      # 0x94d4
callq 0x2140
movq %rax, %rdi
movq 0x90bb(%rip), %rsi      # 0xcfc0
callq 0x2180
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movzwl 0x26(%rsp), %edx
movq 0x60(%rsp), %rax
movq (%rax), %rcx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, (%rax)
movq 0x60(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x58(%rsp), %rax
movq %rax, 0x10(%rsp)
leaq 0x40(%rsp), %rdi
callq 0x58b0
movq 0x18(%rsp), %rdi
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %rax, %rcx
addq $0x2, %rcx
callq 0x4b40
testb $0x1, %al
jne 0x3f6b
movb $0x0, 0x77(%rsp)
jmp 0x3f8e
movq 0x60(%rsp), %rax
movq (%rax), %rcx
addq $0x4, %rcx
movq %rcx, (%rax)
movb $0x1, 0x56(%rsp)
jmp 0x3820
movb 0x56(%rsp), %al
andb $0x1, %al
movb %al, 0x77(%rsp)
movb 0x77(%rsp), %al
andb $0x1, %al
addq $0x78, %rsp
retq
nopl (%rax)