// File: night-shift[P]Srl/src/lib/ToolsStrConv.cpp
// Function: Srl::Tools::conv_charset(Srl::Encoding, Srl::String const&, std::vector<unsigned char, std::allocator<unsigned char>>&, bool, unsigned long)
size_t Tools::conv_charset(Encoding target_encoding, const String& str_wrap,
                           vector<uint8_t>& buffer,  bool throw_error, size_t buffer_index)
{
    if(str_wrap.size() < 1) {
        return 0;
    }

    auto src_encoding = str_wrap.encoding();

    auto* cs_from = get_charset_string(src_encoding);
    auto* cs_to   = get_charset_string(target_encoding);

    if(cs_from == cs_to) {
        auto seg = str_wrap.size() + buffer_index;
        if(buffer.size() < seg) {
            buffer.resize(seg);
        }
        memcpy(&buffer[buffer_index], str_wrap.data(), str_wrap.size());

        return str_wrap.size();
    }

    if(cs_from == nullptr || cs_to == nullptr) {
        if(throw_error) {
            throw Exception("Unable to convert charset. Unknown encoding.");
        }
        return 0;
    }

    iconv_t desc = iconv_open(cs_to, cs_from);

    if(desc == (iconv_t)(-1)) {
        if(throw_error) {
            throw Exception("Unable to convert charset. Failed to open iconv descriptor.");
        }
        return 0;
    }

    size_t left_in = str_wrap.size();
    size_t reserve = left_in * (
        target_encoding < src_encoding ? 1 : src_encoding == Encoding::UTF16 ? 2 : 4
    );

    if(buffer_index + reserve > buffer.size()) {
        buffer.resize(buffer_index + reserve);
    }
    size_t left_out = buffer.size() - buffer_index;

    auto* src = (char*)str_wrap.data();
    size_t converted = 0;

    while(true) {
        auto* dst = (char*)&buffer[buffer_index + converted];
        converted = iconv(desc, &src, &left_in, &dst, &left_out);

        if(converted == 0) {
            /* all characters converted */
            break;
        }

        if(errno == EINVAL) {
            iconv_close(desc);
            if(throw_error) {
                throw Exception("Unable to convert charset. Incomplete byte sequence.");
            }
            return 0;
        }

        if(errno == EILSEQ) {
            iconv_close(desc);
            if(throw_error) {
                throw Exception("Unable to convert charset. Invalid byte sequence.");
            }
            return 0;
        }

        if (errno == E2BIG) {
            /* output buffer not big enough */
            auto current = buffer.size();
            auto new_size = buffer.size() + left_in * 4;
            buffer.resize(new_size);
            converted = current - left_out;
            left_out = new_size - converted;
        }
    }

    iconv_close(desc);

    return buffer.size() - buffer_index - left_out;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1b0, %rsp            # imm = 0x1B0
movb %cl, %al
movb %dil, %cl
movb %cl, -0x9(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
andb $0x1, %al
movb %al, -0x21(%rbp)
movq %r8, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x37f50
cmpq $0x1, %rax
jae 0x64550
movq $0x0, -0x8(%rbp)
jmp 0x64be1
movq -0x18(%rbp), %rdi
callq 0x342c0
movb %al, -0x31(%rbp)
movzbl -0x31(%rbp), %edi
callq 0x64c00
movq %rax, -0x40(%rbp)
movzbl -0x9(%rbp), %edi
callq 0x64c00
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rax
cmpq -0x48(%rbp), %rax
jne 0x64606
movq -0x18(%rbp), %rdi
callq 0x37f50
addq -0x30(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x20(%rbp), %rdi
callq 0x37840
cmpq -0x50(%rbp), %rax
jae 0x645b1
movq -0x20(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x35f00
movq -0x20(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x33120
movq %rax, -0x158(%rbp)
movq -0x18(%rbp), %rdi
callq 0x33490
movq %rax, -0x150(%rbp)
movq -0x18(%rbp), %rdi
callq 0x37f50
movq -0x158(%rbp), %rdi
movq -0x150(%rbp), %rsi
movq %rax, %rdx
callq 0x35360
movq -0x18(%rbp), %rdi
callq 0x37f50
movq %rax, -0x8(%rbp)
jmp 0x64be1
cmpq $0x0, -0x40(%rbp)
je 0x64618
cmpq $0x0, -0x48(%rbp)
jne 0x646f6
testb $0x1, -0x21(%rbp)
je 0x646e9
movb $0x1, -0x85(%rbp)
movl $0x28, %edi
callq 0x34160
movq %rax, -0x168(%rbp)
leaq -0x71(%rbp), %rdi
movq %rdi, -0x160(%rbp)
callq 0x38240
movq -0x160(%rbp), %rdx
leaq 0x5c10(%rip), %rsi      # 0x6a268
leaq -0x70(%rbp), %rdi
callq 0x37f40
jmp 0x64663
movq -0x168(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x33910
jmp 0x64675
movq -0x168(%rbp), %rdi
movb $0x0, -0x85(%rbp)
movq 0x1e95e(%rip), %rsi     # 0x82fe8
movq 0x1e8a7(%rip), %rdx     # 0x82f38
callq 0x37fc0
jmp 0x64bf7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x646c4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x38ce0
leaq -0x71(%rbp), %rdi
callq 0x35f90
testb $0x1, -0x85(%rbp)
jne 0x646d8
jmp 0x646e4
movq -0x168(%rbp), %rdi
callq 0x34ce0
jmp 0x64bee
movq $0x0, -0x8(%rbp)
jmp 0x64be1
movq -0x48(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x34fc0
movq %rax, -0x90(%rbp)
movq $-0x1, %rax
cmpq %rax, -0x90(%rbp)
jne 0x6480b
testb $0x1, -0x21(%rbp)
je 0x647fe
movb $0x1, -0xb2(%rbp)
movl $0x28, %edi
callq 0x34160
movq %rax, -0x178(%rbp)
leaq -0xb1(%rbp), %rdi
movq %rdi, -0x170(%rbp)
callq 0x38240
movq -0x170(%rbp), %rdx
leaq 0x5b34(%rip), %rsi      # 0x6a295
leaq -0xb0(%rbp), %rdi
callq 0x37f40
jmp 0x6476f
movq -0x178(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x33910
jmp 0x64784
movq -0x178(%rbp), %rdi
movb $0x0, -0xb2(%rbp)
movq 0x1e84f(%rip), %rsi     # 0x82fe8
movq 0x1e798(%rip), %rdx     # 0x82f38
callq 0x37fc0
jmp 0x64bf7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x647d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0x38ce0
leaq -0xb1(%rbp), %rdi
callq 0x35f90
testb $0x1, -0xb2(%rbp)
jne 0x647ed
jmp 0x647f9
movq -0x178(%rbp), %rdi
callq 0x34ce0
jmp 0x64bee
movq $0x0, -0x8(%rbp)
jmp 0x64be1
movq -0x18(%rbp), %rdi
callq 0x37f50
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
movq %rax, -0x180(%rbp)
movb -0x9(%rbp), %al
cmpb -0x31(%rbp), %al
jae 0x6483e
movl $0x1, %eax
movl %eax, -0x184(%rbp)
jmp 0x64857
movb -0x31(%rbp), %dl
movl $0x4, %eax
movl $0x2, %ecx
cmpb $0x2, %dl
cmovel %ecx, %eax
movl %eax, -0x184(%rbp)
movq -0x180(%rbp), %rax
movl -0x184(%rbp), %ecx
movslq %ecx, %rcx
imulq %rcx, %rax
movq %rax, -0xc8(%rbp)
movq -0x30(%rbp), %rax
addq -0xc8(%rbp), %rax
movq %rax, -0x190(%rbp)
movq -0x20(%rbp), %rdi
callq 0x37840
movq %rax, %rcx
movq -0x190(%rbp), %rax
cmpq %rcx, %rax
jbe 0x648b0
movq -0x20(%rbp), %rdi
movq -0x30(%rbp), %rsi
addq -0xc8(%rbp), %rsi
callq 0x35f00
movq -0x20(%rbp), %rdi
callq 0x37840
subq -0x30(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x33490
movq %rax, -0xd8(%rbp)
movq $0x0, -0xe0(%rbp)
movq -0x20(%rbp), %rdi
movq -0x30(%rbp), %rsi
addq -0xe0(%rbp), %rsi
callq 0x33120
movq %rax, -0xe8(%rbp)
movq -0x90(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
leaq -0xe8(%rbp), %rcx
leaq -0xd0(%rbp), %r8
callq 0x38230
movq %rax, -0xe0(%rbp)
cmpq $0x0, -0xe0(%rbp)
jne 0x64938
jmp 0x64bbd
callq 0x33110
cmpl $0x16, (%rax)
jne 0x64a3f
movq -0x90(%rbp), %rdi
callq 0x351d0
testb $0x1, -0x21(%rbp)
je 0x64a32
movb $0x1, -0x10a(%rbp)
movl $0x28, %edi
callq 0x34160
movq %rax, -0x1a0(%rbp)
leaq -0x109(%rbp), %rdi
movq %rdi, -0x198(%rbp)
callq 0x38240
movq -0x198(%rbp), %rdx
leaq 0x593c(%rip), %rsi      # 0x6a2d1
leaq -0x108(%rbp), %rdi
callq 0x37f40
jmp 0x649a3
movq -0x1a0(%rbp), %rdi
leaq -0x108(%rbp), %rsi
callq 0x33910
jmp 0x649b8
movq -0x1a0(%rbp), %rdi
movb $0x0, -0x10a(%rbp)
movq 0x1e61b(%rip), %rsi     # 0x82fe8
movq 0x1e564(%rip), %rdx     # 0x82f38
callq 0x37fc0
jmp 0x64bf7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x64a0a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x108(%rbp), %rdi
callq 0x38ce0
leaq -0x109(%rbp), %rdi
callq 0x35f90
testb $0x1, -0x10a(%rbp)
jne 0x64a21
jmp 0x64a2d
movq -0x1a0(%rbp), %rdi
callq 0x34ce0
jmp 0x64bee
movq $0x0, -0x8(%rbp)
jmp 0x64be1
callq 0x33110
cmpl $0x54, (%rax)
jne 0x64b46
movq -0x90(%rbp), %rdi
callq 0x351d0
testb $0x1, -0x21(%rbp)
je 0x64b39
movb $0x1, -0x132(%rbp)
movl $0x28, %edi
callq 0x34160
movq %rax, -0x1b0(%rbp)
leaq -0x131(%rbp), %rdi
movq %rdi, -0x1a8(%rbp)
callq 0x38240
movq -0x1a8(%rbp), %rdx
leaq 0x586a(%rip), %rsi      # 0x6a306
leaq -0x130(%rbp), %rdi
callq 0x37f40
jmp 0x64aaa
movq -0x1b0(%rbp), %rdi
leaq -0x130(%rbp), %rsi
callq 0x33910
jmp 0x64abf
movq -0x1b0(%rbp), %rdi
movb $0x0, -0x132(%rbp)
movq 0x1e514(%rip), %rsi     # 0x82fe8
movq 0x1e45d(%rip), %rdx     # 0x82f38
callq 0x37fc0
jmp 0x64bf7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x64b11
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0x130(%rbp), %rdi
callq 0x38ce0
leaq -0x131(%rbp), %rdi
callq 0x35f90
testb $0x1, -0x132(%rbp)
jne 0x64b28
jmp 0x64b34
movq -0x1b0(%rbp), %rdi
callq 0x34ce0
jmp 0x64bee
movq $0x0, -0x8(%rbp)
jmp 0x64be1
callq 0x33110
cmpl $0x7, (%rax)
jne 0x64bb8
movq -0x20(%rbp), %rdi
callq 0x37840
movq %rax, -0x140(%rbp)
movq -0x20(%rbp), %rdi
callq 0x37840
movq -0xc0(%rbp), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x148(%rbp)
movq -0x20(%rbp), %rdi
movq -0x148(%rbp), %rsi
callq 0x35f00
movq -0x140(%rbp), %rax
subq -0xd0(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0x148(%rbp), %rax
subq -0xe0(%rbp), %rax
movq %rax, -0xd0(%rbp)
jmp 0x648df
movq -0x90(%rbp), %rdi
callq 0x351d0
movq -0x20(%rbp), %rdi
callq 0x37840
subq -0x30(%rbp), %rax
subq -0xd0(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x1b0, %rsp            # imm = 0x1B0
popq %rbp
retq
movq -0x80(%rbp), %rdi
callq 0x38210
nopw (%rax,%rax)