// File: qhan1028[P]JPEG-Decoder/jpeg-decoder.cpp
// Function: read_bits(std::basic_ifstream<char, std::char_traits<char>>&, buffer&, std::vector<unsigned short, std::allocator<unsigned short>>&, unsigned char, bool)
uint16_t read_bits(ifstream& jpegfile, buffer_t& b, vector<uint16_t>& prev_dc, uint8_t n_bits, bool is_symbol) {
    char c;

    if (n_bits > b.valid_bits) {

        do {
            jpegfile.read(&c, 1);
            uint8_t byte = to_uint(c);

            if (byte == TAG) {
                jpegfile.read(&c, 1);
                if (USE_RST) { // reset dc prev
                    switch (to_uint(c)) {
                        case 0xD0: case 0xD1: case 0xD2: case 0xD3:
                        case 0xD4: case 0xD5: case 0xD6: case 0xD7:
                            for (int i = 0; i < prev_dc.size(); i++) prev_dc[i] = 0;
                            break;
                        default:;
                    }
                }
            }

            b.bits = b.bits | (to_uint(byte) << (24 - b.valid_bits));
            b.valid_bits += 8;

            //cout << b.bits << ", n_bits: " << (int)n_bits << ", valid_bits: " << (int)b.valid_bits << endl;

        } while (n_bits > b.valid_bits);
    }

    uint16_t output = 0;

    if (is_symbol) {
        output = ((b.bits >> (31)) & ((1 << 1) - 1));

        b.valid_bits -= 1;
        b.bits = b.bits << 1;

    } else {
        if(((b.bits >> (32 - 1)) & ((1 << 1) - 1)) == 0){
            output = ((b.bits >> (32 - n_bits)) | ((-1) << n_bits));
            output += 1; //why?

        } else {
            output = ((b.bits >> (32 - n_bits)) & ((1 << n_bits) - 1));
        }
        
        b.valid_bits -= n_bits;
        b.bits = b.bits << n_bits;  

        // cout << "msb: " << (int)(b.bits >> (31)) << ", shift: " << (int)((b.bits >> (31)) & ((1 << 1) - 1)) << ", output: " << (int16_t)output << endl;
    }
    
    return output;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movb %cl, -0x19(%rbp)
andb $0x1, %al
movb %al, -0x1a(%rbp)
movzbl -0x19(%rbp), %eax
movq -0x10(%rbp), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jle 0x2676
jmp 0x2584
movq -0x8(%rbp), %rdi
leaq -0x1b(%rbp), %rsi
movl $0x1, %edx
callq 0x2230
movsbl -0x1b(%rbp), %edi
callq 0x6210
movb %al, -0x1c(%rbp)
movzbl -0x1c(%rbp), %eax
cmpl $0xff, %eax
jne 0x2626
movq -0x8(%rbp), %rdi
leaq -0x1b(%rbp), %rsi
movl $0x1, %edx
callq 0x2230
testb $0x1, 0xdc55(%rip)      # 0x1021b
je 0x2624
movsbl -0x1b(%rbp), %edi
callq 0x6210
addl $0xffffff30, %eax       # imm = 0xFFFFFF30
subl $0x7, %eax
ja 0x2620
jmp 0x25dd
movl $0x0, -0x20(%rbp)
movslq -0x20(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x6220
movq %rax, %rcx
movq -0x30(%rbp), %rax
cmpq %rcx, %rax
jae 0x261e
movq -0x18(%rbp), %rdi
movslq -0x20(%rbp), %rsi
callq 0x6240
movw $0x0, (%rax)
movl -0x20(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20(%rbp)
jmp 0x25e4
jmp 0x2622
jmp 0x2622
jmp 0x2624
jmp 0x2626
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x34(%rbp)
movsbl -0x1c(%rbp), %edi
callq 0x6210
movq -0x10(%rbp), %rcx
movzbl (%rcx), %edx
movl $0x18, %ecx
subl %edx, %ecx
shll %cl, %eax
movl -0x34(%rbp), %ecx
orl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x10(%rbp), %rax
movzbl (%rax), %ecx
addl $0x8, %ecx
movb %cl, (%rax)
movzbl -0x19(%rbp), %eax
movq -0x10(%rbp), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jg 0x2584
jmp 0x2676
movw $0x0, -0x22(%rbp)
testb $0x1, -0x1a(%rbp)
je 0x26b4
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
shrl $0x1f, %eax
andl $0x1, %eax
movw %ax, -0x22(%rbp)
movq -0x10(%rbp), %rax
movzbl (%rax), %ecx
subl $0x1, %ecx
movb %cl, (%rax)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %ecx
shll %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x4(%rax)
jmp 0x2749
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
shrl $0x1f, %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x26fa
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movzbl -0x19(%rbp), %edx
movl $0x20, %ecx
subl %edx, %ecx
shrl %cl, %eax
movzbl -0x19(%rbp), %ecx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
shll %cl, %edx
movl %edx, %ecx
orl %ecx, %eax
movw %ax, -0x22(%rbp)
movzwl -0x22(%rbp), %eax
addl $0x1, %eax
movw %ax, -0x22(%rbp)
jmp 0x2724
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movzbl -0x19(%rbp), %edx
movl $0x20, %ecx
subl %edx, %ecx
shrl %cl, %eax
movzbl -0x19(%rbp), %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
subl $0x1, %ecx
andl %ecx, %eax
movw %ax, -0x22(%rbp)
movzbl -0x19(%rbp), %edx
movq -0x10(%rbp), %rax
movzbl (%rax), %ecx
subl %edx, %ecx
movb %cl, (%rax)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movzbl -0x19(%rbp), %ecx
shll %cl, %eax
movl %eax, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x4(%rax)
movw -0x22(%rbp), %ax
addq $0x40, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)