/*	
 *	clipfpk.c
 *
 *	ファイルパック形式
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2008 Naoyuki Sawa
 *
 *	* Wed Nov 30 22:35:00 JST 2005 Naoyuki Sawa
 *	- ファイルパック形式、オンメモリファイルパック形式は、利用頻度が低いので、
 *	  コードサイズ節約のために、実装をclipmisc.cからclipfpk.cへ分離しました。
 *	* Wed Aug 06 23:14:45 JST 2008 Naoyuki Sawa
 *	- FilePackユーティリティー(tool/dfpck)が長いファイル名に対応したことに追従し、
 *	  長いファイル名を扱えるように対応しました。
 *	- コードサイズ削減のため、ファイル構造が壊れている場合の対策は行っていません。
 *	  たとえば、FILE_PAC_INFO.fname[]のファイル名がnul終端されていなかったり、
 *	  極端に長過ぎるファイル名でstrcat()がオーバーフローする対策は行っていません。
 */
#include "clip.h"

/*****************************************************************************
 *	ユーティリティ：ファイルパック形式
 *****************************************************************************/

static int
fpk_find(FILE* fp, const char* name, FILE_INFO* fi)
{
	int retval, i;
	FILE_PAC_INFO pi;
//{{2008/08/06:長いファイル名対応:追加
	char fname[256/*_MAX_FNAME*/]; /* 長いファイル名 */
//}}2008/08/06:長いファイル名対応:追加

	/* fpk情報を読みます。 */
	/* 呼び出し時にファイル位置が先頭であること。この関数はrewind()しません。 */
	retval = fread(&pi, 1, sizeof pi, fp);
	if(retval != sizeof pi) DIE();
	if(pi.head != FILE_PAC_INFO_HEAD) DIE(); /* シグネチャ検査 */

	/* ファイル情報を走査して… */
//{{2008/08/06:長いファイル名対応:追加
	fname[0] = '\0'; /* 長いファイル名をリセット */
//}}2008/08/06:長いファイル名対応:追加
	for(i = 0; i < pi.famount; i++) {
		/* ファイル情報を読みます。 */
		retval = fread(fi, 1, sizeof *fi, fp);
		if(retval != sizeof *fi) DIE();

		/* 見つけた？ */
//{{2008/08/06:長いファイル名対応:変更
//		if(strncasecmp(fi->fname, name, sizeof fi->fname) == 0) break;
//↓2008/08/06:長いファイル名対応:変更
		strcat(fname, fi->fname); /* 長いファイル名を連結 */
		if(fi->size) { /* 実エントリ (size>0) */
			if(strcasecmp(fname, name) == 0) break;
			fname[0] = '\0'; /* 長いファイル名をリセット */
		}
//}}2008/08/06:長いファイル名対応:変更
	}

	return i < pi.famount; /* 1:見つけた/0:見つからなかった */
}

int
fpk_size(const char* fname, const char* name)
{
	int retval;
	FILE* fp;
	FILE_INFO fi;

	/* fpkファイルを開きます。 */
	fp = fopen(fname, "rb");
	if(fp == NULL) DIE();

	/* ファイル情報を探します。 */
	retval = fpk_find(fp, name, &fi);
	if(!retval) DIE();

	/* fpkファイルを閉じます。 */
	fclose(fp);

	return fi.size;
}

int
fpk_load(const char* fname, const char* name, void* buffer, int buflen)
{
	int retval;
	FILE* fp;
	FILE_INFO fi;

	/* fpkファイルを開きます。 */
	fp = fopen(fname, "rb");
	if(fp == NULL) DIE();

	/* ファイル情報を探します。 */
	retval = fpk_find(fp, name, &fi);
	if(!retval) DIE();
	if((int)fi.size > buflen) DIE(); /* バッファ不足 */

	/* ファイルを読み込みます。 */
	retval = fseek(fp, fi.offset, SEEK_SET);
	if(retval != 0) DIE();
	retval = fread(buffer, 1, fi.size, fp);
	if(retval != (int)fi.size) DIE();

	/* fpkファイルを閉じます。 */
	fclose(fp);

	return fi.size; /* 読み込んだサイズを返します */
}

/*****************************************************************************
 *	ユーティリティ：オンメモリファイルパック形式
 *****************************************************************************/

const void*
fpk_address(const void* fpk, const char* name, int* size)
{
	int i;
	unsigned char* base;
	FILE_PAC_INFO* pi;
	FILE_INFO* fi;
//{{2008/08/06:長いファイル名対応:追加
	char fname[256/*_MAX_FNAME*/]; /* 長いファイル名 */
//}}2008/08/06:長いファイル名対応:追加

	base = (unsigned char*)fpk;

	/* シグネチャを検査します。 */
	pi = (FILE_PAC_INFO*)(base + 0);
	if(pi->head != FILE_PAC_INFO_HEAD) DIE();

	/* ファイルエントリを探します。 */
//{{2008/08/06:長いファイル名対応:追加
	fname[0] = '\0'; /* 長いファイル名をリセット */
//}}2008/08/06:長いファイル名対応:追加
	fi = (FILE_INFO*)(base + sizeof(FILE_PAC_INFO));
	for(i = 0; i < pi->famount; i++) {
//{{2008/08/06:長いファイル名対応:変更
//		if(strncasecmp(fi->fname, name, sizeof fi->fname) == 0) break;
//↓2008/08/06:長いファイル名対応:変更
		strcat(fname, fi->fname); /* 長いファイル名を連結 */
		if(fi->size) { /* 実エントリ (size>0) */
			if(strcasecmp(fname, name) == 0) break;
			fname[0] = '\0'; /* 長いファイル名をリセット */
		}
//}}2008/08/06:長いファイル名対応:変更
		fi++;
	}
	if(i == pi->famount) DIE();

	/* ファイルサイズを格納します。 */
	if(size) *size = fi->size;

	/* ファイルの先頭アドレスを返します。 */
	return base + fi->offset;
}

