///////////////////////////////////////////////////////////
// BDP-S390 Firmware Modification Code:
//    Binary Sub-file Insertion for Sony Format
//--------------------------------------------------------
// Copyright (C) 2013 Malcolm Stagg
///////////////////////////////////////////////////////////

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

//it looks like the partition information is safe unless the file is modified to be too large to fit in the partition
//bit information must be changed in multiple places (BIT tables are linked to other tables through their file system)
//i.e. these are some kind of FATs

//for FILE_4

using namespace std;

typedef struct _binaryinfo {
	char name[17];
	char typeinfo[16];
	int pid;
	int binoffs;
	int binsize;
	int poffs;
	int info;
} binaryinfo;

typedef struct _partitioninfo {
	char name[17];
	int id;
	int protection;
	int flashloc;
	int flashsize;
} partitioninfo;


typedef struct _spaceinfo {
	int start;
	int size;
	int free;
} spaceinfo;

partitioninfo * partinfolist[16];
binaryinfo * bininfolist[16];
int numbin[16] = {};
int numpart[16] = {};
int numblock = 0;

int pitstarts[16];
int pitloc;

int haswarning=0;

//pointers of addresses to change
vector<int> pointerLoc;
vector<int> pointerVal;
//pointers of sizes to change
vector<int> fsizeLoc;

int ptrchecksum=-1;

int findmagic(int magicnum, int countneeded, ifstream &infile) {
	int curint;
	infile.read((char *)&curint, 4);
	int i=0;
	int magiccount = 0;
	int addr1 = 0;
	while (infile) {
		if (curint == magicnum)
			magiccount++;
		else
			magiccount=0;
		if (magiccount==countneeded) {
			addr1 = infile.tellg();
			return addr1;
		}
		infile.read((char *)&curint, 4);
	}
	return -1;
}

void checkBinOverlap() {
	list<spaceinfo> spacelist;
	for (int i=0;i<numblock;i++) {
		for (int j=0;j<numbin[i];j++) {
			spaceinfo si;
			int found = 0;
			si.free = 0;
			si.start = bininfolist[i][j].binoffs;
			si.size = bininfolist[i][j].binsize;
			for (list<spaceinfo>::iterator it = spacelist.begin();it!=spacelist.end();it++) {
				if (it->start>=si.start && it->start<si.start+si.size || 
				si.start>=it->start && si.start<it->start+it->size) {
					//these overlap:
					found = 1;
					if (it->free) {
						//it's free space, doesn't matter
						//change this to taken though and make sure it's big enough to hold the whole thing
						int beforesize = si.start - it->start;
						int aftersize = (it->start+it->size)-(si.start+si.size);
						if (beforesize<0 || aftersize<0) {
							cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous binary position detected!\n\n";
							haswarning=1;
						} else {
							*it = si;
							spaceinfo si_before, si_after;
							if (beforesize>0) {
								si_before.start = si.start-beforesize;
								si_before.size = beforesize;
								si_before.free = 1;
								spacelist.insert(it, si_before);
							}
							if (aftersize>0) {
								si_after.start = si.start+si.size;
								si_after.size = aftersize;
								si_after.free = 1;
								it++;
								spacelist.insert(it, si_after);
							}
						}
					} else if (it->start!=si.start || it->size!=si.size) {
						cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous binary position detected!\n\n";
						haswarning = 1;
					}
					break;
				}
			}
			if (!found) {
				int beforesize;
				if (spacelist.empty())
					beforesize = si.start;
				else
					beforesize = si.start-(spacelist.back().start+spacelist.back().size);
				if (beforesize<0) {
					cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous binary position detected!\n\n";
					haswarning = 1;
				} else {
					spaceinfo si_before;
					if (beforesize>0) {
						si_before.start = si.start-beforesize;
						si_before.size = beforesize;
						si_before.free = 1;
						spacelist.push_back(si_before);
					}
					spacelist.push_back(si);
				}
			}
		}	
	}
	cout << "binary usage table:\n";
	for (list<spaceinfo>::iterator it = spacelist.begin();it!=spacelist.end();it++) {
		cout << "@ " << hex << it->start << " size " << it->size << " free " << it->free << endl;
		if (it->free && it->size>=0x10) {
			int foundPIT=0;
			for (int i=0;i<numblock;i++)
				if (pitstarts[i]==it->start && it->size<=0x1000) {
					cout << "[bit table]\n";
					foundPIT=1;
					break;
				}
			if (!foundPIT) {
				cout << "WARNING: unallocated binary space @ " << it->start << " found\n";
				haswarning = 1;
			}
		}
	}
}

