// File: /workspace/github_c_makefile_star2_O3/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 0x4272
leaq 0x2ade(%rip), %rsi      # 0x6d46
movl $0x3, %edi
movl %r14d, %edx
jmp 0x42ed
movq %rdx, %r15
movl 0x4(%rbx), %edx
cmpl $0x1, %edx
jne 0x42e1
movzwl (%r15), %eax
movzwl %ax, %ecx
cmpl $0x100, %ecx            # imm = 0x100
jne 0x4309
movq 0x2(%r15), %rcx
bswapq %rcx
movq 0x20(%rbx), %rdx
cmpq %rdx, %rcx
jne 0x432a
movl 0xa(%r15), %ecx
bswapl %ecx
movl %ecx, %eax
movq 0x40(%rbx), %rdx
cmpq %rax, %rdx
jne 0x433f
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 0x4354
leaq 0x2b71(%rip), %rsi      # 0x6e4d
jmp 0x4375
leaq 0x2a8c(%rip), %rsi      # 0x6d74
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
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 0x2a8b(%rip), %rsi      # 0x6da2
movl $0x3, %edi
movl $0x1, %edx
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4
leaq 0x2aae(%rip), %rsi      # 0x6ddf
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4
leaq 0x2acc(%rip), %rsi      # 0x6e12
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4
cmpl $0x16, %r14d
ja 0x4363
leaq 0x2b0d(%rip), %rsi      # 0x6e6e
jmp 0x4375
testl %eax, %eax
je 0x4386
cmpb $0x0, 0x14(%r15)
je 0x43ad
leaq 0x2b2d(%rip), %rsi      # 0x6ea2
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4
movq %rdx, -0x30(%rbp)
leal -0x14(%r14), %esi
leaq 0x14(%r15), %rdx
movq %rbx, %rdi
callq 0x459b
testq %rax, %rax
je 0x42f4
addq $0x14, %rax
movq -0x30(%rbp), %rdx
jmp 0x43b2
movl $0x17, %eax
movl %r14d, %ecx
leaq (%rdx,%rax), %rsi
cmpq %rcx, %rsi
jbe 0x43d9
subq %rax, %rcx
leaq 0x2b0c(%rip), %rsi      # 0x6ed4
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4
movq %rax, -0x30(%rbp)
callq 0x4921
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 0x493e
movq 0x50(%rbx), %rcx
testq %rcx, %rcx
je 0x444e
movzwl (%r12), %edx
movq %rcx, %rax
movzwl (%rcx), %r8d
movzwl 0x2(%rcx), %r9d
addl %r8d, %r9d
cmpl %edx, %r9d
jbe 0x4435
movzwl 0x2(%r12), %ecx
addl %edx, %ecx
cmpl %r8d, %ecx
jae 0x44a8
movq 0x10(%rax), %rcx
testq %rcx, %rcx
jne 0x4414
movq %r12, 0x10(%rax)
movzwl 0x2(%r12), %eax
addq 0x48(%rbx), %rax
jmp 0x4458
movq %r12, 0x50(%rbx)
movzwl 0x2(%r12), %eax
movq %rax, 0x48(%rbx)
movq 0x20(%rbx), %rdx
movq 0x40(%rbx), %rcx
subq %rax, %rcx
jne 0x4487
leaq 0x2b24(%rip), %rsi      # 0x6f94
movl $0x1, %edi
xorl %eax, %eax
callq 0x3fa4
movl $0x1, (%rbx)
jmp 0x42fa
leaq 0x2b28(%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 0x3fa4
leaq 0x2a78(%rip), %rsi      # 0x6f27
movl $0x3, %edi
xorl %eax, %eax
callq 0x3fa4
jmp 0x42f4