///////////////////////////////////////////////////////////
// BDP-S390 Firmware Modification Code:
//    Binary File Extraction
//--------------------------------------------------------
// Copyright (C) 2013 Malcolm Stagg
///////////////////////////////////////////////////////////

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string.h>

using namespace std;

int main(int argc, char * argv[]) {
	ifstream infile;
	ofstream outfile, outfile2;
	
	if (argc != 2) {
		cout << "Usage: extractfiles [decoded bin input]" << endl;
		exit(1);
	}
	char * infilename = argv[1];
	
	infile.open(infilename, ifstream::binary);
	
	if (!infile) {
		cout << "cannot open input file" << endl;
		exit(1);
	}
	
	//read header
	char binheader[0x200];
	
	infile.read(binheader, 0x200);
	
	//it is actually 0xf0 in the new version, but this is for compatibility since the older ones had larger headers
	
	char mainversion[16];
	char subversion[16];
	char verdate[16];
	char notsure1[16];
	char notsure2[16];
	int notsure3;
	int binfilesize;
	char ifconver[16];
	int notsure4;
	int notsure5;
	int notsure6;
	int notsure7;
	char microbever[16];
	strcpy(mainversion, binheader+0);
	strcpy(subversion, binheader+0x10);
	strcpy(verdate, binheader+0x20);
	strcpy(notsure1, binheader+0x30);
	strcpy(notsure2, binheader+0x38);
	notsure3 = *((int *)(binheader+0x50));
	binfilesize = *((int *)(binheader+0x5C));
	strcpy(ifconver, binheader+0x70);
	notsure4 = *((int *)(binheader+0x80));
	notsure5 = *((int *)(binheader+0x84));
	notsure6 = *((int *)(binheader+0x88));
	notsure7 = *((int *)(binheader+0x8C));
	strcpy(microbever, binheader+0x90);
	
	//subfile locations:
	int fileloc[32], filesize[32];
	int maxend = 0xf0;
	int minstart = 0x00ffffff;
	int numfiles = 0;
	for (int i=0;i<32;i++) {
		fileloc[i] = *((int *)(binheader+0xa0+8*i));
		filesize[i] = *((int *)(binheader+0xa4+8*i));
		if (fileloc[i]+filesize[i]>maxend) maxend=fileloc[i]+filesize[i];
		if (fileloc[i]>=0xf0 && fileloc[i]<minstart) minstart=fileloc[i];
		numfiles++;
		if (0xa8+8*i >= minstart) break;
	}
	
	if (minstart != 0xf0)
		cout << "WARNING: first file should start at 0xf0 but actually starts at " << hex << minstart << endl;
	else if (maxend != binfilesize)
		cout << "WARNING: last file should go to the end of the file (" << binfilesize << ") not " << hex << maxend << endl;
	
	// put this information in a config file for writing back to the header later
	cout << "main version: " << mainversion << endl
	<< "subversion: " << subversion << endl
	<< "version date: " << verdate << endl
	<< "not sure 1: " << notsure1 << endl
	<< "not sure 2: " << notsure2 << endl
	<< "not sure 3: " << hex << notsure3 << endl
	<< "file size: " << binfilesize << endl
	<< "not sure 4-7: " << notsure4 << " " << notsure5 << " " << notsure6 << " " << notsure7 << endl
	<< "microbe version: " << microbever << endl << endl;
	
	//subfile locations:
	for (int i=0;i<numfiles;i++) {
		cout << "FILE " << i << " LOCATION = " << hex << fileloc[i] << " SIZE = " << filesize[i] << endl;
	}
	
	outfile.open("fileheader.txt");
	outfile << mainversion << endl
	<< subversion << endl
	<< verdate << endl
	<< notsure1 << endl
	<< notsure2 << endl
	<< hex << notsure3 << endl
	<< binfilesize << endl
	<< notsure4 << endl
	<< notsure5 << endl
	<< notsure6 << endl
	<< notsure7 << endl
	<< microbever << endl;
	
	for (int i=0;i<numfiles;i++) {
		if (filesize[i]>0) {
			char filename2[16];
			sprintf(filename2, "FILE_%d", i);
			outfile2.open(filename2, ios::binary);
			infile.seekg(fileloc[i], ios::beg);
			char * filedata = (char *)malloc(filesize[i]);
			infile.read(filedata, filesize[i]);
			outfile2.write(filedata, filesize[i]);
			outfile2.close();
			outfile << filename2 << endl;
			free(filedata);
		} else
			outfile << endl;
		outfile << hex << fileloc[i] << endl << filesize[i] << endl;
	}
	
	outfile.close();
	infile.close();
}