void checkPartOverlap() {
	for (int i=0;i<numblock;i++) {
		
		//partitions are blockwise!
		list<spaceinfo> spacelist;
		
		for (int j=0;j<numbin[i];j++) {
			int curpid = bininfolist[i][j].pid;
			int foundPID = -1;
			for (int k=0;k<numpart[i];k++) {
				if (partinfolist[i][k].id == curpid)
					foundPID = k;
			}
			if (foundPID<0) {
				cout << "WARNING: partition " << curpid << " was not found (" << bininfolist[i][j].name << ") in block " << i << " entry " << j << "!\n";
				haswarning = 1;
			} else {
				if (partinfolist[i][foundPID].flashsize < bininfolist[i][j].poffs+bininfolist[i][j].binsize) {
					cout << "WARNING: partition " << curpid << " is not big enough to hold file " << bininfolist[i][j].name;
					haswarning = 1;
				}
				
				int found = 0;
				spaceinfo si;
				si.free = 0;
				si.start = partinfolist[i][foundPID].flashloc+bininfolist[i][j].poffs;
				si.size = bininfolist[i][j].binsize;
				
				for (list<spaceinfo>::iterator it = spacelist.begin();it!=spacelist.end();it++) {
					if (it->start>=si.start && it->start<si.start+si.size || 
					si.start>=it->start && si.start<it->start+it->size) {
						//these overlap:
						found = 1;
						if (it->free) {
							//it's free space, doesn't matter
							//change this to taken though and make sure it's big enough to hold the whole thing
							int beforesize = si.start - it->start;
							int aftersize = (it->start+it->size)-(si.start+si.size);
							if (beforesize<0 || aftersize<0) {
								cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous partition position detected on block " << i 
								<< " (free space before: " << beforesize << " after: " << aftersize << ")!\n\n";
								haswarning = 1;
							} else {
								*it = si;
								spaceinfo si_before, si_after;
								if (beforesize>0) {
									si_before.start = si.start-beforesize;
									si_before.size = beforesize;
									si_before.free = 1;
									spacelist.insert(it, si_before);
								}
								if (aftersize>0) {
									si_after.start = si.start+si.size;
									si_after.size = aftersize;
									si_after.free = 1;
									it++;
									spacelist.insert(it, si_after);
								}
							}
						} else {
							if (it->start!=si.start || it->size!=si.size) {
								cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous partition position detected on block " << i
								<< " (used: " << it->start << " size " << it->size << ", @ " << si.start << " size " << si.size
								<< ")\n\n";
								haswarning = 1;
							}
						}
						break;
					}
				}
				if (!found) {
					int beforesize;
					if (spacelist.empty())
						beforesize = si.start;
					else
						beforesize = si.start-(spacelist.back().start+spacelist.back().size);
					if (beforesize<0) {
						cout << "WARNING: file " << bininfolist[i][j].name << " ambiguous partition position detected!\n\n";
						haswarning = 1;
					} else {
						spaceinfo si_before;
						if (beforesize>0) {
							si_before.start = si.start-beforesize;
							si_before.size = beforesize;
							si_before.free = 1;
							spacelist.push_back(si_before);
						}
						spacelist.push_back(si);
					}
				}
			}
		}
		cout << "partition usage table for block " << i << ":\n";
		for (list<spaceinfo>::iterator it = spacelist.begin();it!=spacelist.end();it++) {
			cout << "@ " << hex << it->start << " size " << it->size << " free " << it->free << endl;
		}
	}
}

