// File: /workspace/github_c_makefile_star2_O2/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 0x4055
leaq 0x1cf9(%rip), %rsi      # 0x5d46
pushq $0x3
popq %rdi
movl %r14d, %edx
jmp 0x40c9
movq %rdx, %r15
movl 0x4(%rbx), %edx
cmpl $0x1, %edx
jne 0x40bf
movzwl (%r15), %eax
cmpw $0x100, %ax             # imm = 0x100
jne 0x40e5
movq 0x2(%r15), %rcx
bswapq %rcx
movq 0x20(%rbx), %rdx
cmpq %rdx, %rcx
jne 0x4102
movl 0xa(%r15), %ecx
bswapl %ecx
movl %ecx, %eax
movq 0x40(%rbx), %rdx
cmpq %rax, %rdx
jne 0x4115
movl 0xe(%r15), %eax
movl %eax, %r13d
movzwl 0x12(%r15), %r12d
rolw $0x8, %r12w
bswapl %r13d
movzwl %r12w, %edx
leal (%rdx,%r13), %esi
cmpl %esi, %ecx
jae 0x4128
leaq 0x1d93(%rip), %rsi      # 0x5e4d
jmp 0x4149
leaq 0x1cae(%rip), %rsi      # 0x5d74
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
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 0x1caf(%rip), %rsi      # 0x5da2
pushq $0x3
popq %rdi
pushq $0x1
popq %rdx
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0
leaq 0x1cd6(%rip), %rsi      # 0x5ddf
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0
leaq 0x1cf6(%rip), %rsi      # 0x5e12
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0
cmpl $0x16, %r14d
ja 0x4137
leaq 0x1d39(%rip), %rsi      # 0x5e6e
jmp 0x4149
testl %eax, %eax
je 0x4158
cmpb $0x0, 0x14(%r15)
je 0x417f
leaq 0x1d59(%rip), %rsi      # 0x5ea2
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0
movq %rdx, -0x30(%rbp)
leal -0x14(%r14), %esi
leaq 0x14(%r15), %rdx
movq %rbx, %rdi
callq 0x4363
testq %rax, %rax
je 0x40d0
addq $0x14, %rax
movq -0x30(%rbp), %rdx
jmp 0x4182
pushq $0x17
popq %rax
movl %r14d, %ecx
leaq (%rdx,%rax), %rsi
cmpq %rcx, %rsi
jbe 0x41a7
subq %rax, %rcx
leaq 0x1d3c(%rip), %rsi      # 0x5ed4
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0
movq %rax, -0x30(%rbp)
callq 0x46a8
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 0x46c0
movq 0x50(%rbx), %rcx
testq %rcx, %rcx
je 0x421c
movzwl (%r12), %edx
movq %rcx, %rax
movzwl (%rcx), %r8d
movzwl 0x2(%rcx), %r9d
addl %r8d, %r9d
cmpl %edx, %r9d
jbe 0x4203
movzwl 0x2(%r12), %ecx
addl %edx, %ecx
cmpl %r8d, %ecx
jae 0x4272
movq 0x10(%rax), %rcx
testq %rcx, %rcx
jne 0x41e2
movq %r12, 0x10(%rax)
movzwl 0x2(%r12), %eax
addq 0x48(%rbx), %rax
jmp 0x4226
movq %r12, 0x50(%rbx)
movzwl 0x2(%r12), %eax
movq %rax, 0x48(%rbx)
movq 0x20(%rbx), %rdx
movq 0x40(%rbx), %rcx
subq %rax, %rcx
jne 0x4253
leaq 0x1d56(%rip), %rsi      # 0x5f94
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x3db4
movl $0x1, (%rbx)
jmp 0x40d6
leaq 0x1d5c(%rip), %rsi      # 0x5fb6
pushq $0x1
popq %rdi
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3db4
leaq 0x1cae(%rip), %rsi      # 0x5f27
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x3db4
jmp 0x40d0