#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>

#define		ver		"0.01"

struct {
    char	id[ 6 ] ;
    char	name[ 8 ] ;
    char	x[ 1 ] ;
    char	y[ 1 ] ;
    char	type[ 1 ] ;
} Header ;
int		Num_font = 0 ;
int		Size_font = 0 ;
long		Size_dll = 0 ;		/* DLLのフォント領域のサイズ */
char		FontID[16] = "" ;
char		FontName[16] = "" ;
long		pos_han = 0, pos_tbl = 0, pos_zen = 0 ;
long		size_han = 0, size_tbl = 0, size_zen = 0 ;

int
read_header( FILE *fp )
{
    if ( fread( &Header, sizeof Header, 1, fp ) != 1 ) {
	return 0 ;
    }
    memcpy( FontID, Header.id, 6 ) ;		FontID[6] = 0 ;
    memcpy( FontName, Header.name, 8 ) ;	FontName[8] = 0 ;
    Size_font = ((0xFF & Header.x[0]) + 7) / 8 * (0xFF & Header.y[0]) ;
    return 1 ;
}

int
find_dll_data( FILE *fp, int tagidx )
{
    int		c, num = 0 ;
    char	buf[ 5 ], tag[ 5 ] ;
    static char	*tagadd[] = { "HAN", "TBL", "ZEN" } ;

    fseek( fp, 0L, SEEK_SET ) ;
    memset( buf, 0, sizeof buf ) ;
    memcpy( tag, "X2", 2 ) ;
    memcpy( &tag[2], tagadd[ tagidx ], 3 ) ;
    c = fgetc( fp ) ;
    while ( !feof( fp ) ) {
	memcpy( buf, &buf[1], sizeof buf - 1 ) ;
	buf[ sizeof buf - 1 ] = c ;
	if ( !memcmp( buf, tag, sizeof buf ) ) {
	    if ( fread( buf, 3, 1, fp ) != 1 ) {
		return 0 ;
	    }
	    buf[ 3 ] = 0 ;
	    sscanf( buf, " %x", &num ) ;
	    Size_dll = 256L * num ;
	    return 1 ;
	}
	c = fgetc( fp ) ;
    }
    return 0 ;
}

int
read_table( FILE *src, FILE *dst )
{
    int			ret, i ;
    char		buf[ 10 ] ;
    unsigned short	range[ 2 ] ;

    ret = fgetc( src ) ;
    if ( ret == EOF ) {
	printf( "Error: can't read font data\n" ) ;
	return 0 ;
    }
    if ( (long) ret > size_tbl / 3L ) {
	printf( "Error: too large font table(%d)\n", ret ) ;
	return 0 ;
    }
    Num_font = 0 ;
    buf[0] = ret % 256 ;
    buf[1] = ret / 256 ;
    buf[2] = 0 ;
    buf[3] = 0 ;
    fseek( dst, 0L, SEEK_CUR ) ;
    if ( fwrite( buf, 4, 1, dst ) != 1 ) {
	printf( "Error: can't write dll data\n" ) ;
	return 0 ;
    }
    for ( i = 0 ; i < ret ; i ++ ) {
	if ( fread( range, sizeof range, 1, src ) != 1 ) {
	    printf( "Error: can't read font data\n" ) ;
	    return 0 ;
	}
	buf[0] = range[0] % 256 ;
	buf[1] = range[0] / 256 ;
	buf[2] = range[1] % 256 ;
	buf[3] = range[1] / 256 ;
	buf[4] = Num_font % 256 ;
	buf[5] = Num_font / 256 ;
	fseek( dst, 0L, SEEK_CUR ) ;
	if ( fwrite( buf, 6, 1, dst ) != 1 ) {
	    printf( "Error: can't write dll data\n" ) ;
	    return 0 ;
	}
	Num_font += range[1] - range[0] + 1 ;
    }
    return 1 ;
}

const unsigned char ConvTable[] = {
	0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,
	8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,
	4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,
	12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,
	2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,
	10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,
	6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,
	14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,
	1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,
	9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,
	5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,
	13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,
	3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,
	11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,
	7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,
	15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255,
} ;

char	srcbuf[ 256 ] ;
char	dstbuf[ 256 ] ;

int
read_data( FILE *src, FILE *dst )
{
    int		i, j ;
    char	*ptr ;

    /* DLLデータのヘッダー部書き込み */
    ptr = srcbuf ;
    *ptr++ = Header.x[0] ;
    *ptr++ = Header.y[0] ;
    *ptr++ = Size_font ;
    memset( ptr, 0, 5 ) ;		ptr += 5 ;
    memcpy( ptr, Header.name, 8 ) ;	ptr += 8 ;
    if ( fwrite( srcbuf, 16, 1, dst ) != 1 ) {
	printf( "Error: can't write dll data\n" ) ;
	return 0 ;
    }
    /* DLLデータのフォントデータ書き込み */
    for ( i = 0 ; i < Num_font ; i ++ ) {
	if ( fread( srcbuf, Size_font, 1, src ) != 1 ) {
	    printf( "Error: can't read font data\n" ) ;
	    return 0 ;
	}
	for ( j = 0 ; j < Size_font ; j ++ ) {
	    dstbuf[ j ] = ConvTable[ 0xFF & srcbuf[ j ] ] ;
	}
	fwrite( dstbuf, Size_font, 1, dst ) ;
    }
    return 1 ;
}

char	buf[ 1024 ] ;

