// File: ivanoleinik[P]archiver/src/huffman.cpp
// Function: HuffDecode::HuffDecode(std::istream&)
HuffDecode::HuffDecode(std::istream &in) {
    in.seekg(0, std::ios::beg);

    std::vector<std::size_t> frequencies;
    frequencies.assign(256, 0);
    for (size_t &freq : frequencies)
        in.read(reinterpret_cast<char*>(&freq), sizeof(size_t));
    _tree = std::make_shared<HuffTree>(frequencies);
    _codes = _tree->get_codes();

    in.seekg(0, std::ios::end);
    _encoded_data.reserve(in.tellg());
    in.seekg(256 * sizeof(size_t), std::ios::beg);
    _encoded_data.assign((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());

    std::shared_ptr<TreeNode> root = _tree->get_root();
    std::shared_ptr<TreeNode> curr_node = root;

    size_t freq_sum = 0;
    for (size_t freq : _tree->get_frequencies())
        freq_sum += freq;
    for (unsigned char c : _encoded_data) {
        if (!freq_sum)
            break;
        for (size_t bit = 0; bit < 8 && freq_sum; bit++) {
            if (c & (1 << bit))
                curr_node = curr_node->left;
            else
                curr_node = curr_node->right;

            if (curr_node->is_leaf()) {
                _decoded_data += curr_node->data;
                freq_sum--;
                curr_node = root;
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x180, %rsp            # imm = 0x180
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x120(%rbp)
movq %rdi, %rax
movq %rax, -0x138(%rbp)
callq 0x32f0
movq -0x120(%rbp), %rdi
addq $0x20, %rdi
movq %rdi, -0x130(%rbp)
callq 0x32f0
movq -0x120(%rbp), %rdi
addq $0x40, %rdi
movq %rdi, -0x128(%rbp)
callq 0x5440
movq -0x120(%rbp), %rdi
addq $0x50, %rdi
movq %rdi, -0x118(%rbp)
callq 0x50b0
movq -0x10(%rbp), %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x32e0
jmp 0x4581
leaq -0x38(%rbp), %rdi
movq %rdi, -0x140(%rbp)
callq 0x5c40
movq -0x140(%rbp), %rdi
movq $0x0, -0x40(%rbp)
movl $0x100, %esi            # imm = 0x100
leaq -0x40(%rbp), %rdx
callq 0x5c60
jmp 0x45b0
leaq -0x38(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x5a30
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rdi
callq 0x5a60
movq %rax, -0x58(%rbp)
leaq -0x50(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x5a90
testb $0x1, %al
jne 0x45e5
jmp 0x4635
leaq -0x50(%rbp), %rdi
callq 0x5ad0
movq %rax, -0x60(%rbp)
movq -0x10(%rbp), %rdi
movq -0x60(%rbp), %rsi
movl $0x8, %edx
callq 0x32c0
jmp 0x4606
jmp 0x4608
leaq -0x50(%rbp), %rdi
callq 0x5af0
jmp 0x45d2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x18(%rbp)
movl %eax, -0x1c(%rbp)
jmp 0x4a35
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x18(%rbp)
movl %eax, -0x1c(%rbp)
jmp 0x4a2c
leaq -0x70(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x5700
jmp 0x4644
movq -0x138(%rbp), %rdi
addq $0x40, %rdi
movq %rdi, -0x148(%rbp)
leaq -0x70(%rbp), %rsi
movq %rsi, -0x150(%rbp)
callq 0x5770
movq -0x150(%rbp), %rdi
callq 0x57a0
movq -0x148(%rbp), %rdi
callq 0x57c0
movq %rax, %rdi
callq 0x3e80
movq -0x138(%rbp), %rdi
movq %rax, %rsi
addq $0x50, %rdi
callq 0x57e0
jmp 0x469b
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
callq 0x32e0
jmp 0x46af
movq -0x138(%rbp), %rax
movq %rax, -0x168(%rbp)
movq -0x10(%rbp), %rdi
callq 0x33b0
movq %rdx, -0x160(%rbp)
movq %rax, -0x158(%rbp)
jmp 0x46d6
movq -0x160(%rbp), %rax
movq -0x158(%rbp), %rcx
movq %rcx, -0x80(%rbp)
movq %rax, -0x78(%rbp)
leaq -0x80(%rbp), %rdi
callq 0x5460
movq %rax, -0x170(%rbp)
jmp 0x46fe
movq -0x170(%rbp), %rsi
movq -0x168(%rbp), %rdi
callq 0x3360
jmp 0x4713
movq -0x10(%rbp), %rdi
movl $0x800, %esi            # imm = 0x800
xorl %edx, %edx
callq 0x32e0
jmp 0x4725
movq -0x10(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x5530
leaq -0xa0(%rbp), %rdi
callq 0x5590
movq -0x138(%rbp), %rdi
movq -0x90(%rbp), %rsi
movl -0x88(%rbp), %edx
movq -0xa0(%rbp), %rcx
movl -0x98(%rbp), %r8d
callq 0x5480
jmp 0x476a
movq -0x138(%rbp), %rdi
addq $0x40, %rdi
callq 0x57c0
movq %rax, %rsi
leaq -0xb0(%rbp), %rdi
callq 0x3ea0
jmp 0x478b
leaq -0xc0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x4db0
movq -0x138(%rbp), %rdi
movq $0x0, -0xc8(%rbp)
addq $0x40, %rdi
callq 0x57c0
movq %rax, %rdi
callq 0x3e70
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rdi
callq 0x5a30
movq %rax, -0xd8(%rbp)
movq -0xd0(%rbp), %rdi
callq 0x5a60
movq %rax, -0xe0(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
callq 0x5a90
testb $0x1, %al
jne 0x4807
jmp 0x4840
leaq -0xd8(%rbp), %rdi
callq 0x5ad0
movq (%rax), %rax
movq %rax, -0xe8(%rbp)
movq -0xe8(%rbp), %rax
addq -0xc8(%rbp), %rax
movq %rax, -0xc8(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x5af0
jmp 0x47ee
movq -0x138(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rdi
callq 0x31f0
movq %rax, -0xf8(%rbp)
movq -0xf0(%rbp), %rdi
callq 0x3140
movq %rax, -0x100(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x100(%rbp), %rsi
callq 0x5680
testb $0x1, %al
jne 0x4890
jmp 0x4a02
leaq -0xf8(%rbp), %rdi
callq 0x56c0
movb (%rax), %al
movb %al, -0x101(%rbp)
cmpq $0x0, -0xc8(%rbp)
jne 0x48b3
jmp 0x4a02
movq $0x0, -0x110(%rbp)
xorl %eax, %eax
cmpq $0x8, -0x110(%rbp)
movb %al, -0x171(%rbp)
jae 0x48e1
cmpq $0x0, -0xc8(%rbp)
setne %al
movb %al, -0x171(%rbp)
movb -0x171(%rbp), %al
testb $0x1, %al
jne 0x48f0
jmp 0x49ef
movzbl -0x101(%rbp), %eax
movq -0x110(%rbp), %rcx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
andl %ecx, %eax
cmpl $0x0, %eax
je 0x492f
leaq -0xc0(%rbp), %rdi
callq 0x4c10
movq %rax, %rsi
addq $0x10, %rsi
leaq -0xc0(%rbp), %rdi
callq 0x4ba0
jmp 0x494e
leaq -0xc0(%rbp), %rdi
callq 0x4c10
movq %rax, %rsi
addq $0x20, %rsi
leaq -0xc0(%rbp), %rdi
callq 0x4ba0
leaq -0xc0(%rbp), %rdi
callq 0x4c10
movq %rax, %rdi
callq 0x36b0
testb $0x1, %al
jne 0x4968
jmp 0x49d6
leaq -0xc0(%rbp), %rdi
callq 0x4c10
movq -0x138(%rbp), %rdi
movsbl (%rax), %esi
addq $0x20, %rdi
callq 0x3160
jmp 0x4989
movq -0xc8(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0xc8(%rbp)
leaq -0xc0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x4ba0
jmp 0x49d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x18(%rbp)
movl %eax, -0x1c(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x4bd0
leaq -0xb0(%rbp), %rdi
callq 0x4bd0
jmp 0x4a2c
jmp 0x49d8
movq -0x110(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x110(%rbp)
jmp 0x48be
jmp 0x49f1
leaq -0xf8(%rbp), %rdi
callq 0x56e0
jmp 0x4874
leaq -0xc0(%rbp), %rdi
callq 0x4bd0
leaq -0xb0(%rbp), %rdi
callq 0x4bd0
leaq -0x38(%rbp), %rdi
callq 0x53e0
addq $0x180, %rsp            # imm = 0x180
popq %rbp
retq
leaq -0x38(%rbp), %rdi
callq 0x53e0
movq -0x118(%rbp), %rdi
callq 0x5360
movq -0x128(%rbp), %rdi
callq 0x57a0
movq -0x130(%rbp), %rdi
callq 0x3150
movq -0x120(%rbp), %rdi
callq 0x3150
movq -0x18(%rbp), %rdi
callq 0x33d0
nop