// File: /workspace/github_c_makefile_star2_O1/TimeToogo[P]ff-proxy/src/parser.c
// Function: ff_request_parse_data_chunk
void ff_request_parse_data_chunk(struct ff_request *request, uint32_t buff_size, void *buff)
{
    size_t i = 0;

    if (buff_size < sizeof(struct __raw_ff_request_header))
    {
        ff_log(FF_WARNING, "Packet buffer to small to contain header (%d)", buff_size);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    struct __raw_ff_request_header *header = (struct __raw_ff_request_header *)buff;
    i += sizeof(struct __raw_ff_request_header);

    // Normalise endianess
    uint16_t version = ntohs(header->version);
    uint64_t request_id = ntohll(header->request_id);
    uint32_t total_length = ntohl(header->total_length);
    uint32_t chunk_offset = ntohl(header->chunk_offset);
    uint16_t chunk_length = ntohs(header->chunk_length);

    if (request->version != FF_VERSION_1)
    {
        ff_log(FF_WARNING, "Request received with unknown version flag %d", request->version);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    if (version != request->version)
    {
        ff_log(FF_WARNING, "Mismatch between request version (%d) and chunk version (%d)", request->version, version);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    if (request_id != request->request_id)
    {
        ff_log(FF_WARNING, "Mismatch between request ID (%d) and chunk ID (%d)", request->request_id, request_id);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    if (total_length != request->payload_length)
    {
        ff_log(FF_WARNING, "Mismatch between request length (%d) and chunk length (%d)", request->payload_length, total_length);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    if (chunk_offset + chunk_length > request->payload_length)
    {
        ff_log(FF_WARNING, "Chunk offset and length too long");
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    if (buff_size < i + sizeof(struct __raw_ff_request_option_header))
    {
        ff_log(FF_WARNING, "Packet buffer ran out while looking for TLV options");
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    // Only first request can contain options
    if (header->chunk_offset == 0)
    {
        size_t options_i = ff_request_parse_options(request, buff_size - i, buff + i);

        if (options_i == 0)
        {
            request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
            return;
        }

        i += options_i;
    }
    else
    {
        struct __raw_ff_request_option_header *option_header = (struct __raw_ff_request_option_header *)(buff + i);

        i += sizeof(struct __raw_ff_request_option_header);

        if (option_header->type != FF_REQUEST_OPTION_TYPE_EOL)
        {
            ff_log(FF_WARNING, "Noninitial packets cannot contain request options");
            request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
            return;
        }
    }

    if (buff_size < i + chunk_length)
    {
        ff_log(FF_WARNING, "Packet buffer ran out while receiving payload. Expected %hu bytes, %u bytes remain", chunk_length, buff_size - i);
        request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
        return;
    }

    struct ff_request_payload_node *node = ff_request_payload_node_alloc();
    node->offset = chunk_offset;
    node->length = chunk_length;

    ff_request_payload_load_buff(
        node,
        buff_size - i,
        buff + i);

    if (request->payload == NULL)
    {
        request->payload = node;
        request->received_length = node->length;
    }
    else
    {
        struct ff_request_payload_node *current_node = request->payload;

        while (1)
        {

            bool overlaps_existing_node = node->offset < current_node->offset + current_node->length && current_node->offset <= node->offset + node->length;
            if (overlaps_existing_node)
            {
                ff_log(FF_WARNING,
                       "Received chunk range overlaps existing data. Received byte range [%u, %u] intersects existing range [%u, %u]",
                       node->offset, node->offset + node->length,
                       current_node->offset, current_node->offset + current_node->length);
                request->state = FF_REQUEST_STATE_RECEIVING_FAIL;
                return;
            }

            if (current_node == NULL || current_node->next == NULL)
            {
                break;
            }

            current_node = current_node->next;
        }

        current_node->next = node;
        request->received_length += node->length;
    }

    if (request->received_length == request->payload_length)
    {
        ff_log(FF_DEBUG, "Request %lu successfully received", request->request_id);
        request->state = FF_REQUEST_STATE_RECEIVED;
    }
    else
    {
        ff_log(FF_DEBUG, "Finished parsing request %lu partial packet, %lu bytes remain", request->request_id, request->payload_length - request->received_length);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movl %esi, %r14d
movq %rdi, %rbx
cmpl $0x13, %esi
ja 0x43ce
leaq 0x2982(%rip), %rsi      # 0x6d46
movl $0x3, %edi
movl %r14d, %edx
jmp 0x444a
movq %rdx, %r15
movl 0x4(%rbx), %edx
cmpl $0x1, %edx
jne 0x443e
movzwl (%r15), %eax
movzwl %ax, %ecx
cmpl $0x100, %ecx            # imm = 0x100
jne 0x4466
movq 0x2(%r15), %rcx
bswapq %rcx
movq 0x20(%rbx), %rdx
cmpq %rdx, %rcx
jne 0x4487
movl 0xa(%r15), %ecx
bswapl %ecx
movl %ecx, %eax
movq 0x40(%rbx), %rdx
cmpq %rax, %rdx
jne 0x449c
movl 0xe(%r15), %eax
movl %eax, %r13d
movzwl 0x12(%r15), %r12d
rolw $0x8, %r12w
bswapl %r13d
movzwl %r12w, %r8d
leal (%r8,%r13), %ecx
cmpq %rcx, %rdx
jae 0x44b1
leaq 0x2a14(%rip), %rsi      # 0x6e4d
jmp 0x44d2
leaq 0x292f(%rip), %rsi      # 0x6d74
movl $0x3, %edi
xorl %eax, %eax
callq 0x4100
movl $0x2, (%rbx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
rolw $0x8, %ax
movzwl %ax, %ecx
leaq 0x292e(%rip), %rsi      # 0x6da2
movl $0x3, %edi
movl $0x1, %edx
xorl %eax, %eax
callq 0x4100
jmp 0x4451
leaq 0x2951(%rip), %rsi      # 0x6ddf
movl $0x3, %edi
xorl %eax, %eax
callq 0x4100
jmp 0x4451
leaq 0x296f(%rip), %rsi      # 0x6e12
movl $0x3, %edi
xorl %eax, %eax
callq 0x4100
jmp 0x4451
cmpl $0x16, %r14d
ja 0x44c0
leaq 0x29b0(%rip), %rsi      # 0x6e6e
jmp 0x44d2
testl %eax, %eax
je 0x44e3
cmpb $0x0, 0x14(%r15)
je 0x4502
leaq 0x29d0(%rip), %rsi      # 0x6ea2
movl $0x3, %edi
xorl %eax, %eax
callq 0x4100
jmp 0x4451
movq %r8, -0x30(%rbp)
leal -0x14(%r14), %esi
leaq 0x14(%r15), %rdx
movq %rbx, %rdi
callq 0x4747
testq %rax, %rax
je 0x4509
leaq 0x14(%rax), %rdx
jmp 0x4514
movl $0x17, %edx
jmp 0x4521
movl $0x2, (%rbx)
movl $0x14, %edx
movq -0x30(%rbp), %r8
testq %rax, %rax
je 0x4457
movl %r14d, %ecx
leaq (%r8,%rdx), %rax
cmpq %rcx, %rax
jbe 0x454b
subq %rdx, %rcx
leaq 0x299d(%rip), %rsi      # 0x6ed4
movl $0x3, %edi
movl %r8d, %edx
xorl %eax, %eax
callq 0x4100
jmp 0x4451
movq %rdx, -0x30(%rbp)
callq 0x4b31
movw %r13w, (%rax)
movw %r12w, 0x2(%rax)
movq %rax, %r12
movq -0x30(%rbp), %rax
subl %eax, %r14d
addq %rax, %r15
movq %r12, %rdi
movl %r14d, %esi
movq %r15, %rdx
callq 0x4b4e
movq 0x50(%rbx), %r15
testq %r15, %r15
je 0x45f7
leaq 0x299f(%rip), %r14      # 0x6f27
movzwl (%r12), %edx
movzwl (%r15), %r8d
movzwl 0x2(%r15), %r9d
addl %r8d, %r9d
cmpl %edx, %r9d
jbe 0x45ab
movzwl 0x2(%r12), %ecx
addl %edx, %ecx
cmpl %r8d, %ecx
jae 0x45c0
movq 0x10(%r15), %rcx
xorl %eax, %eax
testq %rcx, %rcx
sete %al
leal (%rax,%rax,2), %eax
cmovneq %rcx, %r15
jmp 0x45da
movl $0x3, %edi
movq %r14, %rsi
xorl %eax, %eax
callq 0x4100
movl $0x2, (%rbx)
movl $0x1, %eax
testl %eax, %eax
je 0x4588
cmpl $0x3, %eax
jne 0x4457
movq %r12, 0x10(%r15)
movzwl 0x2(%r12), %eax
addq %rax, 0x48(%rbx)
jmp 0x4605
movq %r12, 0x50(%rbx)
movzwl 0x2(%r12), %eax
movq %rax, 0x48(%rbx)
movq 0x20(%rbx), %rdx
movq 0x40(%rbx), %rcx
subq 0x48(%rbx), %rcx
jne 0x4631
leaq 0x297a(%rip), %rsi      # 0x6f94
movl $0x1, %edi
xorl %eax, %eax
callq 0x4100
movl $0x1, (%rbx)
jmp 0x4457
leaq 0x297e(%rip), %rsi      # 0x6fb6
movl $0x1, %edi
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x4100