// InfoIC.dll extractor from http://www.nullsecurity.org/i/showoff/parse_InfoIC.c
// Modified to be POSIX C and to work with v6.7.1 of the software
// TL866II Plus DLL has a slightly different structure


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define DEBUG 0

typedef struct ICStru{
	uint32_t	_IC_u01;			/// 0x00 -- (used as uint8_t)
	uint32_t	_IC_u02;			/// 0x04 Not used, always 0x00000000
	uint32_t	_IC_Type;			/// 0x08 Chip type: 0=""; 1="EEPROM"; 2="MCU/MPU"; 3="PLD/CPLD"; 4="SRAM"; 5="LOGIC"
	uint8_t	_IC_Name[0x28];		/// 0x0C Chip name
	uint32_t	_IC_u03;			/// 0x34 -- flags? more re needed! (used as uint8_t)
	uint32_t	_IC_CodeMemory;		/// 0x38 size of Code memory
	uint32_t	_IC_DataMemory;		/// 0x3C size of Data memory
	uint32_t	_IC_UserMemory;		/// 0x40 size of User memory ("User.Row" or "Encry.TB")
	uint16_t	_IC_u04;			/// 0x44
	uint16_t	_IC_u05;			/// 0x46
	uint16_t	_IC_u06;			/// 0x48
	uint8_t	_IC_u07;			/// 0x4A
	uint8_t	_IC_u08;			/// 0x4B
	uint32_t	_IC_u09;			/// 0x4C
	uint32_t	_IC_u10;			/// 0x50
	uint32_t	_IC_ChipID;			/// 0x54 Chip ID
	uint32_t	_IC_u11;			/// 0x58 Not used, always 0x00000000
	uint32_t	_IC_u12;			/// 0x5C
	uint32_t	_IC_u13;			/// 0x60
	uint32_t	_IC_Package;		/// 0x64 XXXXXXFF - last uint8_t determines the socket/adapter/wiring scheme
	uint32_t	_IC_u14;			/// 0x68
} ICStru;

typedef struct MfcStru{
	uint32_t	mfc_id;				// Order number of the manufacturer (starts from 1 and determines where the manufacturer will be placed in the dropdown menu)
	uint32_t	mfc_logo;			// Manufacturer logo ID. Logos are hardcoded as resources in main executable
	uint8_t	mfc_name_short[20];	// Short manufacturer name (eg. "ATMEL", "ALI", etc.)
	uint8_t	mfc_name_full[40];	// Full manufacturer name (eg. "Atmel Corporation", "Acer Laboratories Inc", etc.)
	uint32_t	mfc_ic_struc;		// Pointer to the ICs structure data
	uint32_t	mfc_ic_count;		// Number of ICs for this manufacturer
} MfcStru;

char szInfoIC[] = "InfoIC.dll";	/// InfoIC.dll filename
//int baseOfMfc = 0x12AA40;		/// Base adress of Manufacturers, pointing directly to _numberOfMfcs var
//int baseOfMfc = 0x188320; /// Correct value for v6.71
int baseOfMfc = 0x1892B8; // v6.85

int main() {

	FILE *hFile;
	uint32_t fileSize;
	uint8_t* fileData;
	uint8_t* fileData_t;
	MfcStru mfc;
	ICStru ic;
	int number_of_Mfc;
	int i, j;
  int err;


	/// Read entire InfoIC.mem data
  hFile = fopen(szInfoIC, "rb");
  
	if (hFile == NULL) {
		printf("Error opening \"%s\"\n", szInfoIC);
		return 1;
	}
  
  fseek(hFile, 0, SEEK_END);
  fileSize = ftell(hFile);
  fseek(hFile, 0, SEEK_SET);
  
  fileData = malloc(fileSize);
  if(fileData == NULL) {
    printf("Error allocating memory!\n");
    return 1;
  }
  
  err = fread(fileData, fileSize, 1, hFile);
  if(err != 1) {
    printf("Error copying file data!\n");
    return 1;
  }
  
  fclose(hFile);

	number_of_Mfc = *(uint32_t*) & 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-0x10000000;

		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");
	}

  free(fileData);
	return 0;
}
