// File: irakr[P]Minimal-File-Compression-Tool/src/huffman-encoder.cpp
// Function: HuffmanEncoder::encode(unsigned char*, long*)
byte* HuffmanEncoder :: encode(byte *in_buff, fsize_t *buff_len) {
	Log(this, "Started...");

	m_inBuffSize = *buff_len;

	// This will hold bytes of the compressed data;
	// Header + content
	byte *out_buff = NULL;

	try {
		// All the 3 statements below must be in this sequence only.
		buildFrequencyTable(in_buff);			// (OK)
		buildHuffmanTree();						// (OK)
		buildCodewordTable();					// (OK)
	}
	catch(std::exception &e) {
		std::cerr << e.what() << std::endl
			<< "[.......Rethrowing exception]" << std::endl;
		throw (new std::exception(e));
	}

	// Build the file header.
	HeaderStruct header;
	build_header(&header, *m_codewordTable);
	header.header_size = get_header_size(&header);
	header.original_size = m_inBuffSize;
	header.compressed_size = get_compressed_size(&header, *m_frequencyTable);
	
	// Build the compressed data(payload)
	size_t out_size = header.header_size + header.compressed_size + PREFIX_LEN;
	
	// If compression not useful.
	if(out_size >= m_inBuffSize)
	    return NULL;
	// Else continue encoding...
	out_buff = new byte[out_size];
	::memcpy((byte*)out_buff, (byte*)PREFIX_STR, PREFIX_LEN);
	
	dump_header(&header, out_buff + PREFIX_LEN);
    dump_content(&header, in_buff, *buff_len, out_buff + header.header_size);
	
	// Return compressed file buffer and its size.
	*buff_len = out_size;
	return out_buff;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movq %rdi, -0x78(%rbp)
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq %rax, 0x28(%rdi)
movq $0x0, -0x28(%rbp)
movq -0x18(%rbp), %rsi
callq 0x3980
jmp 0x374d
movq -0x78(%rbp), %rdi
callq 0x3b40
jmp 0x3758
movq -0x78(%rbp), %rdi
callq 0x3d10
jmp 0x3763
jmp 0x3892
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl -0x34(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x3960
movq -0x30(%rbp), %rdi
callq 0x30e0
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movq %rax, %rsi
movq 0x10848(%rip), %rdi     # 0x13ff0
callq 0x3200
movq %rax, -0x80(%rbp)
jmp 0x37b3
movq -0x80(%rbp), %rdi
movq 0x107e2(%rip), %rsi     # 0x13fa0
callq 0x3230
movq %rax, -0x88(%rbp)
jmp 0x37cc
movq -0x88(%rbp), %rdi
leaq 0x9891(%rip), %rsi      # 0xd06b
callq 0x3200
movq %rax, -0x90(%rbp)
jmp 0x37e8
movq -0x90(%rbp), %rdi
movq 0x107aa(%rip), %rsi     # 0x13fa0
callq 0x3230
jmp 0x37fd
movl $0x8, %edi
movq %rdi, -0xa8(%rbp)
callq 0x3110
movq -0xa8(%rbp), %rdi
movq %rax, -0xa0(%rbp)
callq 0x3210
movq %rax, -0x98(%rbp)
jmp 0x382a
movq -0x98(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x43e0
movq -0x98(%rbp), %rax
movq -0xa0(%rbp), %rdi
movq %rax, (%rdi)
leaq 0x103f6(%rip), %rsi     # 0x13c48
xorl %eax, %eax
movl %eax, %edx
callq 0x33b0
jmp 0x3971
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x3886
movq -0xa0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x3180
callq 0x3390
jmp 0x388d
jmp 0x3960
movq -0x78(%rbp), %rax
movq 0x40(%rax), %rsi
leaq -0x68(%rbp), %rdi
callq 0xa8c0
leaq -0x68(%rbp), %rdi
callq 0xa870
movq %rax, %rcx
movq -0x78(%rbp), %rax
movl %ecx, -0x68(%rbp)
movq 0x28(%rax), %rcx
movq %rcx, -0x60(%rbp)
movq 0x30(%rax), %rsi
leaq -0x68(%rbp), %rdi
callq 0xaac0
movq -0x78(%rbp), %rcx
movq %rax, -0x58(%rbp)
movslq -0x68(%rbp), %rax
addq -0x58(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
cmpq 0x28(%rcx), %rax
jb 0x38f7
movq $0x0, -0x8(%rbp)
jmp 0x3953
movq -0x70(%rbp), %rdi
callq 0x3030
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movl 0x971a(%rip), %ecx      # 0xd028
movl %ecx, (%rax)
movq -0x28(%rbp), %rsi
addq $0x4, %rsi
leaq -0x68(%rbp), %rdi
callq 0xac10
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rax
movq (%rax), %rdx
movq -0x28(%rbp), %rcx
movslq -0x68(%rbp), %rax
addq %rax, %rcx
leaq -0x68(%rbp), %rdi
callq 0xad10
movq -0x70(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, (%rax)
movq -0x28(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0xb0, %rsp
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x33e0
movq %rax, %rdi
callq 0x4400
nopw %cs:(%rax,%rax)