/*
 *  dviout for Windows  Ver.3.05.2
 *
 *  plug_in.c: module to use  Susie plug_in
 *             Susie plug_in: DLL which transforms various graphic formats
 *                            into DIB
 *  March 17, 1998  by SHIMA
 */

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#ifdef MSVC
#include <memory.h>
#pragma warning( disable : 4113 )
#else
#include <mem.h>
#endif
#include "inter.h"

#define	REG_SUSIE	"Software\\Takechin\\Susie\\Plug-in"
#define	KEY			"Path"

char *GetOutPath(char *);
void *marea(int);
void Free0(void *);
int read_num(unsigned char *, int);
char *spi;
BOOL SetPath(char *,char *);
int ReadRegString(char *, int, char *, char *, int);

/*
						plug-in
extern "C" int _export PASCAL IsSupported(LPSTR filename,DWORD dw);
extern "C" int _export PASCAL GetPictureInfo(
	LPSTR buf,long len,unsigned int flag,struct PictureInfo *lpInfo);
extern "C" int _export PASCAL GetPicture(
	LPSTR buf,long len,unsigned int flag, HANDLE *pHBInfo,HANDLE *pHBm,
	FARPROC lpPrgressCallback,long lData);
extern "C" int _export PASCAL GetPreview(
	LPSTR buf,long len,unsigned int flag, HANDLE *pHBInfo,HANDLE *pHBm,
	FARPROC lpPrgressCallback,long lData);

						xplug-in
*/


#pragma pack(push)
#pragma pack(1)
typedef struct PictureInfo
{
	long left,top;			/* 画像を展開する位置 */
	long width;				/* 画像の幅(pixel) */
	long height;			/* 画像の高さ(pixel) */
	WORD x_density;			/* 画素の水平方向密度 */
	WORD y_density;			/* 画素の垂直方向密度 */
	short colorDepth;		/* 画素当たりのbit数 */
	HLOCAL hInfo;			/* 画像内のテキスト情報 */
} PictureInfo;
#pragma pack(pop)

static int (__stdcall *IsSupported)(LPSTR filename, DWORD dw);
static int (__stdcall *GetPicture)(LPSTR buf, long len, unsigned int flag, 
	HANDLE *pHBInfo,HANDLE *pHBm, FARPROC lpPrgressCallback, long lData);

static int (__stdcall *GetPluginInfo)(int infono, char *buf, int buflen);
static int (__stdcall *IsXSupported)(int colorDepth);
static int (__stdcall *CreatePicture)(char *filepath, unsigned int flag,
	HANDLE *pHBInfo, HANDLE *pHBm, struct PictureInfo *lpInfo, 
	FARPROC lpPrgressCallback, long lData);

#if	0
static int (__stdcall *GetPictureInfo)(LPSTR buf, long len, unsigned int flag,
	struct PictureInfo *lpInfo);
static int (__stdcall *GetPreview)(LPSTR buf, long len, unsigned int flag, 
	HANDLE *pHBInfo,HANDLE *pHBm, FARPROC lpPrgressCallback, long lData);
#endif

// static char *spi_dll[5];

#define	MAX_TYPE	5


static int __stdcall ProgressCallback(int nNum, int nDenom, long lData)
{
	return 0;
}

void ResolvePath(char *path, char *s)
{
	int len;

	if(s == NULL || !*s)
		s = "^x\\";
	SetPath(path,s);
	len = strlen(path);
	if(len && path[--len] != '\\' && path[len] != '/')
		strcat(path, "\\");
}