void parseBIT2(int addr1, int addr2, ifstream &infile, int indx, int offset) {
	cout << "BINARY INFO TABLE(2) FOUND AT ADDRESS " << hex << addr1 << endl;
	infile.seekg(addr1, ios::beg);
	int i=0;
	int unk1, unk2;
	infile.read((char *)&unk1, 4);
	infile.read((char *)&unk2, 4);
	addr1+=8;
	cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
	
	int sizeElement, numElement;
	infile.read((char *)&sizeElement, 4);
	infile.read((char *)&numElement, 4);
	addr1+=8;
	cout << "sizeElement (should be 40) = " << hex << sizeElement << " numElement = " << numElement << endl;
	
	
	for (int k=0;k<sizeElement/8-3;k++) {
		infile.read((char *)&unk1, 4);
		infile.read((char *)&unk2, 4);
		addr1+=8;
		if (unk1 != 0 || unk2 != 0)
			cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
	}
	
	while (i < numElement) {
		char name[17];
		int pid, poffs, binsize, encid[4], unk1, unk2;
		infile.read(name, 16); name[16]=0;
		infile.read((char *)&pid, 4);
		infile.read((char *)&unk1, 4);
		infile.read((char *)&poffs, 4);
		infile.read((char *)&binsize, 4);
		infile.read((char *)&encid[0], 4);
		infile.read((char *)&encid[1], 4);
		infile.read((char *)&encid[2], 4);
		infile.read((char *)&encid[3], 4);
		cout << i << ": name = " << name << hex << " pid = " << pid
		<< " unknown1 = " << unk1 << " poffs = " 
		<< poffs << " binsize = " << binsize << " encid = " 
		<< encid[0] << " " << encid[1] << " " << encid[2] << " " << encid[3] 
		<< endl;
		
		for (int k=0;k<sizeElement/8-6;k++) {
			infile.read((char *)&unk1, 4);
			infile.read((char *)&unk2, 4);
			if (unk1 != 0 || unk2 != 0)
				cout << "......unknown1 (should be 0) = " << hex << unk1 << " unknown2 (should be 0) = " << unk2 << endl;
		}
		
		int found = -1;
		for (int k=0;k<numbin[indx];k++) {
			if (bininfolist[indx][k].pid == pid && bininfolist[indx][k].poffs == poffs) {
				found = k;
				break;
			}
		}
		if (found<0) {
			numbin[indx]++;
			bininfolist[indx] = (binaryinfo *)realloc(bininfolist[indx], numbin[indx]*sizeof(binaryinfo));
			found = numbin[indx]-1;
			bininfolist[indx][found].binoffs = -1;
			bininfolist[indx][found].info = -1;
			bininfolist[indx][found].binsize = binsize;
			bininfolist[indx][found].pid = pid;
			bininfolist[indx][found].poffs = poffs;
		} else {
			if (bininfolist[indx][found].binoffs == offset)
				fsizeLoc.push_back(addr1+28);
		}
		if (bininfolist[indx][found].name[0] && strcmp(bininfolist[indx][found].name, name)!=0) {
			cout << "WARNING: file name inconsistency found for " << name << " / " << bininfolist[indx][found].name << endl;
			haswarning = 1;
		}
		strcpy(bininfolist[indx][found].name, name);
		if (binsize != bininfolist[indx][found].binsize) {
			cout << "WARNING: inconsistency found for binary file size of " << name << ": " << binsize 
			<< " vs " << bininfolist[indx][found].binsize << "!!!\n\n\n";
			haswarning = 1;
		}
			
		addr1 += sizeElement;
		i++;
	}
	
	infile.read((char *)&unk1, 4);
	infile.read((char *)&unk2, 4);
	addr1+=8;
	cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
	
	infile.read((char *)&unk1, 4);
	infile.read((char *)&unk2, 4);
	addr1+=8;
	cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
}

