// File: divinity76[P]pi_compression/compressor/compressor.cpp
// Function: main
int main(int argc, char *argv[])
{
    if(argc !=4)
    {
        std::cerr << "usage: " << argv[0] << " \"pi_file.WTF\" \"file_to_compress\" \"save_path\"" << std::endl;
        std::cerr << "(" << (argc-1) << " arguments provided but exactly 3 arguments required.)" << std::endl;
        exit(EXIT_FAILURE);
    }
    const std::string pi_file=argv[1];
    const uint_fast32_t max_loop=(uint_fast32_t)std::min(uint64_t(UINT32_MAX),uint64_t(std::filesystem::file_size(pi_file)));
    if(max_loop < UINT32_MAX)
    {
        std::cerr << "Warning: pi file is small, it should be slightly larger than "<< UINT32_MAX << " bytes for better compression! (UINT32_MAX)" << std::endl;
    }
    const std::string pi_binary=file_get_contents(pi_file);
    assert(max_loop <= pi_binary.size());
    const std::string file_to_compress=argv[2];
    const size_t file_to_compress_size=std::filesystem::file_size(file_to_compress);
    std::string compress_binary=file_get_contents(file_to_compress);
    const std::string save_path=argv[3];
    if(std::filesystem::exists(save_path))
    {
        std::cerr << "Error: save file already exists! delete it first" << std::endl;
        exit(EXIT_FAILURE);
    }
    std::ofstream outfile (save_path,std::ofstream::binary);
    outfile.exceptions ( std::ofstream::failbit | std::ofstream::badbit );
    char packed[sizeof(uint32_t)+sizeof(uint8_t)];
    while(compress_binary.size()>0)
    {
        uint_fast32_t best_offset=0;
        uint_fast8_t best_offset_matches=0;
        for(uint_fast32_t pi_offset=0; pi_offset<max_loop; ++pi_offset)
        {
            uint_fast8_t matches=0;
            for(uint_fast32_t binary_offset=0; binary_offset<compress_binary.size(); ++binary_offset)
            {
                if(compress_binary[binary_offset]!=pi_binary[pi_offset+binary_offset] || matches>=UINT8_MAX)
                {
                    break;
                }
                ++matches;
            }
            if(matches>best_offset_matches)
            {
                best_offset=pi_offset;
                best_offset_matches=matches;
            }
        }
        std::cout << "offset: " << best_offset << " matches: " << uint_fast16_t(best_offset_matches) << std::endl;
        // optimized for little-endian...
        const uint32_t pack32_offset=HETOLE32(uint32_t(best_offset));
        memcpy(&packed[0],&pack32_offset,sizeof(pack32_offset));
        const uint8_t pack8_matches=uint8_t(best_offset_matches);
        memcpy(&packed[sizeof(pack32_offset)],&pack8_matches,sizeof(pack8_matches));
        outfile.write(packed, sizeof(packed));
        compress_binary.erase(0,best_offset_matches);
    }
}