void
help( char *appname, char *dllorg, char *dllname )
{
    printf( "%s V%s -- Font Setup Program for KCTRL.DLL\n", appname, ver ) ;
    printf( "Copyright (C) Eiichiroh Itoh. 1997. All rights reserved.\n\n" ) ;
    printf( "Usage:\n\n" ) ;
    printf( "\t%s 半角フォントファイル名 全角フォントファイル名\n\n",
	    appname ) ;
    printf( "\t注意：フォントは両方同時に指定してください。\n" ) ;
    printf( "\t　　　また、%sと同じディレクトリで実行して下さい。\n",
	    dllorg ) ;
    printf( "\t　　　実行後カレントディレクトリに%sが作成されていれば\n",
	    dllname ) ;
    printf( "\t　　　変換は成功です。\n" ) ;
    printf( "\t　　　成功後%sをＨＰＣの/Windowsフォルダに転送して下さい。\n",
	    dllname ) ;
}

int
main( int argc, char *argv[] )
{
    int		i, ret, f_han = 0, f_zen = 0 ;
    char	*dllorg = "KCTRLFNT.ORG" ;
    char	*dllfile = "KCTRLFNT.DLL" ;
    FILE	*font, *dorg, *dll ;

    if ( argc < 3 ) {
	help( "SETKCTRL", dllorg, dllfile ) ;
	return 99 ;
    }
    dorg = fopen( dllorg, "rb" ) ;
    if ( dorg == NULL ) {
	printf( "Error: can't find %s.\n", dllorg ) ;
	return 99 ;
    }
    /* DLLのデータ領域を探す */
    printf( "Finding data area of %s\n", dllorg ) ;

    if ( !find_dll_data( dorg, 0 ) ) {
	printf( "Error: can't find a HANKAKU-AREA of %s.\n",
	        dllorg ) ;
	fclose( dorg ) ;
	return 98 ;
    }
    pos_han = ftell( dorg ) ;
    size_han = Size_dll ;
    if ( !find_dll_data( dorg, 1 ) ) {
	printf( "Error: can't find a TABLE-AREA of %s.\n",
	        dllorg ) ;
	fclose( dorg ) ;
	return 98 ;
    }
    pos_tbl = ftell( dorg ) ;
    size_tbl = Size_dll ;
    if ( !find_dll_data( dorg, 2 ) ) {
	printf( "Error: can't find a ZENTAKU-AREA of %s.\n",
	        dllorg ) ;
	fclose( dorg ) ;
	return 98 ;
    }
    pos_zen = ftell( dorg ) ;
    size_zen = Size_dll ;
    printf( "  DLL Info:han=%lX-%lX(%lx),tbl=%lX-%lX(%lx),zen=%lX-%lX(%lx)\n",
	    pos_han, pos_han + size_han - 1, size_han,
	    pos_tbl, pos_tbl + size_tbl - 1, size_tbl,
	    pos_zen, pos_zen + size_zen - 1, size_zen ) ;
    /* 書き込み先ファイルをオープンする */
    dll = fopen( dllfile, "w+b" ) ;
    if ( dll == NULL ) {
	printf( "Error: can't create %s.\n", dllfile ) ;
	fclose( dorg ) ;
	return 99 ;
    }
    /* KCTRLFNT.ORG を KCTRLFNT.DLL にコピーする */
    printf( "Copying %s to %s.,,\n", dllorg, dllfile ) ;

    fseek( dorg, 0L, SEEK_SET ) ;
    ret = fread( buf, 1, sizeof buf, dorg ) ;
    while ( ret ) {
	fwrite( buf, 1, ret, dll ) ;
	if ( ret != sizeof buf ) {
	    break ;
	}
	ret = fread( buf, 1, sizeof buf, dorg ) ;
    }
    /* KCTRLFNT.ORG をクローズする */
    fclose( dorg ) ;
    /* FontX2ファイルを読み込む */
    for ( i = 1 ; i < argc ; i ++ ) {
	char	*fontfile = argv[ i ] ;

	font = fopen( fontfile, "rb" ) ;
	if ( font == NULL ) {
	    printf( "Error: can't find %s.\n", fontfile ) ;
	    goto error ;
	}
	printf( "Parsing %s...\n", fontfile ) ;
	if ( !read_header( font ) ) {
	    printf( "Error: can't read header.\n" ) ;
	    fclose( font ) ;
	    goto error ;
	}
	if ( strcmp( FontID, "FONTX2" ) ) {
	    printf( "Error: invalid font(ID=%s).\n", FontID ) ;
	    fclose( font ) ;
	    goto error ;
	}
	if ( Header.type[0] ) {
	    f_zen = 1 ;
	    fseek( dll, pos_tbl, SEEK_SET ) ;
	    if ( !read_table( font, dll ) ) {
		fclose( font ) ;
		goto error ;
	    }
	    fseek( dll, pos_zen, SEEK_SET ) ;
	    Size_dll = size_zen ;
	} else {
	    f_han = 1 ;
	    fseek( dll, pos_han, SEEK_SET ) ;
	    Num_font = 256 ;
	    Size_dll = size_han ;
	}
	printf( "  Font Info:name=%s,num=%d,size=%d\n",
	        FontName, Num_font, Size_font ) ;
	if ( (long) Num_font * (long) Size_font > Size_dll ) {
	    printf( "Error: too large font\n" ) ;
	    fclose( font ) ;
	    goto error ;
	}
	if ( !read_data( font, dll ) ) {
	    fclose( font ) ;
	    goto error ;
	}
	fclose( font ) ;
    }
    if ( !f_han ) {
	printf( "Error: can't find HANKAKU-FONT\n" ) ;
	goto error ;
    }
    if ( !f_zen ) {
	printf( "Error: can't find ZENKAKU-FONT\n" ) ;
	goto error ;
    }
    fclose( dll ) ;
    return 0 ;

error:
    fclose( dll ) ;
    unlink( dllfile ) ;
    return 97 ;
}