void parseBIT(int addr1, int addr2, ifstream &infile, int indx, int offset) {
	cout << "BINARY INFO TABLE FOUND AT ADDRESS " << hex << addr1 << endl;
	infile.seekg(addr1, ios::beg);
	addr2-=20;
	int i=0;
	int oBIT2[256];
	int numBIT2=0;
	numbin[indx] = (addr2-addr1)/20;
	bininfolist[indx] = (binaryinfo *)malloc(numbin[indx] * sizeof(binaryinfo));
	while (addr1<addr2) {
		int partid, offsetfile, binsize, offsetpart, bininfo;
		infile.read((char *)&partid, 4);
		infile.read((char *)&offsetfile, 4);
		infile.read((char *)&binsize, 4);
		infile.read((char *)&offsetpart, 4);
		infile.read((char *)&bininfo, 4);
		cout << i << ": pid = " << hex << partid << " offsf = " << offsetfile
		<< " size = " << binsize << " offsp = " << offsetpart << " info = " << bininfo << endl;
		int curaddr = infile.tellg();
		infile.seekg(offsetfile, ios::beg);
		int begword;
		infile.read((char *)&begword, 4);
		cout << " : " << hex << begword << endl; // this is the magic number
		
		if (offsetfile == offset) {
			fsizeLoc.push_back(addr1+8);
		} else if (offsetfile > offset) {
			pointerLoc.push_back(addr1+4);
			pointerVal.push_back(offsetfile);
		}
		
		bininfolist[indx][i].typeinfo[0] = 0;
		if (begword == 0x8530AFBE) {
			oBIT2[numBIT2]=offsetfile;
			numBIT2++;
			strcpy(bininfolist[indx][i].typeinfo, " [BinInfoTab]");
		} else if (begword == 0x474e5089)
			strcpy(bininfolist[indx][i].typeinfo, " [PNG Image]");
		else if (begword == 0x73717368)
			strcpy(bininfolist[indx][i].typeinfo, " [SquashFS]");
		else if (begword == 0x56190527)
			strcpy(bininfolist[indx][i].typeinfo, " [uImage]");
		
		
		bininfolist[indx][i].name[0] = 0;
		bininfolist[indx][i].pid = partid;
		bininfolist[indx][i].binoffs = offsetfile;
		bininfolist[indx][i].binsize = binsize;
		bininfolist[indx][i].binsize = binsize;
		bininfolist[indx][i].poffs = offsetpart;
		bininfolist[indx][i].info = bininfo;
		
		infile.seekg(curaddr, ios::beg);
		addr1 += 20;
		i++;
	}
	
	//now go through and parse the file tables
	for (i=0;i<numBIT2;i++) {
		infile.seekg(oBIT2[i], ios::beg);
		addr1 = findmagic(0x8530AFBE, 2, infile);
		if (addr1 != oBIT2[i] + 8)
			cout << "INVALID BIT(2) BLOCK" << endl;
		else 
			parseBIT2(addr1, addr1+256, infile, indx, offset);
	}
}

void parsePIT2(int addr1, int addr2, ifstream &infile, int indx, int offset) {
	cout << "PARTITION INFO TABLE(2) FOUND AT ADDRESS " << hex << addr1 << endl;
	infile.seekg(addr1, ios::beg);
	int i=0;
	int unk1, unk2;
	infile.read((char *)&unk1, 4);
	infile.read((char *)&unk2, 4);
	addr1+=8;
	cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
	
	int sizeElement, numElement;
	infile.read((char *)&sizeElement, 4);
	infile.read((char *)&numElement, 4);
	addr1+=8;
	cout << "sizeElement (should be 40) = " << hex << sizeElement << " numElement = " << numElement << endl;
	
	for (int k=0;k<sizeElement/8-3;k++) {
		infile.read((char *)&unk1, 4);
		infile.read((char *)&unk2, 4);
		addr1+=8;
		if (unk1 != 0 || unk2 != 0)
			cout << "unknown1 (should be 0) = " << hex << unk1 << " unknown2 (should be 0) = " << unk2 << endl;
	}
	partinfolist[indx] = (partitioninfo *)malloc(numElement * sizeof(partitioninfo));
	numpart[indx] = numElement;
	while (i < numElement) {
		char name[17];
		int pid, flashloc, flashsize, protection, unk1, unk2;
		infile.read(name, 16); name[16]=0;
		infile.read((char *)&pid, 4);
		infile.read((char *)&unk1, 4);
		infile.read((char *)&flashloc, 4);
		infile.read((char *)&flashsize, 4);
		infile.read((char *)&protection, 4);
		infile.read((char *)&unk2, 4);
		cout << i << ": name = " << name << hex << " pid = " << pid
		<< " unknown1 = " << unk1 << " flashloc = " 
		<< flashloc << " flashsize = " << flashsize 
		<< " protection = " << protection << " unknown2 = " << unk2 << endl;
		
		strcpy(partinfolist[indx][i].name, name);
		partinfolist[indx][i].id = pid;
		partinfolist[indx][i].protection = protection;
		partinfolist[indx][i].flashloc = flashloc;
		partinfolist[indx][i].flashsize = flashsize;
	
		for (int k=0;k<sizeElement/8-5;k++) {
			infile.read((char *)&unk1, 4);
			infile.read((char *)&unk2, 4);
			if (unk1 != 0 || unk2 != 0)
				cout << "......unknown1 (should be 0) = " << hex << unk1 << " unknown2 (should be 0) = " << unk2 << endl;
		}
		
		addr1 += sizeElement;
		i++;
	}	
}

