//----------------------------------------------------------------------
/*
 *	PokemonDP メッセージデータ暗号化
 */
//----------------------------------------------------------------------

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

typedef unsigned short u16;
typedef unsigned int   u32;


typedef struct {
	u16  numMsgs;
	u16  randValue;
}MSG_HEADER;

typedef struct {
	u32  offset;
	u32  len;
}MSG_PARAM;



static void* read_data( const char* filepath, int* size )
{
	FILE* fp = fopen(filepath, "rb");
	if( fp )
	{
		void *buf;

		fseek( fp, 0, SEEK_END );
		*size = ftell(fp);
		fseek( fp, 0, SEEK_SET );

		buf = malloc( *size );
		if( buf )
		{
			fread( buf, *size, 1, fp );
		}
		return buf;
	}
	return NULL;
}

static int write_data( void* dat, const char* filepath, int size )
{
	FILE* fp = fopen( filepath, "wb" );
	if( fp )
	{
		fwrite( dat, size, 1, fp );
		fclose( fp );
		return 1;
	}
	return 0;
}


//------------------------------------------------------
/*
 *	暗号サブ（文字列部）
 */
//------------------------------------------------------
static void encode_str( u16* str, u16 len, u32 id, u16 rand )
{
	rand = (id + 1) * 596947;
	while(len--)
	{
		*str ^= rand;
		str++;
		rand += 18749;
	}
}
//------------------------------------------------------
/*
 *	暗号サブ（パラメータ部）
 */
//------------------------------------------------------
static void encode_param( MSG_PARAM* param, u32 id, u16 rand )
{
	u32 rand_mask;

	rand = (rand * ((id + 1) * 765)) & 0xffff;
	rand_mask = (rand<<16) | rand;

	param->offset ^= rand_mask;
	param->len ^= rand_mask;
}
//------------------------------------------------------
/*
 *	暗号メイン
 */
//------------------------------------------------------
static void encode( void* data )
{
	MSG_HEADER* header = (MSG_HEADER*)data;
	MSG_PARAM* param = (MSG_PARAM*)(((char*)data) + sizeof(MSG_HEADER));
	int i;
	u16* str;

	for(i=0; i<header->numMsgs; i++)
	{
		str = (u16*)( (char*)data + param->offset );
		encode_str( str, param->len, i, header->randValue );
		encode_param( param, i, header->randValue );
		param++;
	}
}


//------------------------------------------------------
/*
 *	復号サブ（文字列部）
 */
//------------------------------------------------------
static void decode_str( u16* str, u16 len, u32 id, u16 rand )
{
	encode_str( str, len, id, rand );
}
//------------------------------------------------------
/*
 *	復号サブ（パラメータ部）
 */
//------------------------------------------------------
static void decode_param( MSG_PARAM* param, u32 id, u16 rand )
{
	encode_param( param, id, rand );
}
//------------------------------------------------------
/*
 *	復号メイン
 */
//------------------------------------------------------
static void decode( void* data )
{
	MSG_HEADER* header = (MSG_HEADER*)data;
	MSG_PARAM* param = (MSG_PARAM*)(((char*)data) + sizeof(MSG_HEADER));
	int i;
	u16* str;

	for(i=0; i<header->numMsgs; i++)
	{
		decode_param( param, i, header->randValue );
		str = (u16*)( (char*)data + param->offset );
		decode_str( str, param->len, i, header->randValue );
		param++;
	}
}







int main(int argc, char** argv )
{
	if( argc != 2 && argc != 3)
	{
		printf("usage:>msgenc [-d] <datfile>\n");
		printf("[-d] つけると復号モード\n");
		printf("<datfile> 暗号化したいメッセージデータファイル\n");
		return 1;
	}
	else
	{
		int size;
		void *dat;
		const char* filename;

		filename = ( argc == 2 )? argv[1] : argv[2];
		dat = read_data( filename, &size );

		if( dat == NULL )
		{
			printf("%s を読み込めない\n", filename);
			return 1;
		}

		if( argc == 2 )
		{
			encode( dat );
		}
		else
		{
			decode( dat );
		}

		if( write_data( dat, filename, size ) == 0 )
		{
			printf("%s に書き込めない\n", filename);
			return 1;
		}
	}

	return 0;
}