// Assembly:
subq $0x478, %rsp            # imm = 0x478
movl $0x0, 0x474(%rsp)
movl %edi, 0x470(%rsp)
movq %rsi, 0x468(%rsp)
cmpl $0x4, 0x470(%rsp)
je 0x25a0
movq 0x3ada(%rip), %rdi      # 0x5ff0
leaq 0x1ae7(%rip), %rsi      # 0x4004
callq 0x21b0
movq %rax, %rdi
movq 0x468(%rsp), %rax
movq (%rax), %rsi
callq 0x21b0
movq %rax, %rdi
leaq 0x1acd(%rip), %rsi      # 0x400c
callq 0x21b0
movq %rax, %rdi
movq 0x3a72(%rip), %rsi      # 0x5fc0
callq 0x21d0
movq 0x3a96(%rip), %rdi      # 0x5ff0
leaq 0x1ad9(%rip), %rsi      # 0x403a
callq 0x21b0
movq %rax, %rdi
movl 0x470(%rsp), %esi
subl $0x1, %esi
callq 0x2310
movq %rax, %rdi
leaq 0x1aba(%rip), %rsi      # 0x403c
callq 0x21b0
movq %rax, %rdi
movq 0x3a2f(%rip), %rsi      # 0x5fc0
callq 0x21d0
movl $0x1, %edi
callq 0x2240
movq 0x468(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0xc0(%rsp)
leaq 0x447(%rsp), %rdi
movq %rdi, 0xc8(%rsp)
callq 0x2330
movq 0xc0(%rsp), %rsi
movq 0xc8(%rsp), %rdx
leaq 0x448(%rsp), %rdi
callq 0x2ed0
jmp 0x25e8
leaq 0x447(%rsp), %rdi
callq 0x21f0
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x420(%rsp)
leaq 0x3f0(%rsp), %rdi
leaq 0x448(%rsp), %rsi
movl $0x2, %edx
callq 0x2fd0
jmp 0x261e
leaq 0x3f0(%rsp), %rdi
callq 0x2270
movq %rax, 0xb8(%rsp)
jmp 0x2635
movq 0xb8(%rsp), %rax
movq %rax, 0x418(%rsp)
leaq 0x420(%rsp), %rdi
leaq 0x418(%rsp), %rsi
callq 0x2f90
movq %rax, 0xb0(%rsp)
jmp 0x2664
movq 0xb0(%rsp), %rax
movq (%rax), %rax
movq %rax, 0xa8(%rsp)
leaq 0x3f0(%rsp), %rdi
callq 0x30d0
movq 0xa8(%rsp), %rax
movq %rax, 0x428(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpq %rax, 0x428(%rsp)
jae 0x277b
movq 0x3942(%rip), %rdi      # 0x5ff0
leaq 0x19be(%rip), %rsi      # 0x4073
callq 0x21b0
movq %rax, 0xa0(%rsp)
jmp 0x26c4
movq 0xa0(%rsp), %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
callq 0x2280
movq %rax, 0x98(%rsp)
jmp 0x26e0
movq 0x98(%rsp), %rdi
leaq 0x19c2(%rip), %rsi      # 0x40b1
callq 0x21b0
movq %rax, 0x90(%rsp)
jmp 0x26fe
movq 0x90(%rsp), %rdi
movq 0x38b3(%rip), %rsi      # 0x5fc0
callq 0x21d0
jmp 0x2714
jmp 0x277b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x447(%rsp), %rdi
callq 0x21f0
jmp 0x2d98
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
jmp 0x2d8b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x3f0(%rsp), %rdi
callq 0x30d0
jmp 0x2d8b
leaq 0x3d0(%rsp), %rdi
leaq 0x448(%rsp), %rsi
callq 0x2db0
jmp 0x2792
movq 0x428(%rsp), %rax
movq %rax, 0x88(%rsp)
leaq 0x3d0(%rsp), %rdi
callq 0x2150
movq %rax, %rcx
movq 0x88(%rsp), %rax
cmpq %rcx, %rax
ja 0x27c1
jmp 0x27e0
leaq 0x1915(%rip), %rdi      # 0x40dd
leaq 0x192b(%rip), %rsi      # 0x40fa
movl $0x49, %edx
leaq 0x1939(%rip), %rcx      # 0x4114
callq 0x2130
movq 0x468(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x78(%rsp)
leaq 0x3af(%rsp), %rdi
movq %rdi, 0x80(%rsp)
callq 0x2330
movq 0x78(%rsp), %rsi
movq 0x80(%rsp), %rdx
leaq 0x3b0(%rsp), %rdi
callq 0x2ed0
jmp 0x2822
leaq 0x3af(%rsp), %rdi
callq 0x21f0
leaq 0x378(%rsp), %rdi
leaq 0x3b0(%rsp), %rsi
movl $0x2, %edx
callq 0x2fd0
jmp 0x284b
leaq 0x378(%rsp), %rdi
callq 0x2270
movq %rax, 0x70(%rsp)
jmp 0x285f
leaq 0x378(%rsp), %rdi
callq 0x30d0
movq 0x70(%rsp), %rax
movq %rax, 0x3a0(%rsp)
leaq 0x358(%rsp), %rdi
leaq 0x3b0(%rsp), %rsi
callq 0x2db0
jmp 0x2890
movq 0x468(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x60(%rsp)
leaq 0x337(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x2330
movq 0x60(%rsp), %rsi
movq 0x68(%rsp), %rdx
leaq 0x338(%rsp), %rdi
callq 0x2ed0
jmp 0x28cc
leaq 0x337(%rsp), %rdi
callq 0x21f0
leaq 0x308(%rsp), %rdi
leaq 0x338(%rsp), %rsi
movl $0x2, %edx
callq 0x2fd0
jmp 0x28f5
leaq 0x308(%rsp), %rdi
callq 0x3100
movb %al, 0x5f(%rsp)
jmp 0x2908
leaq 0x308(%rsp), %rdi
callq 0x30d0
movb 0x5f(%rsp), %al
testb $0x1, %al
jne 0x2922
jmp 0x2a23
movq 0x36c7(%rip), %rdi      # 0x5ff0
leaq 0x17fb(%rip), %rsi      # 0x412b
callq 0x21b0
movq %rax, 0x50(%rsp)
jmp 0x293c
movq 0x50(%rsp), %rdi
movq 0x3678(%rip), %rsi      # 0x5fc0
callq 0x21d0
jmp 0x294f
movl $0x1, %edi
callq 0x2240
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x3af(%rsp), %rdi
callq 0x21f0
jmp 0x2d7e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
jmp 0x2d71
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x378(%rsp), %rdi
callq 0x30d0
jmp 0x2d71
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x337(%rsp), %rdi
callq 0x21f0
jmp 0x2d64
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
jmp 0x2d57
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x308(%rsp), %rdi
callq 0x30d0
jmp 0x2d57
leaq 0x108(%rsp), %rdi
leaq 0x338(%rsp), %rsi
movl $0x4, %edx
callq 0x2350
jmp 0x2a3f
movq 0x108(%rsp), %rax
movq -0x18(%rax), %rax
leaq 0x108(%rsp,%rax), %rax
movq %rax, 0x40(%rsp)
movl $0x4, %edi
movl $0x1, %esi
callq 0x3130
movl %eax, 0x4c(%rsp)
jmp 0x2a6d
movl 0x4c(%rsp), %esi
movq 0x40(%rsp), %rdi
callq 0x20c0
jmp 0x2a7d
jmp 0x2a7f
leaq 0x358(%rsp), %rdi
callq 0x2150
cmpq $0x0, %rax
jbe 0x2cfa
movq $0x0, 0xf8(%rsp)
movb $0x0, 0xf7(%rsp)
movq $0x0, 0xe8(%rsp)
movq 0xe8(%rsp), %rax
cmpq 0x428(%rsp), %rax
jae 0x2c0b
movb $0x0, 0xe7(%rsp)
movq $0x0, 0xd8(%rsp)
movq 0xd8(%rsp), %rax
movq %rax, 0x38(%rsp)
leaq 0x358(%rsp), %rdi
callq 0x2150
movq %rax, %rcx
movq 0x38(%rsp), %rax
cmpq %rcx, %rax
jae 0x2bbe
movq 0xd8(%rsp), %rsi
leaq 0x358(%rsp), %rdi
callq 0x2370
movq %rax, 0x30(%rsp)
jmp 0x2b27
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
movl %eax, 0x2c(%rsp)
movq 0xe8(%rsp), %rsi
addq 0xd8(%rsp), %rsi
leaq 0x3d0(%rsp), %rdi
callq 0x2220
movq %rax, %rcx
movl 0x2c(%rsp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
jne 0x2b6d
movzbl 0xe7(%rsp), %eax
cmpl $0xff, %eax
jl 0x2b95
jmp 0x2bbe
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x438(%rsp)
movl %eax, 0x434(%rsp)
leaq 0x108(%rsp), %rdi
callq 0x22c0
jmp 0x2d57
movb 0xe7(%rsp), %al
addb $0x1, %al
movb %al, 0xe7(%rsp)
movq 0xd8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xd8(%rsp)
jmp 0x2ae0
movzbl 0xe7(%rsp), %eax
movzbl 0xf7(%rsp), %ecx
cmpl %ecx, %eax
jle 0x2bf0
movq 0xe8(%rsp), %rax
movq %rax, 0xf8(%rsp)
movb 0xe7(%rsp), %al
movb %al, 0xf7(%rsp)
jmp 0x2bf2
movq 0xe8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xe8(%rsp)
jmp 0x2ab6
movq 0x33be(%rip), %rdi      # 0x5fd0
leaq 0x1543(%rip), %rsi      # 0x415c
callq 0x21b0
movq %rax, 0x20(%rsp)
jmp 0x2c25
movq 0x20(%rsp), %rdi
movq 0xf8(%rsp), %rsi
callq 0x2060
movq %rax, 0x18(%rsp)
jmp 0x2c3e
movq 0x18(%rsp), %rdi
leaq 0x151b(%rip), %rsi      # 0x4165
callq 0x21b0
movq %rax, 0x10(%rsp)
jmp 0x2c56
movq 0x10(%rsp), %rdi
movzbl 0xf7(%rsp), %eax
movl %eax, %esi
callq 0x2060
movq %rax, 0x8(%rsp)
jmp 0x2c71
movq 0x8(%rsp), %rdi
movq 0x3343(%rip), %rsi      # 0x5fc0
callq 0x21d0
jmp 0x2c84
movl 0xf8(%rsp), %eax
movl %eax, 0xd4(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, 0x100(%rsp)
movb 0xf7(%rsp), %al
movb %al, 0xd3(%rsp)
movb 0xd3(%rsp), %al
movb %al, 0x104(%rsp)
leaq 0x108(%rsp), %rdi
leaq 0x100(%rsp), %rsi
movl $0x5, %edx
callq 0x2260
jmp 0x2cd8
movzbl 0xf7(%rsp), %eax
movl %eax, %edx
xorl %eax, %eax
movl %eax, %esi
leaq 0x358(%rsp), %rdi
callq 0x2050
jmp 0x2cf5
jmp 0x2a7f
leaq 0x108(%rsp), %rdi
callq 0x22c0
leaq 0x338(%rsp), %rdi
callq 0x2120
leaq 0x358(%rsp), %rdi
callq 0x2120
leaq 0x3b0(%rsp), %rdi
callq 0x2120
leaq 0x3d0(%rsp), %rdi
callq 0x2120
leaq 0x448(%rsp), %rdi
callq 0x2120
movl 0x474(%rsp), %eax
addq $0x478, %rsp            # imm = 0x478
retq
leaq 0x338(%rsp), %rdi
callq 0x2120
leaq 0x358(%rsp), %rdi
callq 0x2120
leaq 0x3b0(%rsp), %rdi
callq 0x2120
leaq 0x3d0(%rsp), %rdi
callq 0x2120
leaq 0x448(%rsp), %rdi
callq 0x2120
movq 0x438(%rsp), %rdi
callq 0x2320
nopw %cs:(%rax,%rax)