// File: /workspace/github_cpp_makefile_star2_O1/irakr[P]Minimal-File-Compression-Tool/src/compression-driver.cpp
// Function: CompressionDriver::decompress(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&)
void CompressionDriver :: decompress(std::string &ifilename) {
	Log(this, "Started...");
	if(!m_Compressor) {
		Log(this, "[Fatal Error] No compression algorithm registered.");
		return; // FIXME... Throw an exception from here
	}

	std::cout << "Input File: " << ifilename << std::endl;

	// Output filename
	// (XXX) For now this is the auto generated output file name
	std::string ofilename = ifilename + ".orig";

	// TODO ...
	// Open file named 'file'
	// Pass the handle to specific decode() function
	// decode() should return back the decompressed file handle
	std::fstream inputf(ifilename, std::fstream::in | std::fstream::binary);
	if(!inputf.is_open()) {
		std::cerr << "[Error] The file \"" << ifilename << "\" does not exist." << std::endl;
		return;
	}
	
	fsize_t file_size = getFileSize(inputf);
    std::cout << "Size: " << file_size << " bytes" << std::endl;
    
	// Read bytes from input file
	byte *in_data_byte_buff = new byte[file_size + 1];
	inputf.read((char*)in_data_byte_buff, file_size);
	in_data_byte_buff[file_size] = 0; // Append null at the end because read() doesn't
	//std::cout << "file_buff: " << in_data_byte_buff << std::endl;

	// Get the compressed byte stream
	byte* decompressed_buff = m_Compressor->decoder().decode(in_data_byte_buff, &file_size);
	if(!decompressed_buff) {
	    // TODO... Cleanup code like should be placed somewhere else systematically.
	    Logf(this, "Error: Invalid file format.");
	    delete[] in_data_byte_buff;
	    inputf.close();
	    return;
	}
	std::cout << "Decompressed size = " << file_size << " bytes" << std::endl;

	// Open output file. The size will be obviously less than or impossibly
	// equal to the input file size;
	// Then write the compressed byte stream to it.
	std::fstream outputf;
	outputf.open(ofilename, std::fstream::out | std::fstream::binary);
	outputf.write((const char*)decompressed_buff,
		file_size);

	inputf.close();
	outputf.close();
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x448, %rsp            # imm = 0x448
cmpq $0x0, 0x38(%rdi)
je 0x3feb
movq %rsi, %r14
movq %rdi, %rbx
movq 0x52ce(%rip), %r15      # 0x8fc0
leaq 0x246c(%rip), %rsi      # 0x6165
movl $0xc, %edx
movq %r15, %rdi
callq 0x2200
movq (%r14), %rsi
movq 0x8(%r14), %rdx
movq %r15, %rdi
callq 0x2200
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x21c0
movsbl %al, %esi
movq %r15, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2150
leaq 0x18(%rsp), %r12
movq %r12, -0x10(%r12)
movq (%r14), %rsi
movq 0x8(%r14), %rdx
addq %rsi, %rdx
leaq 0x8(%rsp), %r15
movq %r15, %rdi
callq 0x3612
leaq 0x2450(%rip), %rsi      # 0x61b7
movq %r15, %rdi
callq 0x2350
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
movl $0xc, %edx
callq 0x22f0
leaq 0xa8(%rsp), %r15
movq %r15, %rdi
callq 0x2090
testb %al, %al
je 0x3f4d
movq %r15, %rdi
callq 0x2090
movq $-0x1, %r14
testb %al, %al
je 0x3dd8
leaq 0x28(%rsp), %rdi
xorl %esi, %esi
movl $0x2, %edx
callq 0x2270
leaq 0x28(%rsp), %rdi
callq 0x2310
movq %rax, %r14
leaq 0x28(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2270
movq %r14, (%rsp)
movq 0x51dd(%rip), %rdi      # 0x8fc0
leaq 0x23ac(%rip), %rsi      # 0x6196
movl $0x6, %edx
callq 0x2200
movq (%rsp), %rsi
movq 0x51c1(%rip), %rdi      # 0x8fc0
callq 0x21b0
movq %rax, %r14
leaq 0x238f(%rip), %rsi      # 0x619d
movl $0x6, %edx
movq %rax, %rdi
callq 0x2200
movq (%r14), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x21c0
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2150
movq (%rsp), %r15
leaq 0x1(%r15), %rdi
callq 0x2030
movq %rax, %r14
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
movq %r15, %rdx
callq 0x2230
movq %rsp, %rdx
movq (%rdx), %rax
movb $0x0, (%r14,%rax)
movq 0x38(%rbx), %rax
movq 0x48(%rax), %rdi
movq (%rdi), %rax
movq %r14, %rsi
callq *(%rax)
movq %rax, %rbx
testq %rax, %rax
je 0x3fb8
movq 0x5130(%rip), %rdi      # 0x8fc0
leaq 0x234b(%rip), %rsi      # 0x61e2
movl $0x14, %edx
callq 0x2200
movq (%rsp), %rsi
movq 0x5114(%rip), %rdi      # 0x8fc0
callq 0x21b0
movq %rax, %r14
leaq 0x22e2(%rip), %rsi      # 0x619d
movl $0x6, %edx
movq %rax, %rdi
callq 0x2200
movq (%r14), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x21c0
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2150
leaq 0x238(%rsp), %rdi
callq 0x2210
leaq 0x238(%rsp), %rdi
leaq 0x8(%rsp), %rsi
movl $0x14, %edx
callq 0x2280
leaq 0x248(%rsp), %rdi
movq (%rsp), %rdx
movq %rbx, %rsi
callq 0x2250
leaq 0x28(%rsp), %rdi
callq 0x2050
leaq 0x238(%rsp), %rdi
callq 0x2050
leaq 0x238(%rsp), %rdi
callq 0x2080
jmp 0x3fca
movq 0x509c(%rip), %rdi      # 0x8ff0
leaq 0x2262(%rip), %rsi      # 0x61bd
movl $0x12, %edx
callq 0x2200
movq (%r14), %rsi
movq 0x8(%r14), %rdx
movq 0x507d(%rip), %rdi      # 0x8ff0
callq 0x2200
movq %rax, %rbx
leaq 0x224e(%rip), %rsi      # 0x61d0
movl $0x11, %edx
movq %rax, %rdi
callq 0x2200
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21c0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2150
jmp 0x3fca
movq %r14, %rdi
callq 0x2240
leaq 0x28(%rsp), %rdi
callq 0x2050
leaq 0x28(%rsp), %rdi
callq 0x2080
movq 0x8(%rsp), %rdi
cmpq %r12, %rdi
je 0x3feb
movq 0x18(%rsp), %rsi
incq %rsi
callq 0x21f0
addq $0x448, %rsp            # imm = 0x448
popq %rbx
popq %r12
popq %r14
popq %r15
retq
jmp 0x401b
jmp 0x401b
jmp 0x4000
movq %rax, %rbx
jmp 0x4028
movq %rax, %rbx
leaq 0x238(%rsp), %rdi
callq 0x2080
jmp 0x401e
jmp 0x401b
jmp 0x401b
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x2080
movq 0x8(%rsp), %rdi
cmpq %r12, %rdi
je 0x403f
movq 0x18(%rsp), %rsi
incq %rsi
callq 0x21f0
movq %rbx, %rdi
callq 0x2320
nop