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

    uint length = bitReader.readWord();

    for (uint i = 0; i < image->numComponents; ++i) {
        image->colorComponents[i].usedInScan = false;
    }

    // the number of components in the next scan might not be all
    //   components in the image
    image->componentsInScan = bitReader.readByte();
    if (image->componentsInScan == 0) {
        std::cout << "Error - Scan must include at least 1 component\n";
        image->valid = false;
        return;
    }
    for (uint i = 0; i < image->componentsInScan; ++i) {
        byte componentID = bitReader.readByte();
        // component IDs are usually 1, 2, 3 but rarely can be seen as 0, 1, 2
        if (image->zeroBased) {
            componentID += 1;
        }
        if (componentID == 0 || componentID > image->numComponents) {
            std::cout << "Error - Invalid color component ID: " << (uint)componentID << '\n';
            image->valid = false;
            return;
        }
        ColorComponent& component = image->colorComponents[componentID - 1];
        if (!component.usedInFrame) {
            std::cout << "Error - Invalid color component ID: " << (uint)componentID << '\n';
            image->valid = false;
            return;
        }
        if (component.usedInScan) {
            std::cout << "Error - Duplicate color component ID: " << (uint)componentID << '\n';
            image->valid = false;
            return;
        }
        component.usedInScan = true;

        byte huffmanTableIDs = bitReader.readByte();
        component.huffmanDCTableID = huffmanTableIDs >> 4;
        component.huffmanACTableID = huffmanTableIDs & 0x0F;
        if (component.huffmanDCTableID > 3) {
            std::cout << "Error - Invalid Huffman DC table ID: " << (uint)component.huffmanDCTableID << '\n';
            image->valid = false;
            return;
        }
        if (component.huffmanACTableID > 3) {
            std::cout << "Error - Invalid Huffman AC table ID: " << (uint)component.huffmanACTableID << '\n';
            image->valid = false;
            return;
        }
    }

    image->startOfSelection = bitReader.readByte();
    image->endOfSelection = bitReader.readByte();
    byte successiveApproximation = bitReader.readByte();
    image->successiveApproximationHigh = successiveApproximation >> 4;
    image->successiveApproximationLow = successiveApproximation & 0x0F;

    if (image->frameType == SOF0) {
        // Baseline JPGs don't use spectral selection or successive approximtion
        if (image->startOfSelection != 0 || image->endOfSelection != 63) {
            std::cout << "Error - Invalid spectral selection\n";
            image->valid = false;
            return;
        }
        if (image->successiveApproximationHigh != 0 || image->successiveApproximationLow != 0) {
            std::cout << "Error - Invalid successive approximation\n";
            image->valid = false;
            return;
        }
    }
    else if (image->frameType == SOF2) {
        if (image->startOfSelection > image->endOfSelection) {
            std::cout << "Error - Invalid spectral selection (start greater than end)\n";
            image->valid = false;
            return;
        }
        if (image->endOfSelection > 63) {
            std::cout << "Error - Invalid spectral selection (end greater than 63)\n";
            image->valid = false;
            return;
        }
        if (image->startOfSelection == 0 && image->endOfSelection != 0) {
            std::cout << "Error - Invalid spectral selection (contains DC and AC)\n";
            image->valid = false;
            return;
        }
        if (image->startOfSelection != 0 && image->componentsInScan != 1) {
            std::cout << "Error - Invalid spectral selection (AC scan contains multiple components)\n";
            image->valid = false;
            return;
        }
        if (image->successiveApproximationHigh != 0 &&
            image->successiveApproximationLow != image->successiveApproximationHigh - 1) {
            std::cout << "Error - Invalid successive approximation\n";
            image->valid = false;
            return;
        }
    }

    for (uint i = 0; i < image->numComponents; ++i) {
        const ColorComponent& component = image->colorComponents[i];
        if (image->colorComponents[i].usedInScan) {
            if (image->quantizationTables[component.quantizationTableID].set == false) {
                std::cout << "Error - Color component using uninitialized quantization table\n";
                image->valid = false;
                return;
            }
            if (image->startOfSelection == 0) {
                if (image->huffmanDCTables[component.huffmanDCTableID].set == false) {
                    std::cout << "Error - Color component using uninitialized Huffman DC table\n";
                    image->valid = false;
                    return;
                }
            }
            if (image->endOfSelection > 0) {
                if (image->huffmanACTables[component.huffmanACTableID].set == false) {
                    std::cout << "Error - Color component using uninitialized Huffman AC table\n";
                    image->valid = false;
                    return;
                }
            }
        }
    }

    if (length - 6 - (2 * image->componentsInScan) != 0) {
        std::cout << "Error - SOS invalid\n";
        image->valid = false;
        return;
    }
}

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x30(%rsp)
movq %rsi, 0x28(%rsp)
movq 0x8f13(%rip), %rdi      # 0xbfd8
leaq 0x61a7(%rip), %rsi      # 0x9273
callq 0x2110
movq 0x28(%rsp), %rax
movzbl 0x2070(%rax), %eax
cmpl $0x0, %eax
jne 0x3106
movq 0x8eef(%rip), %rdi      # 0xbfd8
leaq 0x6197(%rip), %rsi      # 0x9287
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x30(%rsp), %rdi
callq 0x7a40
movl %eax, 0x24(%rsp)
movl $0x0, 0x20(%rsp)
movl 0x20(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
cmpl %ecx, %eax
jae 0x3157
movq 0x28(%rsp), %rax
addq $0x2050, %rax           # imm = 0x2050
movl 0x20(%rsp), %ecx
imulq $0x7, %rcx, %rcx
addq %rcx, %rax
movb $0x0, 0x6(%rax)
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x311c
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2072(%rax)
movq 0x28(%rsp), %rax
movzbl 0x2072(%rax), %eax
cmpl $0x0, %eax
jne 0x31a3
movq 0x8e52(%rip), %rdi      # 0xbfd8
leaq 0x611b(%rip), %rsi      # 0x92a8
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2072(%rcx), %ecx
cmpl %ecx, %eax
jae 0x33e9
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, 0x1b(%rsp)
movq 0x28(%rsp), %rax
testb $0x1, 0x2071(%rax)
je 0x31eb
movzbl 0x1b(%rsp), %eax
addl $0x1, %eax
movb %al, 0x1b(%rsp)
movzbl 0x1b(%rsp), %eax
cmpl $0x0, %eax
je 0x320a
movzbl 0x1b(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
cmpl %ecx, %eax
jle 0x3248
movq 0x8dc7(%rip), %rdi      # 0xbfd8
leaq 0x60c0(%rip), %rsi      # 0x92d8
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 0x3820
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)
jne 0x32b3
movq 0x8d5c(%rip), %rdi      # 0xbfd8
leaq 0x6055(%rip), %rsi      # 0x92d8
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 0x3820
movq 0x10(%rsp), %rax
testb $0x1, 0x6(%rax)
je 0x32fc
movq 0x8d13(%rip), %rdi      # 0xbfd8
leaq 0x5e7a(%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 0x3820
movq 0x10(%rsp), %rax
movb $0x1, 0x6(%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, 0x3(%rax)
movzbl 0xf(%rsp), %eax
andl $0xf, %eax
movb %al, %cl
movq 0x10(%rsp), %rax
movb %cl, 0x4(%rax)
movq 0x10(%rsp), %rax
movzbl 0x3(%rax), %eax
cmpl $0x3, %eax
jle 0x3387
movq 0x8c8c(%rip), %rdi      # 0xbfd8
leaq 0x5faa(%rip), %rsi      # 0x92fd
callq 0x2110
movq %rax, %rdi
movq 0x10(%rsp), %rax
movzbl 0x3(%rax), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x10(%rsp), %rax
movzbl 0x4(%rax), %eax
cmpl $0x3, %eax
jle 0x33d7
movq 0x8c3c(%rip), %rdi      # 0xbfd8
leaq 0x5f80(%rip), %rsi      # 0x9323
callq 0x2110
movq %rax, %rdi
movq 0x10(%rsp), %rax
movzbl 0x4(%rax), %esi
callq 0x21b0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2160
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
jmp 0x33d9
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x31ab
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2073(%rax)
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2074(%rax)
movq 0x30(%rsp), %rdi
callq 0x7a80
movb %al, 0xe(%rsp)
movzbl 0xe(%rsp), %eax
sarl $0x4, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2075(%rax)
movzbl 0xe(%rsp), %eax
andl $0xf, %eax
movb %al, %cl
movq 0x28(%rsp), %rax
movb %cl, 0x2076(%rax)
movq 0x28(%rsp), %rax
movzbl 0x2065(%rax), %eax
cmpl $0xc0, %eax
jne 0x34f7
movq 0x28(%rsp), %rax
movzbl 0x2073(%rax), %eax
cmpl $0x0, %eax
jne 0x3488
movq 0x28(%rsp), %rax
movzbl 0x2074(%rax), %eax
cmpl $0x3f, %eax
je 0x34ac
movq 0x8b49(%rip), %rdi      # 0xbfd8
leaq 0x5eb3(%rip), %rsi      # 0x9349
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2075(%rax), %eax
cmpl $0x0, %eax
jne 0x34ce
movq 0x28(%rsp), %rax
movzbl 0x2076(%rax), %eax
cmpl $0x0, %eax
je 0x34f2
movq 0x8b03(%rip), %rdi      # 0xbfd8
leaq 0x5e91(%rip), %rsi      # 0x936d
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
jmp 0x3667
movq 0x28(%rsp), %rax
movzbl 0x2065(%rax), %eax
cmpl $0xc2, %eax
jne 0x3665
movq 0x28(%rsp), %rax
movzbl 0x2073(%rax), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2074(%rcx), %ecx
cmpl %ecx, %eax
jle 0x354e
movq 0x8aa7(%rip), %rdi      # 0xbfd8
leaq 0x5e5f(%rip), %rsi      # 0x9397
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2074(%rax), %eax
cmpl $0x3f, %eax
jle 0x3583
movq 0x8a72(%rip), %rdi      # 0xbfd8
leaq 0x5e67(%rip), %rsi      # 0x93d4
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2073(%rax), %eax
cmpl $0x0, %eax
jne 0x35c9
movq 0x28(%rsp), %rax
movzbl 0x2074(%rax), %eax
cmpl $0x0, %eax
je 0x35c9
movq 0x8a2c(%rip), %rdi      # 0xbfd8
leaq 0x5e5b(%rip), %rsi      # 0x940e
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2073(%rax), %eax
cmpl $0x0, %eax
je 0x360f
movq 0x28(%rsp), %rax
movzbl 0x2072(%rax), %eax
cmpl $0x1, %eax
je 0x360f
movq 0x89e6(%rip), %rdi      # 0xbfd8
leaq 0x5e4e(%rip), %rsi      # 0x9447
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2075(%rax), %eax
cmpl $0x0, %eax
je 0x3663
movq 0x28(%rsp), %rax
movzbl 0x2076(%rax), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2075(%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
je 0x3663
movq 0x8992(%rip), %rdi      # 0xbfd8
leaq 0x5d20(%rip), %rsi      # 0x936d
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
jmp 0x3665
jmp 0x3667
movl $0x0, 0x8(%rsp)
movl 0x8(%rsp), %eax
movq 0x28(%rsp), %rcx
movzbl 0x2070(%rcx), %ecx
cmpl %ecx, %eax
jae 0x37e5
movq 0x28(%rsp), %rax
addq $0x2050, %rax           # imm = 0x2050
movl 0x8(%rsp), %ecx
imulq $0x7, %rcx, %rcx
addq %rcx, %rax
movq %rax, (%rsp)
movq 0x28(%rsp), %rax
addq $0x2050, %rax           # imm = 0x2050
movl 0x8(%rsp), %ecx
imulq $0x7, %rcx, %rcx
addq %rcx, %rax
testb $0x1, 0x6(%rax)
je 0x37d3
movq 0x28(%rsp), %rax
movq (%rsp), %rcx
movzbl 0x2(%rcx), %ecx
imulq $0x104, %rcx, %rcx      # imm = 0x104
addq %rcx, %rax
movb 0x100(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x370c
movq 0x88e9(%rip), %rdi      # 0xbfd8
leaq 0x5d9c(%rip), %rsi      # 0x9492
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
movq 0x28(%rsp), %rax
movzbl 0x2073(%rax), %eax
cmpl $0x0, %eax
jne 0x3770
movq 0x28(%rsp), %rax
addq $0x410, %rax            # imm = 0x410
movq (%rsp), %rcx
movzbl 0x3(%rcx), %ecx
imulq $0x388, %rcx, %rcx      # imm = 0x388
addq %rcx, %rax
movb 0x384(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x376e
movq 0x8887(%rip), %rdi      # 0xbfd8
leaq 0x5d7a(%rip), %rsi      # 0x94d2
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
jmp 0x3770
movq 0x28(%rsp), %rax
movzbl 0x2074(%rax), %eax
cmpl $0x0, %eax
jle 0x37d1
movq 0x28(%rsp), %rax
addq $0x1230, %rax           # imm = 0x1230
movq (%rsp), %rcx
movzbl 0x4(%rcx), %ecx
imulq $0x388, %rcx, %rcx      # imm = 0x388
addq %rcx, %rax
movb 0x384(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x37cf
movq 0x8823(%rip), %rdi      # 0xbfd8
leaq 0x5d54(%rip), %rsi      # 0x9510
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
jmp 0x3820
jmp 0x37d1
jmp 0x37d3
jmp 0x37d5
movl 0x8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x8(%rsp)
jmp 0x366f
movl 0x24(%rsp), %eax
subl $0x6, %eax
movq 0x28(%rsp), %rcx
movzbl 0x2072(%rcx), %ecx
shll %ecx
subl %ecx, %eax
cmpl $0x0, %eax
je 0x3820
movq 0x87d0(%rip), %rdi      # 0xbfd8
leaq 0x5d3f(%rip), %rsi      # 0x954e
callq 0x2110
movq 0x28(%rsp), %rax
movb $0x0, 0x2088(%rax)
addq $0x38, %rsp
retq
nopw %cs:(%rax,%rax)