int open_plugin(char *fname, int type, char **buf, char **buf_end)
{
#define	TMPSIZE		0x800
#define	PATHSIZE	0x200
#define	reg_path	(tmp+TMPSIZE)

	static HINSTANCE hlib[MAX_TYPE];
	static FARPROC	func[MAX_TYPE][2];
#if 0
	struct PictureInfo lpInfo;
#endif
	FILE *fh;
	HANDLE Info, Bm;
	unsigned char *tmp, *tmp1;
	int size, size1, col, pal, comp, pos, reg_susie;
	WIN32_FIND_DATA	wfd;
	HANDLE hfind32 = NULL;
	unsigned char path[MAX_PATH];
	unsigned char path2[MAX_PATH];

	if(type >= MAX_TYPE)
		return 1;
	if(type < 0){
		for(type = 0; type < MAX_TYPE; type++){
			if(hlib[type]){
				FreeLibrary(hlib[type]);
				hlib[type] = NULL;
			}
		}
		return 0;
	}
	tmp = (unsigned char*)marea(TMPSIZE+PATHSIZE);
	for(size = 0; size < TMPSIZE; )
		tmp[size++] = 0;
	fh = fopen(fname, "rb");
	fread(tmp, TMPSIZE, 1, fh);
	fclose(fh);
	reg_susie = 0;
	if(hlib[type] == NULL){
search_spi:	
		if(hfind32 == NULL){
			ResolvePath(path2, reg_susie?reg_path:spi);
			pos = strlen(path2);
			strcpy(path, path2);
#ifdef _WIN64
			strcat(path, "*.sph");
#else
			strcat(path, "*.spi");
#endif
			if((hfind32 = FindFirstFile(path, &wfd))
			  == INVALID_HANDLE_VALUE)
				goto no_spi;
		}else{
nxt_spi:	if(FindNextFile(hfind32, &wfd) == FALSE){
				FindClose(hfind32);
no_spi:			if(!reg_susie++
				  && ReadRegString(reg_path, PATHSIZE, REG_SUSIE, KEY, 1) == 1){
					hfind32 = NULL;
					goto search_spi;
				}
				Free0(tmp);
				return 1;
			}
			if( (wfd.dwFileAttributes & 
				(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM)) != 0)
					goto nxt_spi;
		}
		strcpy(path2+pos, &(wfd.cFileName[0]));
		if(hlib[type] != NULL)
			FreeLibrary(hlib[type]);
		if((hlib[type] = LoadLibrary(path2)) == NULL)
			goto nxt_spi;
		func[type][0] = GetProcAddress(hlib[type], "IsSupported");
		func[type][1] = GetProcAddress(hlib[type], "GetPicture");
//		func[type][2] = GetProcAddress(hlib[type], "GetPictureInfo");
//		func[type][3] = GetProcAddress(hlib[type], "GetPreview");
	}
	if( (IsSupported = func[type][0]) == NULL
	 || (GetPicture = func[type][1]) == NULL
	 || !(*IsSupported)(fname, (DWORD)tmp))
		goto search_spi;
	else if(hfind32)
		FindClose(hfind32);
	Free0(tmp);
#if 0
	GetPictureInfo = func[type][2];
	(*GetPictureInfo)(fname, 0, 0, &lpInfo);
	if(lpInfo.hInfo)
		GlobalFree(lpInfo.hInfo);
#endif
	if((*GetPicture)(fname, 0, 0, &Info, &Bm, ProgressCallback, 0))
		return 2;
	tmp1 = LocalLock(Bm);
	tmp = LocalLock(Info);
	size= read_num(tmp, 4);
	col = read_num(tmp + 14, 2);
	comp = read_num(tmp + 16, 4);
	size1 = read_num(tmp + 20, 4);
	if(size1 == 0){
		size1 = ((read_num(tmp + 4,4)*col+31)/32)*4;
		size1 *= read_num(tmp + 8,4);
	}
	pal = read_num(tmp + 32, 4);
	if(col < 16 && pal == 0)
		pal = 1<<col;
	if(comp == BI_BITFIELDS && (col == 16 || col == 32))
		pal += 3;
	size += pal*sizeof(RGBQUAD);
	*buf = (unsigned char*)marea(size + size1);
	memcpy(*buf, tmp, size);
	memcpy(*buf+size, tmp1, size1);
	*buf_end = *buf + size + size1;
	LocalUnlock(Bm);
	LocalFree(Bm);
	LocalUnlock(Info);
	LocalFree(Info);
	return 0;
#if 0
	GetPreview = func[type][3];
#endif
}


static HINSTANCE xhlib;

static BOOL GetLibrary(char *xpath, char *type)
{
	char ext[0x20];
	if(access(xpath, 0) || (xhlib = LoadLibrary(xpath)) == NULL)
		return FALSE;

	if(  (GetPluginInfo = GetProcAddress(xhlib, "GetPluginInfo")) != NULL
	  && (IsXSupported = GetProcAddress(xhlib, "IsSupported")) != NULL
	  && (CreatePicture = GetProcAddress(xhlib, "CreatePicture")) != NULL ){
		(*GetPluginInfo)(3, ext, 0x20);
		if(!stricmp(ext, type))
			return TRUE;
	}
	FreeLibrary(xhlib);
	return FALSE;
}


int open_xplugin(char *type, int res)
{
	unsigned char xpath[MAX_PATH];
	unsigned char tpath[0x100];
	int count;

	if(xhlib)
		FreeLibrary(xhlib);
	xhlib = NULL;
	if(type == NULL || strlen(type) > 8)
		return 0;
	for(count = 0; count < 5; count++){
		switch(count){
			case 0:
				ResolvePath(xpath, NULL);
				break;
			case 1:
			case 2:
				if(spi == NULL || strlen(spi) >= 0x100){
					count += 2;
					continue;
				}
				ResolvePath(xpath, spi); 
				goto ext;
				break;
			case 3:
			case 4:
				if(ReadRegString(tpath, 0x100, REG_SUSIE, KEY, 1) != 1){
					count += 2;
					continue;
				}
				ResolvePath(xpath, tpath);
ext:			if(!(count & 1))
					strcat(xpath, "exp_plug\\");
				break;
		}
		sprintf(xpath+strlen(xpath), "ex%s.xpi", type+1);
		if(GetLibrary(xpath, type)){
			while(res <= 32){
				if((*IsXSupported)(res))
					return res;
				if(res >= 32)
					break;
				if(res >= 24){
					res = 32;
					continue;
				}
				if(res >= 16){
					res = 24;
					continue;
				}
				if(res >= 8){
					res = 16;
					continue;
				}
				if(res >= 4){
					res = 8;
					continue;
				}
				res = 4;
			}
			FreeLibrary(xhlib);
			return 0;
		}
	}
	return 0;
}

void SavePicture(char *path, unsigned char *info, unsigned char *data, 
	int width, int height, int depth, char *msg)
{
	char *tmp;
//	int ret;
	struct PictureInfo lpInfo;
	HANDLE hinfo, hdata;

	if(xhlib == NULL)
		return;

	lpInfo.left = lpInfo.top = 0;
	lpInfo.width = width;
	lpInfo.height = height;
	lpInfo.x_density = lpInfo.y_density = 1;
	lpInfo.colorDepth = depth; 
	if(msg){
		tmp = dup_string(msg);
		lpInfo.hInfo = LocalHandle(tmp);
	}else
		lpInfo.hInfo = NULL;
	hinfo = LocalHandle(info);
	hdata = LocalHandle(data);

/*
	error(14, "(%d,%d:%d) %d %d %d", width, height, depth,
		lpInfo.hInfo, hinfo, hdata);
*/
// ret = 
	(*CreatePicture)(path, 0, &hinfo, &hdata, &lpInfo, ProgressCallback, 0);

//	error(14, "%d", ret);
	if(msg)
		Free0(tmp);
}