void parsePIT(int addr1, int addr2, ifstream &infile, int offset) {

	int oPIT2[256];
	int sPIT2[256];
	int oBIT[256];
	int sBIT[256];

	cout << "PARTITION INFO TABLE FOUND AT ADDRESS " << hex << addr1 << endl;
	infile.seekg(addr1, ios::beg);
	addr2-=16;
	int i=0;
	int unk1, unk2;
	infile.read((char *)&unk1, 4);
	infile.read((char *)&unk2, 4);
	addr1+=8;
	cout << "unknown1 = " << hex << unk1 << " unknown2 = " << unk2 << endl;
	while (addr1<addr2) {
		int flashloc, binoffsPIT2, sizePIT2, flashid, binoffsBIT, sizeBIT, unk1, unk2;
		infile.read((char *)&flashloc, 4);
		infile.read((char *)&binoffsPIT2, 4);
		infile.read((char *)&sizePIT2, 4);
		infile.read((char *)&flashid, 4);
		infile.read((char *)&binoffsBIT, 4);
		infile.read((char *)&sizeBIT, 4);
		infile.read((char *)&unk1, 4);
		infile.read((char *)&unk2, 4);
		cout << i << ": flashloc = " << hex << flashloc 
		<< " binoffsPIT2 = " << binoffsPIT2 << " sizePIT2 = " 
		<< sizePIT2 << " flashid = " << flashid << " binoffsBIT = " 
		<< binoffsBIT << " sizeBIT = " << sizeBIT 
		<< " unknown1 (should be 0) = " << unk1 
		<< " unknown2 (should be 0) = " << unk2 << endl;
		
		if (binoffsPIT2>offset) {
			pointerLoc.push_back(addr1+4);
			pointerVal.push_back(binoffsPIT2);
		}
		
		if (binoffsBIT>offset) {
			pointerLoc.push_back(addr1+16);
			pointerVal.push_back(binoffsBIT);
		}
		
		sPIT2[i] = sizePIT2;
		oPIT2[i] = binoffsPIT2;
		sBIT[i] = sizeBIT;
		oBIT[i] = binoffsBIT;
		
		addr1 += 32;
		i++;
	}
	
	int ict = i;
	
	numblock = ict;
	
	for (i=0; i<ict; i++) {
		cout << "PIT ENTRY " << i << ": ***************************" << endl;
		//parse PIT entry
		infile.seekg(oPIT2[i], ios::beg);
		addr1 = findmagic(0x8530EADC, 2, infile);
		if (addr1 != oPIT2[i] + 8)
			cout << "INVALID PIT(2) BLOCK" << endl;
		else
			parsePIT2(addr1, oPIT2[i]+sPIT2[i], infile, i, offset);
		
		//parse BIT
		infile.seekg(oBIT[i], ios::beg);
		addr1 = findmagic(0x8530ABCD, 5, infile);
		if (addr1 != oBIT[i] + 20)
			cout << "INVALID BIT BLOCK" << endl;
		else {
			addr2 = findmagic(0x8530EFEF, 5, infile);
			if (addr2 != oBIT[i]+sBIT[i])
				cout << "INVALID BIT END BLOCK" << endl;
			else
				parseBIT(addr1, addr2, infile, i, offset);
		}
		pitstarts[i] = oBIT[i];
	}
		
}

