#include <windows.h>
#include <stdio.h>

#define DEBUG 0

typedef struct ICStru{
	DWORD	_IC_u01;			/// 0x00 -- (used as byte)
	DWORD	_IC_u02;			/// 0x04 Not used, always 0x00000000
	DWORD	_IC_Type;			/// 0x08 Chip type: 0=""; 1="EEPROM"; 2="MCU/MPU"; 3="PLD/CPLD"; 4="SRAM"; 5="LOGIC"
	char	_IC_Name[0x28];		/// 0x0C Chip name
	DWORD	_IC_u03;			/// 0x34 -- flags? more re needed! (used as byte)
	DWORD	_IC_CodeMemory;		/// 0x38 size of Code memory
	DWORD	_IC_DataMemory;		/// 0x3C size of Data memory
	DWORD	_IC_UserMemory;		/// 0x40 size of User memory ("User.Row" or "Encry.TB")
	WORD	_IC_u04;			/// 0x44
	WORD	_IC_u05;			/// 0x46
	WORD	_IC_u06;			/// 0x48
	byte	_IC_u07;			/// 0x4A
	byte	_IC_u08;			/// 0x4B
	DWORD	_IC_u09;			/// 0x4C
	DWORD	_IC_u10;			/// 0x50
	DWORD	_IC_ChipID;			/// 0x54 Chip ID
	DWORD	_IC_u11;			/// 0x58 Not used, always 0x00000000
	DWORD	_IC_u12;			/// 0x5C
	DWORD	_IC_u13;			/// 0x60
	DWORD	_IC_Package;		/// 0x64 XXXXXXFF - last byte determines the socket/adapter/wiring scheme
	DWORD	_IC_u14;			/// 0x68
} ICStru;

typedef struct MfcStru{
	DWORD	mfc_id;				// Order number of the manufacturer (starts from 1 and determines where the manufacturer will be placed in the dropdown menu)
	DWORD	mfc_logo;			// Manufacturer logo ID. Logos are hardcoded as resources in main executable
	char	mfc_name_short[20];	// Short manufacturer name (eg. "ATMEL", "ALI", etc.)
	char	mfc_name_full[40];	// Full manufacturer name (eg. "Atmel Corporation", "Acer Laboratories Inc", etc.)
	DWORD	mfc_ic_struc;		// Pointer to the ICs structure data
	DWORD	mfc_ic_count;		// Number of ICs for this manufacturer
} MfcStru;

char szInfoIC[] = "InfoIC.mem";	/// InfoIC.dll filename
int baseOfMfc = 0x12AA40;		/// Base adress of Manufacturers, pointing directly to _numberOfMfcs var

int main() {

	HANDLE hFile;
	DWORD fileSize;
	DWORD lpNumberOfBytesRW;
	byte* fileData;
	byte* fileData_t;
	MfcStru mfc;
	ICStru ic;
	int number_of_Mfc;
	int i, j;


	/// Read entire InfoIC.mem data
	hFile = CreateFile(szInfoIC, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("Error opening \"%s\" : %08X\n", szInfoIC, GetLastError());
		return 0;
	}
	fileSize = GetFileSize(hFile, NULL);
	fileData = VirtualAlloc(NULL, fileSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
	ReadFile(hFile, fileData, fileSize, &lpNumberOfBytesRW, NULL);
	CloseHandle(hFile);

	number_of_Mfc = *(DWORD*)&fileData[baseOfMfc];

	if (DEBUG == 0) {
		printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		printf("<InfoIC>\n");
	}

	/// Iterate through manufacturers
	for(i = 0; i < number_of_Mfc; i++) {
		fileData_t = fileData + (baseOfMfc-(number_of_Mfc*sizeof(MfcStru))) + (i*sizeof(MfcStru));
		memcpy(&mfc, fileData_t, sizeof(MfcStru));

		/// Fix the IC data offset, since the original one has ImageBase 0x10000000
		mfc.mfc_ic_struc = mfc.mfc_ic_struc-0x10041000;

		if (DEBUG == 0) {
			/// Print manufacturer tag
			printf("\t<manufacturer logo=\"%d\" name_short=\"%s\" name_full=\"%s\">\n",
				mfc.mfc_logo,
				mfc.mfc_name_short,
				mfc.mfc_name_full
			);
		}

		fileData_t = fileData + mfc.mfc_ic_struc;
		for(j = 0; j < mfc.mfc_ic_count; j++) {
			memcpy(&ic, fileData_t, sizeof(ICStru));

			if (DEBUG == 0) {
				//if (ic._IC_UserMemory != 0x0) {
					printf("\t\t<ic name=\"%s\" type=\"%d\" id=\"0x%08X\" package=\"0x%08X\">\n", ic._IC_Name, ic._IC_Type, ic._IC_ChipID, ic._IC_Package);
					printf("\t\t\t<memory code=\"0x%08X\" data=\"0x%08X\" user=\"0x%08X\"/>\n", ic._IC_CodeMemory, ic._IC_DataMemory, ic._IC_UserMemory);
					printf("\t\t\t<settings u01=\"0x%08X\" u02=\"0x%08X\" u03=\"0x%08X\" u04=\"0x%04X\" u05=\"0x%04X\" u06=\"0x%04X\" u07=\"0x%02X\" u08=\"0x%02X\" u09=\"0x%08X\" u10=\"0x%08X\" u11=\"0x%08X\" u12=\"0x%08X\" u13=\"0x%08X\" u14=\"0x%08X\"/>\n",
						ic._IC_u01, ic._IC_u02, ic._IC_u03, ic._IC_u04, ic._IC_u05, ic._IC_u06, ic._IC_u07, ic._IC_u08, ic._IC_u09, ic._IC_u10, ic._IC_u11, ic._IC_u12, ic._IC_u13, ic._IC_u14
					);
					printf("\t\t</ic>\n");
				//}
			} else {
				printf("%08X\n", ic._IC_u01);
			}
			fileData_t = fileData_t + sizeof(ICStru);
		}
		if (DEBUG == 0) {
			printf("\t</manufacturer>\n");
		}
	}

	if (DEBUG == 0) {
		printf("</InfoIC>\n");
	}

	VirtualFree(fileData, 0, MEM_RELEASE);
	return 0;
}
