// File: dannye[P]jed/src/decoder.cpp
// Function: readStartOfFrame(BitReader&, JPGImage*)
void readStartOfFrame(BitReader& bitReader, JPGImage* const image) {
    std::cout << "Reading SOF Marker\n";
    if (image->numComponents != 0) {
        std::cout << "Error - Multiple SOFs detected\n";
        image->valid = false;
        return;
    }

    uint length = bitReader.readWord();

    byte precision = bitReader.readByte();
    if (precision != 8) {
        std::cout << "Error - Invalid precision: " << (uint)precision << '\n';
        image->valid = false;
        return;
    }

    image->height = bitReader.readWord();
    image->width = bitReader.readWord();
    if (image->height == 0 || image->width == 0) {
        std::cout << "Error - Invalid dimensions\n";
        image->valid = false;
        return;
    }
    image->blockHeight = (image->height + 7) / 8;
    image->blockWidth = (image->width + 7) / 8;
    image->blockHeightReal = image->blockHeight;
    image->blockWidthReal = image->blockWidth;

    image->numComponents = bitReader.readByte();
    if (image->numComponents == 4) {
        std::cout << "Error - CMYK color mode not supported\n";
        image->valid = false;
        return;
    }
    if (image->numComponents != 1 && image->numComponents != 3) {
        std::cout << "Error - " << (uint)image->numComponents << " color components given (1 or 3 required)\n";
        image->valid = false;
        return;
    }
    for (uint i = 0; i < image->numComponents; ++i) {
        byte componentID = bitReader.readByte();
        // component IDs are usually 1, 2, 3 but rarely can be seen as 0, 1, 2
        // always force them into 1, 2, 3 for consistency
        if (componentID == 0 && i == 0) {
            image->zeroBased = true;
        }
        if (image->zeroBased) {
            componentID += 1;
        }
        if (componentID == 0 || componentID > image->numComponents) {
            std::cout << "Error - Invalid component ID: " << (uint)componentID << '\n';
            image->valid = false;
            return;
        }
        ColorComponent& component = image->colorComponents[componentID - 1];
        if (component.usedInFrame) {
            std::cout << "Error - Duplicate color component ID: " << (uint)componentID << '\n';
            image->valid = false;
            return;
        }
        component.usedInFrame = true;

        byte samplingFactor = bitReader.readByte();
        component.horizontalSamplingFactor = samplingFactor >> 4;
        component.verticalSamplingFactor = samplingFactor & 0x0F;
        if (componentID == 1) {
            if ((component.horizontalSamplingFactor != 1 && component.horizontalSamplingFactor != 2) ||
                (component.verticalSamplingFactor != 1 && component.verticalSamplingFactor != 2)) {
                std::cout << "Error - Sampling factors not supported\n";
                image->valid = false;
                return;
            }
            if (component.horizontalSamplingFactor == 2 && image->blockWidth % 2 == 1) {
                image->blockWidthReal += 1;
            }
            if (component.verticalSamplingFactor == 2 && image->blockHeight % 2 == 1) {
                image->blockHeightReal += 1;
            }
            image->horizontalSamplingFactor = component.horizontalSamplingFactor;
            image->verticalSamplingFactor = component.verticalSamplingFactor;
        }
        else {
            if (component.horizontalSamplingFactor != 1 || component.verticalSamplingFactor != 1) {
                std::cout << "Error - Sampling factors not supported\n";
                image->valid = false;
                return;
            }
        }

        component.quantizationTableID = bitReader.readByte();
        if (component.quantizationTableID > 3) {
            std::cout << "Error - Invalid quantization table ID: " << (uint)component.quantizationTableID << '\n';
            image->valid = false;
            return;
        }
    }

    if (length - 8 - (3 * image->numComponents) != 0) {
        std::cout << "Error - SOF invalid\n";
        image->valid = false;
        return;
    }
}

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x30(%rsp)
movq %rsi, 0x28(%rsp)
movq 0x9923(%rip), %rdi      # 0xbfd8
leaq 0x69a4(%rip), %rsi      # 0x9060
callq 0x2110
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %eax
cmpl $0x0, %eax
je 0x26f6
movq 0x98ff(%rip), %rdi      # 0xbfd8
leaq 0x6994(%rip), %rsi      # 0x9074
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x30(%rsp), %rdi
callq 0x7a40
movl %eax, 0x24(%rsp)
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, 0x23(%rsp)
movzbl 0x23(%rsp), %eax
cmpl $0x8, %eax
je 0x275a
movq 0x98b5(%rip), %rdi      # 0xbfd8
leaq 0x696a(%rip), %rsi      # 0x9094
callq 0x2110
movq %rax, %rdi
movzbl 0x23(%rsp), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x30(%rsp), %rdi
callq 0x7a40
movl %eax, %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x2068(%rax)
movq 0x30(%rsp), %rdi
callq 0x7a40
movl %eax, %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x206c(%rax)
movq 0x28(%rsp), %rax
cmpl $0x0, 0x2068(%rax)
je 0x27a4
movq 0x28(%rsp), %rax
cmpl $0x0, 0x206c(%rax)
jne 0x27c8
movq 0x982d(%rip), %rdi      # 0xbfd8
leaq 0x68fe(%rip), %rsi      # 0x90b0
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x28(%rsp), %rax
movl 0x2068(%rax), %ecx
addl $0x7, %ecx
shrl $0x3, %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x208c(%rax)
movq 0x28(%rsp), %rax
movl 0x206c(%rax), %ecx
addl $0x7, %ecx
shrl $0x3, %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x2090(%rax)
movq 0x28(%rsp), %rax
movl 0x208c(%rax), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x2094(%rax)
movq 0x28(%rsp), %rax
movl 0x2090(%rax), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x2098(%rax)
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2070(%rax)
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %eax
cmpl $0x4, %eax
jne 0x2878
movq 0x977d(%rip), %rdi      # 0xbfd8
leaq 0x686a(%rip), %rsi      # 0x90cc
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %eax
cmpl $0x1, %eax
je 0x28e1
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %eax
cmpl $0x3, %eax
je 0x28e1
movq 0x9737(%rip), %rdi      # 0xbfd8
leaq 0x684b(%rip), %rsi      # 0x90f3
callq 0x2110
movq %rax, %rdi
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %esi
callq 0x21b0
movq %rax, %rdi
leaq 0x6831(%rip), %rsi      # 0x90fc
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
cmpl %ecx, %eax
jae 0x2bf4
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, 0x1b(%rsp)
movzbl 0x1b(%rsp), %eax
cmpl $0x0, %eax
jne 0x292c
cmpl $0x0, 0x1c(%rsp)
jne 0x292c
movq 0x28(%rsp), %rax
movb $0x1, 0x2071(%rax)
movq 0x28(%rsp), %rax
testb $0x1, 0x2071(%rax)
je 0x2946
movzbl 0x1b(%rsp), %eax
addl $0x1, %eax
movb %al, 0x1b(%rsp)
movzbl 0x1b(%rsp), %eax
cmpl $0x0, %eax
je 0x2965
movzbl 0x1b(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
cmpl %ecx, %eax
jle 0x29a3
movq 0x966c(%rip), %rdi      # 0xbfd8
leaq 0x67b4(%rip), %rsi      # 0x9127
callq 0x2110
movq %rax, %rdi
movzbl 0x1b(%rsp), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x28(%rsp), %rax
addq $0x2050, %rax           # imm = 0x2050
movzbl 0x1b(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
imulq $0x7, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
testb $0x1, 0x5(%rax)
je 0x2a0e
movq 0x9601(%rip), %rdi      # 0xbfd8
leaq 0x6768(%rip), %rsi      # 0x9146
callq 0x2110
movq %rax, %rdi
movzbl 0x1b(%rsp), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x10(%rsp), %rax
movb $0x1, 0x5(%rax)
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, 0xf(%rsp)
movzbl 0xf(%rsp), %eax
sarl $0x4, %eax
movb %al, %cl
movq 0x10(%rsp), %rax
movb %cl, (%rax)
movzbl 0xf(%rsp), %eax
andl $0xf, %eax
movb %al, %cl
movq 0x10(%rsp), %rax
movb %cl, 0x1(%rax)
movzbl 0x1b(%rsp), %eax
cmpl $0x1, %eax
jne 0x2b40
movq 0x10(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x1, %eax
je 0x2a70
movq 0x10(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x2, %eax
jne 0x2a8c
movq 0x10(%rsp), %rax
movzbl 0x1(%rax), %eax
cmpl $0x1, %eax
je 0x2ab0
movq 0x10(%rsp), %rax
movzbl 0x1(%rax), %eax
cmpl $0x2, %eax
je 0x2ab0
movq 0x9545(%rip), %rdi      # 0xbfd8
leaq 0x66d3(%rip), %rsi      # 0x916d
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
movq 0x10(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x2, %eax
jne 0x2ae4
movq 0x28(%rsp), %rax
movl 0x2090(%rax), %eax
andl $0x1, %eax
cmpl $0x1, %eax
jne 0x2ae4
movq 0x28(%rsp), %rax
movl 0x2098(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x2098(%rax)
movq 0x10(%rsp), %rax
movzbl 0x1(%rax), %eax
cmpl $0x2, %eax
jne 0x2b19
movq 0x28(%rsp), %rax
movl 0x208c(%rax), %eax
andl $0x1, %eax
cmpl $0x1, %eax
jne 0x2b19
movq 0x28(%rsp), %rax
movl 0x2094(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x2094(%rax)
movq 0x10(%rsp), %rax
movb (%rax), %cl
movq 0x28(%rsp), %rax
movb %cl, 0x209c(%rax)
movq 0x10(%rsp), %rax
movb 0x1(%rax), %cl
movq 0x28(%rsp), %rax
movb %cl, 0x209d(%rax)
jmp 0x2b81
movq 0x10(%rsp), %rax
movzbl (%rax), %eax
cmpl $0x1, %eax
jne 0x2b5b
movq 0x10(%rsp), %rax
movzbl 0x1(%rax), %eax
cmpl $0x1, %eax
je 0x2b7f
movq 0x9476(%rip), %rdi      # 0xbfd8
leaq 0x6604(%rip), %rsi      # 0x916d
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
jmp 0x2b81
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, %cl
movq 0x10(%rsp), %rax
movb %cl, 0x2(%rax)
movq 0x10(%rsp), %rax
movzbl 0x2(%rax), %eax
cmpl $0x3, %eax
jle 0x2be2
movq 0x942e(%rip), %rdi      # 0xbfd8
leaq 0x65e4(%rip), %rsi      # 0x9195
callq 0x2110
movq %rax, %rdi
movq 0x10(%rsp), %rax
movzbl 0x2(%rax), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x2c30
jmp 0x2be4
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x28e9
movl 0x24(%rsp), %eax
subl $0x8, %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
imull $0x3, %ecx, %ecx
subl %ecx, %eax
cmpl $0x0, %eax
je 0x2c30
movq 0x93c0(%rip), %rdi      # 0xbfd8
leaq 0x659e(%rip), %rsi      # 0x91bd
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
addq $0x38, %rsp
retq
nopw %cs:(%rax,%rax)