int changeFileSize(int offset, int oldlen, int filelen) {
	int roundedupold = ((oldlen+15)>>4)<<4;
	int roundedupnew = ((filelen+15)>>4)<<4;
	
	int diffposition = roundedupnew-roundedupold;

	for (int i=0;i<numblock;i++) {
		for (int j=0;j<numbin[i];j++) {
			if (bininfolist[i][j].binoffs == offset)
				bininfolist[i][j].binsize = filelen;
			else if (bininfolist[i][j].binoffs > offset)
				bininfolist[i][j].binoffs += diffposition;
		}
	}
	return diffposition;
}

int main(int argc, char * argv[]) {
	ifstream infile, infile_ins;
	fstream outfile;
	
	if (argc != 5) {
		cout << "Usage: insertsubfile [file to insert] [offset] [FILE_4] [FILE_4_MOD]" << endl << endl;
		cout << "  offset corresponds to binary file offset of file to replace       " << endl;
		exit(1);
	}
	char * infilename_ins = argv[1];
	int offset = atoi(argv[2]);
	char * infilename = argv[3];
	char * outfilename = argv[4];
	
	infile.open(infilename, ifstream::binary);
	infile_ins.open(infilename_ins, ifstream::binary);
	
	if (!infile || !infile_ins) {
		cout << "cannot open input file" << endl;
		exit(1);
	}
	
	outfile.open(outfilename, fstream::out | fstream::binary);
	
	if (!outfile) {
		cout << "cannot open output file" << endl;
		exit(1);
	}
	
	//get size of insert file
	infile_ins.seekg(0, ios::end);
	int filelen = infile_ins.tellg();
	infile_ins.seekg(0, ios::beg);

	infile.seekg(0, ios::end);
	int filelen_orig = infile.tellg();
	infile.seekg(0, ios::beg);
	
	int addr1, addr2;
	
	infile.seekg(0, ios::beg);
	addr1 = findmagic(0x50495469, 2, infile);
	
	if (addr1>=0) {
		pitloc = addr1-8;
		addr2 = findmagic(0x69544950, 4, infile);
		if (addr2>=0) {
			parsePIT(addr1, addr2, infile, offset);
		} else {
			cout << "PARTITION INFO TABLE NOT FOUND!" << endl;
			exit(1);
		}
	} else {
		cout << "PARTITION INFO TABLE NOT FOUND!" << endl;
		exit(1);
	}
	
	int foundi=-1, foundj;
	for (int i=0;i<numblock;i++) {
		for (int j=0;j<numbin[i];j++) {
			if (bininfolist[i][j].binoffs == offset) {
				foundi = i;
				foundj = j;
				break;
			}
		}
	}
	
	if (foundi>=0) {
		char yn;
		cout << "\n\nThis will replace " << bininfolist[foundi][foundj].name 
			<< " offset " << bininfolist[foundi][foundj].binoffs
			<< " size " << bininfolist[foundi][foundj].binsize 
			<< " in the file... continue? (y/n)" << endl;
		cin >> yn;
		if (yn != 'y' && yn != 'Y') exit(1);
	} else {
		cout << "ERROR: A file was not found at the specified offset!!!\n";
		exit(1);
	}

	int oldlen = bininfolist[foundi][foundj].binsize;
	
	//write up to offset
	infile.seekg(0, ios::beg);
	char * filedata = (char *)malloc(4096);
	if (!filedata) {
		cout << "ERROR: Cannot allocate array!!!\n";
		exit(1);
	}
	for (int i=0;i<offset;i+=4096) {
		infile.read(filedata, (offset-i<4096?offset-i:4096));
		outfile.write(filedata, (offset-i<4096?offset-i:4096));
	}
	//copy new file
	infile_ins.seekg(0, ios::beg);
	for (int i=0;i<filelen;i+=4096) {
		infile_ins.read(filedata, (filelen-i<4096?filelen-i:4096));
		outfile.write(filedata, (filelen-i<4096?filelen-i:4096));
	}
	//0-15 bytes of 0xFF
	int curszF = filelen & 0xF;
	if (curszF != 0) {
		char val = 0xFF;
		for (;curszF<=0xF;curszF++)
			outfile.write(&val, 1);
	}
	//write rest of file (offset+old size to end)
	int newoffset=offset+(((oldlen+15)>>4)<<4);
	infile.seekg(newoffset, ios::beg);
	for (int i=newoffset;i<filelen_orig;i+=4096) {
		infile.read(filedata, (filelen_orig-i<4096?filelen_orig-i:4096));
		outfile.write(filedata, (filelen_orig-i<4096?filelen_orig-i:4096));
	}
	free(filedata);
	
	infile.seekg(pitloc, ios::beg);
	int curint1 = -1, curint2;
	do {
		addr1 = findmagic(0x53526F58, 1, infile);
		if (addr1<0) break;
		infile.read((char *)&curint1, 4);
		infile.read((char *)&curint2, 4);
	} while (infile && curint2 != 0x586F5253);
	
	if (infile)
		ptrchecksum = addr1;
	
	
	int diffposition = changeFileSize(offset, oldlen, filelen);	
	
	//display a nice little table now...
	cout << endl << endl;
	for (int i=0;i<numblock;i++) {
		cout << "BLOCK " << i << endl;
		for (int j=0;j<numpart[i];j++) {
			cout << "  PART " << j << ": " << partinfolist[i][j].name 
			<< " pid " << partinfolist[i][j].id
			<< " pro " << partinfolist[i][j].protection
			<< " flc " << partinfolist[i][j].flashloc
			<< " fsz " << partinfolist[i][j].flashsize << endl;
			for (int k=0;k<numbin[i];k++) {
				if (bininfolist[i][k].pid != partinfolist[i][j].id) continue;
				cout << "    " << bininfolist[i][k].name << bininfolist[i][k].typeinfo  
				<< " (offs " << bininfolist[i][k].binoffs
				<< ", size " << bininfolist[i][k].binsize
				<< ") pofs " << bininfolist[i][k].poffs
				<< " info " << bininfolist[i][k].info << endl;
			}
		}
	}
	
	for (int i=0;i<numblock;i++) {
		free(partinfolist[i]);
		free(bininfolist[i]);
	}
	
	infile.close();
	infile_ins.close();
	
	//pointers to locations that need to change
	for (int i=0;i<pointerLoc.size();i++) {
		int ploc = pointerLoc[i]>offset?pointerLoc[i]+diffposition:pointerLoc[i];
		int pval = pointerVal[i]+diffposition;
		outfile.seekp(ploc, ios::beg);
		outfile.write((char *)&pval, 4);
	}
	//pointers to sizes that need to change
	for (int i=0;i<fsizeLoc.size();i++) {
		int ploc = fsizeLoc[i]>offset?fsizeLoc[i]+diffposition:fsizeLoc[i];
		int pval = filelen;
		outfile.seekp(ploc, ios::beg);
		outfile.write((char *)&pval, 4);
	}
	
	if (ptrchecksum >= 0) {	
		int ploc = ptrchecksum>offset?ptrchecksum+diffposition:ptrchecksum;
		int pval = 0;
		outfile.seekp(ploc, ios::beg);
		outfile.write((char *)&pval, 4);
		
		outfile.close();
		outfile.clear();
		outfile.open(outfilename, fstream::in | fstream::out | fstream::binary);
		
		if (!outfile) {
			cout << "Cannot reopen output!\n";
			exit(1);
		}
	
		unsigned char chksum[4];
		for (int i=0;i<4;i++)
			chksum[i]=0;
		
		unsigned char c1;
		outfile.seekg(0, ios::beg);
		c1 = outfile.get();
		int i=0;
		while (outfile) {
			i%=4;
			chksum[i] ^= c1;
			c1 = outfile.get();
			i++;
		}
		outfile.clear();
		
		if (!outfile) {
			cout << "Cannot reopen output!\n";
			exit(1);
		}
		
		chksum[0] ^= 0x53^0x58^0xFF;
		chksum[1] ^= 0x52^0x6F^0xFF;
		chksum[2] ^= 0x6F^0x52^0xFF;
		chksum[3] ^= 0x58^0x53^0xFF;
		
		outfile.seekp(ploc, ios::beg);
		outfile.write((char *)chksum, 4);
		
		outfile.close();
	}
}

