/*!
//********************
//d金魚のソース破棄場 第二処理施設。warning:Those are TRASH codes!!
//第一処理施設はtrash_code.htmlです。
//LastUpDate 16:49 2004/05/22 ファイルパッキング入門
16:01 2004/05/22 まとめ役残骸
21:45 2004/03/23 CreateDirectory SJISに対応させようとしたもの残骸
28:94 2004/03/22 ランキングタイマークラス(仕様が駄目な為廃棄)を追加
20:40 2004/02/27 ワークスペースベースを追加 since 2002/12/7
20:59 2004/01/30 自称、メモリ効率の良いBulletMLRunnerの残骸
20:59 2004/01/18 smart_resource_handle残骸
22:42 2004/01/17 リソースマネージャインターフェイス残骸
14:02 2003/12/27 レジスト理系
13:09 2003/12/26 Zlib Encoder Decoder 追加・・・(bug..bug..
23:04 2003/11/18: INIManagerを追加。(上手く、エラーチェックが出来ない。
22:17 2003/11/15 INIOperatorを追加。

*/



//**********************************************************
//ファイルパッキング入門
//**********************************************************

bool HashCompare( Hash_Adapter_Interface *p,const char *f1,const char *f2){
	scoped_buffer_byte h1,h2;
	h1.reset(p->hash_size());
	h2.reset(p->hash_size());
	
	p->FileToSignature(f1,h1.get(),h1.size());
	p->FileToSignature(f2,h2.get(),h2.size());
	
	if(h1 == h2){
		return true;
	}
	return false;
}

void FolderCompare(const char *folder1,const char *folder2,bool f=true){
	file_listupper a1,a2;
	a1.reset("*.*",folder1,f);
	a2.reset("*.*",folder2,f);

	a1.find();
	a2.find();

	SHA1_Adapter sa;

	file_listupper::iterator i1,i2;
	i1 = a1.begin();
	for(;i1 != a1.end();i1++){
		bool findflag = false;
		for(i2 = a2.begin();i2 != a2.end();i2++){
			if((*i1)==(*i2)){
				findflag = true;
				if(false==HashCompare(&sa,(*i1).c_str(),(*i2).c_str())){
					dODS("合わないなり");
				}
			}
		}
		if(false==findflag){
			dODS("%s not found",(*i1).c_str());
		}
	}
}


void FilePackTester(array_process_interface *face){
	
	
	FilePack a;
	//const char *name="ok.pack";
	char name[dkcdMAXPATH];
	char folder[dkcdMAXPATH];
	char folder2[dkcdMAXPATH];
	if(false==FolderSelect(folder,sizeof(folder),"Packするフォルダを選択してください。")){
		return;
	}
	std::string dir = folder;

	bool r = FileSaveDialog(name,sizeof(name),"保存するファイル名を入力してください。",
		"ファイルパック(*.pack)\0*.pack\0All files(*.*)\0*.*\0\0",
		"DKUT Original File Pack 形式");

	if(false==r){
		return ;
	}

	typedef dkutil::policy::lzss_compress lzss;
	{
		path_string path = name;

		a.open(path.filename().c_str()
			,path.directory().c_str(),
			NULL,false);
	}
	file_listupper up;
	up.reset("*.*",dir.c_str(),true);
	up.find();

	//登録
	{
		file_listupper::iterator it=up.begin();
		for(;it != up.end();it++)
		{
			/*if(GetFileSizeMini((*it)) > 1024 * 1024)
			{//大きいファイルは受け付けない。
		
				dODS(std::string("でかすぎるんだよ!:") + (*it));
				continue;
			}*/

			path_string path= (*it);
			
			a.registFile(path.filename().c_str(),(*it).c_str());
			dODS((*it).c_str());
		}
	}
	
	a.saveFile(name,true);

	dODS("//--解凍開始----------------");
	if(false==FolderSelect(folder2,sizeof(folder2),"解凍するフォルダを選んでください。")){
		return;
	}
	{
		path_string path = name;

		a.open(path.filename().c_str()
			,path.directory().c_str(),
			NULL,true);
	}
	

	//解凍
	{
		file_listupper::iterator it=up.begin();
		for(;it != up.end();it++)
		{
			
			
			ODS(std::string( (*it) + "  ").c_str());
			
			path_string path = (*it);

			std::string s = folder2;
			DirectoryPlusFileName(s,path.filename());

			if(false==a.loadFileToFile( path.filename().c_str(),s.c_str(),true ))
			{
				char buff[2048]="";
				a.getErrorString(buff,sizeof(buff));
				dODS(buff);
			}else{
				dODS("");
			}
		}
	}
	FolderCompare(folder,folder2,true);

}

/*!
ファイル構造
header
file * header::file_num
データ部 * header::file_num
*/
//#error エンコーダとデコーダを分けるか?問題点はregistしたものがファイルかメモリかを見分けられない所だ。
class FilePack : public filepack_interface{
public:

	struct file_info{
		file_info(ULONGLONG originsize,ULONGLONG offs,ULONGLONG encodedsize,UINT crcc,
			BYTE *p,size_t size,const char* filename) : 
			originfilesize(originsize) , offset(offs) , mEncodedSize(encodedsize)
		{
			mData.reset(size);
			if(p){
				dkmemcpy(mData.get(),mData.size(),p,size);
			}
			if(filename){
				mFileReserved = filename;
			}
			crc = crcc;
		}
		file_info(){}
		typedef file_info self_type;
		
		file_info(const self_type &x){
			*this = x;
		}

		self_type &operator=(const self_type &x){
			originfilesize = x.originfilesize;
			offset = x.offset;
			mEncodedSize = x.mEncodedSize;
			mData = x.mData;
			mFileReserved = x.mFileReserved;
			crc = x.crc;
			return (*this);
		}

		///ファイルサイズ(元サイズ)
		ULONGLONG originfilesize;
		///ファイル先頭からデータ部までのオフセット
		ULONGLONG offset;
		///エンコード済みサイズ
		ULONGLONG mEncodedSize;
		///ファイルのコンバート済みデータ等
		scoped_buffer_byte mData;
		///このファイルをPackするよ領域
		std::string mFileReserved;
		
		///crc用
		UINT crc;
		bool empty()const{
			return mData.size()==0;
		}
		void clear(){
			mData.clear();
			mFileReserved.clear();
			originfilesize = 0;
			offset = 0;
			mEncodedSize = 0;
			crc = 0;
		}
		BYTE *get_data(){
			return mData.get();
		}
		size_t get_data_size(){
			return mData.size();
		}
		std::string filename(){
			return mFileReserved;
		}

	};
	/*               ファイル名  ファイル情報*/
	typedef map_ex<std::string,file_info> FILE_HEADER_MAP;

	typedef filepack_interface base_type;
	enum def{
		//eFileSigSize = 128,
		eVersion = 1,
	};
	struct header{
		///バージョン情報(決まり文句・・・?)
		UINT version;
		///ファイル数
		ULONGLONG file_num;
	};
	struct file{
		///ファイル名
		char filename[ dkcdMAXPATH];
		///ファイルサイズ
		ULONGLONG originfilesize;
		///エンコード済みサイズ
		ULONGLONG encodedsize;
		///オフセット(ファイルの先頭から)
		ULONGLONG offset;
		///crc32left
		UINT crc32left;
		//SHA1のシグネチャ
		//ULONG option;
		//BYTE signature[eSigSize];
	};
	typedef CRC_Adapter<policy::crc32_left> CRC_TYPE;
	bool set_file_info(file *p,ULONGLONG offset,parm_string filename,parm_string signature){
		int r = dkstrcpy( p->filename,sizeof(p->filename),signature.c_str(),signature.size());
		if(DKUTIL_FAILED(r)){
			setErrorStr("signature文字列のコピーに失敗しました。");
			return false;
		}
		if(false==GetFileSize(filename.c_str(),&p->originfilesize)){
			setErrorStr("ファイルのサイズ取得に失敗しました。");
			return false;
		}
		CRC_TYPE crc;
		if(false==crc.FileToSignature(filename,&p->crc32left)){
			setErrorStr("CRCの設定に失敗しました。");
			return false;
		}
		p->offset = offset;
		return true;
	}

private:

	///ファイルヘッダの情報格納
	FILE_HEADER_MAP mHM;

	throw_file_operator mOp;
	///ファイル名(すべてのパス要素を合わせた奴
	std::string mFilename;
	///ターゲットファイル名
	std::string mTargetFile;
	///ターゲットディレクトリ
	std::string mTargetDir;
	///コンバート済みファイルデータをキャッシュするオプション
	cache_option mCache;
	///スマポ コンヴァートルール
	sptr<array_process_interface> mRule;
	///てんぷらり(爆)バッファサイズ
	size_t mTempSize;
	///CRCクラス
	CRC_TYPE mCRC;
	///エラー文字列格納バッファ
	std::string mErrorStr;
protected:
	bool open_op2(){
		if(false==mOp.open()){
			setErrorStr("ファイルをオープンできませんでした。");
			return false;
		}
		return true;
	}
	bool open_op(parm_string filename,bool isread){
		if(isread){
			mOp.reset(filename.c_str(),"rb");
			DKUTIL_RETURN_FALSE(open_op2());

			int re = analyze_header(mHM);
			if(DKUTIL_FAILED(re)){
				setErrorStr("ファイルヘッダを解析できませんでした。");
				return false;
			}
		}else{
			mOp.reset(filename.c_str(),"wb");
			DKUTIL_RETURN_FALSE(open_op2());
		}
		return true;
	}
	bool close_op(){
		mOp.close();
		return true;
	}
	void setErrorStr(parm_string str){
		mErrorStr = str.c_str();
		}
	void setErrorStr(parm_string filename,parm_string str){
		setErrorStr(
			std::string(filename.c_str()) + 
			std::string("  ") + 
			std::string(str.c_str())
		);
		}
	/*!
	@return 同じキーがアーカイブ内にあった場合はedk_LogicError(チートされてるんか?
	*/
	int analyze_header(FILE_HEADER_MAP &ma){
		mOp.seek(0,SEEK_SET);
		
		//ヘッダロード
		header h;
		
		mOp.read(&h,sizeof(h));

		//ファイルのヘッダロード
		{
			file f={0};
			std::string str;
			for(ULONGLONG i=0;i<h.file_num;i++){
				mOp.read(&f,sizeof(f));
				UINT crc = f.crc32left;
				///ファイル名の安全なコピー
				string_copy(str,f.filename,sizeof(f.filename));
				///データをセット
				if(false==ma.SetData(
					str,file_info(
						f.originfilesize,
						f.offset,
						f.encodedsize,
						f.crc32left,
						NULL,0,
						NULL
						) ))
				{
					return edk_LogicError;
				}
			}
		}
		return edk_SUCCEEDED;
	}
	bool decode(BYTE *dest,size_t size,const file_info &info){
		if(size < info.originfilesize){
			return false;
		}
		//シーク
		mOp.seek((size_t)info.offset,SEEK_SET);
		int r;
		{
			size_t ts = size;
			
			if(mRule.isNull())
			{
				
				//読み込み
				r = mOp.read(dest,info.originfilesize);

			}else{
				//一時バッファ用意
				scoped_buffer_byte buff((size_t)info.originfilesize);
				//読み込み
				mOp.read(buff.get(),buff.size());

				r = mRule->decode(buff.get(),buff.size(),dest,size);
				if(DKUTIL_FAILED(r)){
					return false;
				}
			}
			
			UINT ct = mCRC.signature(dest,(int)info.originfilesize);
			///crc値が違う
			if(info.crc != ct){
				setErrorStr("CRCが違うの念");
				return false;
			}

			
		}
		

		return true;
	}
	class encode_writer{
		array_process_interface *mp;
		throw_file_operator *mop;
		scoped_buffer_byte mBuff;
		///書き出したサイズ
		ULONGLONG *mpWriteSize;
	public:
		encode_writer(
			array_process_interface *p,
			throw_file_operator *op,
			size_t size,
			ULONGLONG *WSize
		){
			mp = p;
			mop = op;
			mBuff.resize(size);
			mpWriteSize = WSize;
			*mpWriteSize = 0;
		}
		encode_writer(const encode_writer &x){
			(*this) = x;
		}
		
		inline void operator()(const BYTE *b,size_t size)
		{
			if(mBuff.size() < size){
				mBuff.resize(size);
			}
			if(mp){
				mp->encode(b,size,mBuff.get(),mBuff.size());
				size_t size_temp = mp->encoded_size();
				mop->write(mBuff.get(),size_temp);
				*mpWriteSize += size_temp;
			}else{
				mop->write(b,size);
				*mpWriteSize += size;
			}
		}
		inline ULONGLONG getWriteSize()const{
			return *mpWriteSize;
		}
		encode_writer &operator=(const encode_writer &x){
			mp = x.mp;
			mop = x.mop;
			mBuff = x.mBuff;
			mpWriteSize = x.mpWriteSize;
			return (*this);
		}
	};

	///destとsizeを0にするとinfoからファイル名を引っ張ってきてそれを圧縮させて書き出す
	bool encode_write(file_info meminfo,const file &info,ULONGLONG *write_size)
	{
		ULONGLONG wsize;
		encode_writer w(mRule.get(),&mOp,mTempSize,&wsize);
		if(meminfo.empty())
		{
			//ファイルオープン也
			file_operator op(meminfo.filename().c_str(),"rb");
			op.open();
			
			op.div_read_each(
				//encode_writer(mRule.get(),&mOp,mTempSize,&wsize)
				w
			);

		}else{
			//encode_write writer(mRule,mOp,size);
			w(meminfo.get_data(),meminfo.get_data_size());

		}
		///書き込んだサイズを保存
		*write_size = wsize;
		return true;

	}
public:
	FilePack(){
		//close();	
	}

	virtual ~FilePack(){
		close();
	}


	bool isread()const{
		for(const char *p=mOp.mode();;p++){
			if('r'==*p){
				return true;
			}
			if(*p == '\0'){
				break;
			}
		}
		return false;
		
		//return NULL != std::find(mOp.mode(),NULL,'r');
	}
	bool find_packed_file(parm_string str)const{
		FILE_HEADER_MAP::const_iterator it = mHM.find(str.c_str());
		if(it == mHM.end()){
			return false;
		}
		return true;
	}
	ULONGLONG getOriginFileSize(const char *packed_filename)const{
		FILE_HEADER_MAP::const_iterator it = mHM.find(packed_filename);
		if(it == mHM.end()){
			return 0;
		}
		return it->second.originfilesize;
	}
	bool getErrorString(char *buff,size_t size){
		return DKUTIL_SUCCEEDED_BOOL(
			dkstrcpy(buff,size,mErrorStr.c_str(),mErrorStr.size())
		);
	}
	bool open(const char * filename,const char *dir,
		array_process_interface *rule__,
		bool isread_=true,size_t temp_buff_size = 1024 * 512 ,
		const cache_option &caching=cache_option())
	{
		close();

		if(NULL==dir || NULL==filename){
			setErrorStr("ディレクトリまたはファイル名の指定がNULLです。");
			return false;
		}

		mTargetDir = dir;
		mTargetFile = filename;

		mFilename = dir;

		if(false==DirectoryPlusFileName(mFilename,filename))
		{
			setErrorStr("ディレクトリ、ファイル名のどちらかが不正です。結合に失敗しました。");
			return false;
		}

		
		if(false==open_op(mFilename.c_str(),isread_))
		{
			//setErrorStr("ファイルが見つかりません。");
			return false;
		}
		
		mTempSize = temp_buff_size;

		mRule.reset(rule__);

		return true;
	}
	///@todo crcチェック
	bool loadFileToMemory(const char * packed_filename,BYTE *dest,size_t size){
		FILE_HEADER_MAP::mapped_type *ref;
		if(false==mHM.GetData(packed_filename,&ref)){
			setErrorStr(std::string(packed_filename) + "は見つかりません");
			return false;
		}
		if(size < ref->originfilesize){//バッファサイズが少ないぞ!
			setErrorStr("バッファサイズが少ないです。getOriginFileSize()を使ってバッファサイズを測りましょう。");
			return false;
		}
		
		if(false==decode(dest,size,*ref)){
			setErrorStr("decodeに失敗しました。");
			return false;
		}
		return true;
	}
	bool loadFileToFile(const char * packed_filename,const char * filename,bool rewrite){
		if(false==find_packed_file(packed_filename))
		{
			setErrorStr("loadFileToFile():指定されたファイルが見つかりません。");
			return false;
		}
		size_t size = (size_t)getOriginFileSize(packed_filename);
		if(0==size){
			return CreateZeroByteFile(filename,rewrite);
		}
		scoped_buffer_byte buff(size);

		if(false==loadFileToMemory(packed_filename,buff.get(),buff.size())){
			return false;
		}
		
		if(false==SaveBinary(buff.get(),buff.size(),filename)){
			setErrorStr("ファイルに保存するのを失敗しました。");
			return false;
		}
		return true;
	}
	bool regist_check(parm_string str){
		if(str.size() >= dkcdMAXPATH){
			return false;
		}
		if(dkcIsAbsolutelyPath(str.c_str())){
			return false;
		}
		return true;
	}
	bool registFile(const char *filepath_signature,const char * target_file){
		if(isread()){
			setErrorStr("readモードなので登録はできません。");
			return false;
		}
		if(false==regist_check(filepath_signature)){
			return false;
		}
		
		file_info info;
		info.clear();

		info.mFileReserved = target_file;

		
		return mHM.SetData(filepath_signature,info);
	}
	bool registMemory(const char * filepath_signature,BYTE *dest,size_t size){
		if(isread()){
			return false;
		}
		if(false==regist_check(filepath_signature)){
			return false;
		}
		file_info info;

		info.mData.resize(size);
		memcpy(info.mData.get(),dest,size);

		return mHM.SetData(filepath_signature,info);
	}
	bool saveFile(const char *filename,bool rewrite){
		FILE_HEADER_MAP::iterator it = mHM.begin();
		header h;

		typedef std::pair<FILE_HEADER_MAP::iterator,file> DATA_T;
		typedef std::list<DATA_T > TLIST;
		
		//ファイルデータ保存用リスト
		TLIST li;

		size_t count = 0;
		//CRC32
		CRC_TYPE crc;
		//file info headerの準備
		for(;it != mHM.end();it++,count++)
		{
			file f={0};
			if(it->first==mFilename)
			{//書き出し中のファイルは登録されるとバグッチャうので削除
				continue;
			}
			if(it->second.empty())
			{//ファイルの名前のみが登録されていたら
				if(mFilename==it->second.mFileReserved)
				{//書き出し中のファイルは登録されるとバグッチャうので削除
					continue;
				}
				//ファイル名
				set_file_info(&f,NULL,//オフセットは後で
					it->second.mFileReserved,it->first
					);
				
			}
			else
			{//ファイルのメモリ領域まで登録されていたら
				int r = dkstrcpy(f.filename,sizeof(f.filename),it->first.c_str(),it->first.size());
				if(DKUTIL_FAILED(r)){
					return false;
				}
				//ファイルサイズ
				f.originfilesize = it->second.get_data_size();

				//get crc32left
				f.crc32left = crc.signature(it->second.get_data(),f.originfilesize);

			}
			//データを入れとく
			li.push_back(DATA_T(it,f));

		}//end of for

		//ファイルの先頭にseek 
		mOp.seek(0,SEEK_SET);

		//header set
		h.file_num = li.size();
		h.version = eVersion;
		//header write
		mOp.write(&h,sizeof(h));


		//file info headerの予約書き込み
		{
			//file info header set
			TLIST::iterator it = li.begin();
			file reserved={0};
			for(;it != li.end();it++){
				mOp.write(&reserved,sizeof(file));
			}
		}
	
		//file dataの書き込み
		{
			ULONGLONG write_size;
			TLIST::iterator it = li.begin();
			
			for(;it != li.end();it++){
				file &f = it->second;
				if(it->first->second.empty()==false)
				{//ポインタがある
					encode_write(it->first->second,(*it).second,&write_size);
				}
				else
				{//ポインタが無い
					encode_write(it->first->second,(*it).second,&write_size);
				}
				//書き出したサイズを取得
				f.encodedsize = write_size;
			}
		}

		//file info header先頭の領域にseek
		mOp.seek(sizeof(header),SEEK_SET);

		//file info headerの書き込み
		{
			//オフセットカウンタ(オーバーフローしないことを祈る(大丈夫だね普通なら^^;
			ULONGLONG fileoffset = h.file_num * sizeof(file) + sizeof(header);

			//file info header set
			TLIST::iterator it = li.begin();
			/*
			//オフセットを入れる
			it->second.offset = fileoffset;
			//書き込み
			mOp.write(&(*it).second,sizeof(file));

			//offset 更新
			fileoffset += it->second.encodedsize;
			*/
			for(;it != li.end();it++)
			{
				
				it->second.offset = fileoffset;
				
				//書き込み
				mOp.write(&(*it).second,sizeof(file));

				//offset更新
				fileoffset += it->second.encodedsize;
				
			}

		}
		return true;

	}

	///すべてをクリア
	bool close(){
		close_op();
		mHM.clear();
		mFilename.clear();
		//スマポなので多分これで開放されるのだろうけど・・・。
		mRule.reset();
		return true;
	}


};


//**********************************************************
//まとめ役
//**********************************************************

/*
class ConvertRuleManager : public array_process_interface{
public:
	//typedef std::list<sptr<array_process_interface *> > RULE_LIST;
	typedef PointerAlignment<
		array_process_interface,
		std::list<array_process_interface *> 
	> RULE_LIST;
	//typedef std::vector<int> PROCESS_RESULT;
private:
	///デコードルールのリスト
	RULE_LIST mRL;
	///decode,encodeの結果
	PROCESS_RESULT mVec;
	
public:
	ConvertRuleManager(array_process_interface *p){
		setRule(p);
	}
	ConvertRuleManager(array_process_interface **p,size_t num){
		setRules(p,num);
	}

	void setRule(array_process_interface *p){
		mRL.Insert( p );
	}

	void setRules(array_process_interface **p,size_t num){
		for(size_t i=0;i<num;i++){
			mLR.Insert( p[i] );
		}
	}
	bool reset(array_process_interface **p,size_t num){
		clear();
		setRules(p,num);
		return true;
	}
	void clear(){
		mRL.clear();
		mVec.clear();
	}
	PROCESS_RESULT &get_result(){
		return mVec;
	}

	
	virtual int decode(BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		mVec.clear();
		int result;
		RULE_LIST::iterator it = mRL.begin();
		for(;it != mRL.end();it++)
		{
			int r = (*it)->decode(src,size_t,dest,destsize);
			if(DKUTIL_FAILED(r)){
				result = r;
			}
			mVec.push_back(r);
		}
		return result;
	}
	virtual int decode(BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		mVec.clear();
		int result;
		RULE_LIST::iterator it = mRL.begin();
		for(;it != mRL.end();it++)
		{
			int r = (*it)->eccode(src,size_t,dest,destsize);
			if(DKUTIL_FAILED(r)){
				result = r;
			}
			mVec.push_back(r);
		}
		return result;
	}
};
*/

#if 0

///array_process_interfaceのまとめ役
template<class INTERFACE__ = array_process_interface>
class ConvertRuleAlignment : public array_process_interface , 
protected PointerAlignment<
		INTERFACE__,
		std::list<INTERFACE__> 
	> 
{
public:
	typedef array_process_interface base_type;
	typedef INTERFACE__ element_type;
	typedef PointerAlignment<
		INTERFACE__,
		std::list<INTERFACE__> 
	> CONTAINER_TYPE;
	typedef CONTAINER_TYPE::iterator iterator;
	typedef CONTAINER_TYPE::const_iterator const_iterator;
	typedef CONTAINER_TYPE::reverse_iterator reverse_iterator;
	typedef CONTAINER_TYPE::const_reverse_iterator const_reverse_iterator;
	typedef CONTAINER_TYPE::pointer_type pointer_type;
private:
	
public:
	ConvertRuleAlignment(pointer_type p){
		setRule(p);
	}
	ConvertRuleAlignment(pointer_type *p,size_t num){
		setRules(p,num);
	}

	///ルールをぶち込む
	void setRule(pointer_type p){
		CONTAINER_TYPE::Insert( p );
	}
	///ルールの配列をぶち込む
	void setRules(pointer_type *p,size_t num){
		for(size_t i=0;i<num;i++){
			CONTAINER_TYPE::Insert( p[i] );
		}
	}
	///clear()してsetRules()する。
	bool reset(pointer_type *p,size_t num){
		CONTAINER_TYPE::clear();
		setRules(p,num);
		return true;
	}
	///setRule()等で入れたデータをクリアーする。
	void clear(){
		CONTAINER_TYPE::clear();
		}
	/*virtual int encode(BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		iterator it = begin();
		for(;it != end();it++){
			(*it)->encode(src,size,dest,destsize);
		}
		//for_each(array_process_interface::encode,src,size,dest,destsize);
		return edk_SUCCEEDED;
	}
	virtual int decode(BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		iterator it = begin();
		for(;it != end();it++){
			(*it)->decode(src,size,dest,destsize);
		}
		//for_each(array_process_interface::decode,src,size,dest,destsize);

		return edk_SUCCEEDED;
	}*/
};

///責任のある変換まとめ役
class ResponsibleConvertAlignment : 
	public ConvertRuleAlignment<
		std::pair<
			sptr<array_process_interface>,//正規コンバートルート
			sptr<array_process_interface>//エラーした場合盥回しにするルート
		>
	>
{
public:
	typedef ConvertRuleAlignment<
		std::pair<
			sptr<array_process_interface>,
			sptr<array_process_interface>
		>
	> base_type;
	typedef base_type::element_type element_type;
	typedef base_type::pointer_type pointer_type;
	typedef base_type::iterator iterator;
	typedef base_type::const_iterator const_iterator;
	typedef base_type::reverse_iterator reverse_iterator;
	typedef base_type::const_reverse_iterator const_reverse_iterator;
	//typedef std::vector<int> responsible_log;
private:
	//responsible_log mLogVec;
public:
	ResponsibleConvertAlignment(pointer_type p) : base_type(p){
	}
	ResponsibleConvertAlignment(pointer_type *p,size_t num) : base_type(p,num){
	}

	virtual int decode(const BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		int r;
		iterator it = begin();
		for(;it != end();it++)
		{
			r = (*it).first->decode(src,size,dest,destsize);
			if(DKUTIL_FAILED(r)){
				r = (*it).second->decode(src,size,dest,destsize);
				if(DKUTIL_FAILED(r)){
					return r;
				}
			}

		}
		return edk_SUCCEEDED;
	}
	virtual int encode(const BYTE *src,size_t size,BYTE *dest,size_t destsize)
	{
		int r;
		iterator it = begin();
		for(;it != end();it++)
		{
			r = (*it).first->encode(src,size,dest,destsize);
			if(DKUTIL_FAILED(r)){
				r = (*it).second->encode(src,size,dest,destsize);
				if(DKUTIL_FAILED(r)){
					return r;
				}
			}
		}
		return edk_SUCCEEDED;
	}


};
#endif

//**********************************************************
CreateDirectory SJISに対応させようとしたもの残骸
//**********************************************************

int WINAPI dkcCreateDirectory(const char *pPath)
{
	BOOL result;
	char work[dkcdMAXPATH_BUFFER];
	unsigned long n = 0;
	unsigned long len = strlen(pPath);

#ifdef WIN32
	SECURITY_ATTRIBUTES attr;
	
	DKUTIL_STRUCTURE_INIT(attr);
	NULL_CHAR_ARRAY(work);

	//error check
	if(dkcdMAXPATH_LEN < len){
		dkcmNOT_ASSERT_MESSAGE("pathが長すぎる。",pPath);
		return edk_FAILED;
	}
	if(0==len ){
		return edk_ArgumentException;
	}

	//まずは一つ目を撃破
	if ( dkcmIsSJIS1(pPath[n]) || ! dkcmIS_INVALID_FOLDERNAME_CHAR(pPath[n]) )
	{//SJISの1文字目かINVALIDな値では無かったら。
		work[n] = pPath[n];
	}
	n++;
	//二つ目から開始
	while ( n < len )
	{
		 //フォルダ名取得
		while ( n < len )
		{
			
			if(! dkcmIsSJIS1(pPath[n - 1]))
			{//SJISではない!!
				if ( ( dkcmIS_PATH_SEP(pPath[n]) ) /*&& pPath[n] != '\0'*//*(n != '\0')*/ )
				{
					if ( work[n-1] != ':' )
					{//driveを読み込ませたくないらしい。
						break;
					}
				}
				else if(dkcmIS_INVALID_FOLDERNAME_CHAR(pPath[n]))
				{//SJIS問題をクリアしたのに間違いだった
					return edk_FAILED;
				}
			}
			
			work[n] = pPath[n];
			n++;
		}
		work[n] = '\0';

		//フォルダ作成
		attr.nLength = sizeof(SECURITY_ATTRIBUTES);
		attr.lpSecurityDescriptor = NULL;
		attr.bInheritHandle = FALSE;

		result = dkcCreateDirectoryLogic( work, &attr );
		
		dkcmNOT_ASSERT("directoryを作れなかった" && FALSE==result);
		
		work[n++] = dkcdPATH_SEP;
	}
#else
	NULL_CHAR_ARRAY(work);
	
		//error check
	if(dkcdMAXPATH_LEN < len){
		dkcmNOT_ASSERT_MESSAGE("pathが長すぎる。",pPath);
		return edk_FAILED;
	}
	if(0==len ){
		return edk_ArgumentException;
	}

	while ( n < len )
	{
		 //フォルダ名取得
		while ( n < len )
		{
			if ( ( dkcmIS_PATH_SEP(pPath[n]) ) && (n != '\0') )
			{
				if ( work[n-1] != ':' )//Linuxのドライブのパスはコレデいいのかな?
				{
					break;
				}
			}
			work[n] = pPath[n];
			n++;
		}
		work[n] = '\0';

		result = dkcCreateDirectoryLogic( work,NULL );

		dkcmNOT_ASSERT("directoryを作れなかった" && FALSE==result);

		work[n++] = dkcdPATH_SEP;
	}

#endif

	return edk_SUCCEEDED;
}
//**********************************************************
//ランキングタイマークラス(仕様が駄目な為廃棄

#if 0
//template<class OUTPUT_POLICY__ >
class ranking_timer : public boost::noncopyable{
public:
#ifdef _MSC_VER
	typedef RealCPUClock timer_type;
#else
	typedef MilliSecondClock timer_type;
#endif
	//typedef OUTPUT_POLICY__ output_type;
	struct DATA_TYPE{
		double mTime;
		std::string mName;

		DATA_TYPE(double t,const char *s) : mTime(t) , mName(s){}
		DATA_TYPE(const DATA_TYPE &x){
			*this = x;
		}
			

		DATA_TYPE &operator =(const DATA_TYPE &x){
			mTime = x.mTime;
			mName = x.mName;
			return *this;
		}
		friend bool operator <(const DATA_TYPE &x,const DATA_TYPE &y){//less
			//return x.mTime < y.mTime;
			return x.mName < y.mName;
		}
		friend bool operator ==(const DATA_TYPE &x,const DATA_TYPE &y){//less
			//return x.mTime < y.mTime;
			return x.mName == y.mName;
		}
	};
		

	/*typedef stable_priority_queue_ex<DATA_TYPE,
		std::list<DATA_TYPE>,
		std::less<DATA_TYPE> > CONTAINER_TYPE;
	*/
	typedef map_ex_adapter<std::map<std::string,DATA_TYPE,
		std::list<DATA_TYPE>,
		std::less<DATA_TYPE> > CONTAINER_TYPE;

	struct less_Time : public std::binary_function<DATA_TYPE,DATA_TYPE,bool> {
		bool operator ()(const DATA_TYPE &x,const DATA_TYPE &y){//less
			return x.mTime < y.mTime;
		}
	};
	struct less_Name: public std::binary_function<DATA_TYPE,DATA_TYPE,bool> {
		bool operator ()(const DATA_TYPE &x,const DATA_TYPE &y){//less
			//return x.mTime < y.mTime;
			return x.mName < y.mName;
		}
	};

private:
	timer_type mT;
	CONTAINER_TYPE mC;
	
public:
	virtual void sort_output()const{
		dODS("%s",mT.GetOutputSignature());
		mC.sort(less_Time());

		CONTAINER_TYPE::const_iterator it = mC.begin();
		
		for(;it != mC.end();it++)
		{
			double time = (*it).mTime;
			dODS("%s\t:\t%f\t",(*it).mName.c_str(),time);
			//OUTPUT_POLICY__::Output(time,NULL,mT.GetOutputSignature(),time);

		}
		mC.sort(less_Name());
	}
	ranking_timer(){	}
	virtual ~ranking_timer(){
		sort_output();
	}
	///ranking_timerクラスが使うタイマー
	struct scoped_timer{
		timer_type mT;
		ranking_timer *mPtr;
		std::string mName;
		/*!
		@param name[in] 出力する時に一緒に出力する文字列(いわいる識別子)
		@param ptr[in] ranking_timerクラスへのポインタ
		@todo
		このranking_timerクラスへのポインタを渡すところが
		ダサくて嫌いなのですが、これしか思いつきません^^;
		どちら様か、奨励できる実装がありましたら、どうか教えてください。m(_ _)m
		*/
		scoped_timer(const char *name,ranking_timer *ptr){
			dkcmFORCE_NOT_ASSERT(NULL==ptr);
			mPtr = ptr;
			mName = name;
			mT.restart();
		}
		~scoped_timer(){
			mPtr->push_back(mName.c_str(),mT.elapsed());
		}
		void restart(){
			mT.restart();
		}
		double elapsed() const {
			return mT.elapsed();
		}
	};
	void push_back(const char *name,double time){
		mC.push(DATA_TYPE(time,name));
	}
	void clear(){
		mC.clear();
	}
	bool erase(const char *name){
		return mC.erase(DATA_TYPE(0.0f,name));
	}
};

#endif




class ranking_timer : public boost::noncopyable{
public:
#ifdef _MSC_VER
	typedef RealCPUClock timer_type;
#else
	typedef MilliSecondClock timer_type;
#endif
	typedef double_key_map<std::string,double,std::string> CONTAINER_TYPE;
	typedef CONTAINER_TYPE:: INSERT_DATA_TYPE DATA_TYPE;

private:
	timer_type mT;
	CONTAINER_TYPE mC;
	
public:
	virtual void sort_output()const{
		dODS("%s",mT.GetOutputSignature());
		
		CONTAINER_TYPE::MAP2_CONST_ITERATOR it = mC.begin2();
		
		for(;it != mC.end2();it++)
		{
			//double time = (*it).first;
			const std::string &ref = (*((*it).second)).second;
			dODS("%s",ref.c_str());
			//OUTPUT_POLICY__::Output(time,NULL,mT.GetOutputSignature(),time);

		}
	}
	ranking_timer(){	}
	virtual ~ranking_timer(){
		sort_output();
	}
	///ranking_timerクラスが使うタイマー
	struct scoped_timer{
		timer_type mT;
		ranking_timer *mPtr;
		std::string mName;
		/*!
		@param name[in] 出力する時に一緒に出力する文字列(いわいる識別子)
		@param ptr[in] ranking_timerクラスへのポインタ
		@todo
		このranking_timerクラスへのポインタを渡すところが
		ダサくて嫌いなのですが、これしか思いつきません^^;
		どちら様か、奨励できる実装がありましたら、どうか教えてください。m(_ _)m
		*/
		scoped_timer(const char *name,ranking_timer *ptr){
			dkcmFORCE_NOT_ASSERT(NULL==ptr);
			mPtr = ptr;
			mName = name;
			mT.restart();
		}
		~scoped_timer(){
			mPtr->insert(mName.c_str(),mT.elapsed());
		}
		void restart(){
			mT.restart();
		}
		double elapsed() const {
			return mT.elapsed();
		}
	};
	void insert(const char *name,double time){
		//boost::io::str( boost::format("%d") % ui);
		std::string str = boost::io::str(
			boost::format("%s\t:\t%f\t") % name % time
		);

		mC.insert(DATA_TYPE(name,time,str));
	}
	void clear(){
		mC.clear();
	}
	bool erase(const char *name){
		return mC.erase(name);
	}
};


//typedef ranking_timer_base<policy::DebugReport> ranking_timer;
//typedef ranking_timer_base ranking_timer;
//**********************************************************
/*!
@param WORKSPACE_SIZE 元から確保するバッファのサイズ(byte単位
@param BUFFER_T byte_bufferクラスと同じ仕様のバッファクラス(普通はこのままで事足りるでしょう。
@note
場合によってはヒープから確保しないバッファ・・・なんてバカなんだ。私は・・・
仕様用途:タスクワークの元とか<br>
処理内容:BUFFER_T型のバッファクラスを使って動的確保か、
バッファサイズが十分ならばcharのバッファを使って処理コストを下げる!??<br>
主張:なんか、byte_buffer,boost::arrayやstd::vectorとかぶっているけど、
memcpyができる事を中心とした、ちと違うクラスって事で、認識しといてください。
*/
template<std::size_t WORKSPACE_SIZE = 64,class BUFFER_T=byte_buffer>
class WorkSpaceBase{
public:
	typedef BUFFER_T BUFFER_TYPE;
	enum{
		enuWorkSize = WORKSPACE_SIZE,
	};
#	ifdef _MSC_VER
	typedef BUFFER_T::size_type size_type;
	typedef BUFFER_T::pointer pointer;
	typedef BUFFER_T::const_pointer const_pointer;
#else
	typedef size_t size_type;
	typedef char *pointer;
	typedef const pointer const_pointer;
#endif

private://めんどくさいし〜。
	char WorkData[enuWorkSize];

	BUFFER_T mDWorkSpace;
	void _construct(){

		NULL_CHAR_ARRAY(WorkData);
		mDWorkSpace.clear();
	}
public:


	///constructor 
	WorkSpaceBase(){
		_construct();
	}
	///copy constructor
	WorkSpaceBase(const WorkSpaceBase<WORKSPACE_SIZE,BUFFER_T> &data){
		_construct();
		if(data.mDWorkSpace.empty()){
			SetBuff(data.WorkData,enuWorkSize);
		}else{
			mDWorkSpace = data.mDWorkSpace;
		}
	}
	//destructor
	virtual ~WorkSpaceBase(){
		clear();
	}
	///ワークスペースを開放する。( ReserveWorkOnce()を呼び出している場合 )
	void clear(){
		mDWorkSpace.clear();
		NULL_CHAR_ARRAY(WorkData);
	}
	/*!
	@return すでにこの関数を呼び出している場合、clear()を呼び出さないとこの関数は失敗する。
	また、WORKSPACE_SIZE分内部で確保しているのでそれ以下の場合はfalseである。
	*/
	bool reserve(size_type size){
		if(size <= enuWorkSize || (!mDWorkSpace.empty())){
			return false;
		}
		mDWorkSpace.resize(size);
		return true;
	}
	///reserveのWrapper
	bool resize(size_type size){
		return reserve(size);
	}
	///ワークスペースのアドレスをゲットする(後は各自、キャストしてください。
	pointer data(){
		if(mDWorkSpace.empty()){
			return WorkData;
		}else{
			return mDWorkSpace.data();
		}
	}
	const_pointer data()const{
		if(mDWorkSpace.empty()){
			return WorkData;
		}else{
			return mDWorkSpace.data();
		}
	}
	///バッファの許容サイズをゲットする。
	size_type capacity()const{
		if(mDWorkSpace.empty()){
			return enuWorkSize;
		}else{
			return mDWorkSpace.size();
		}
	}

	/*!
	@param src[in] コピー元 buffer
	@param size[in] srcのサイズ
	@return false = 失敗 
	*/
	///srcのメモリ領域をバッファにコピーする。
	bool SetBuff(const char *src,size_type size){
		int r;
		if(!mDWorkSpace.isValid()){
			NULL_CHAR_ARRAY(WorkData);
			r = dkmemcpy(WorkData,capacity(),src,size);
			return DKUTIL_SUCCEEDED(r);
		}else{
			return	mDWorkSpace.SetBuff(src,size);
		}
		//return false;
	}

	bool SetString(size_type buffsize,const char *str,...){
		
		temporary_buffer b(new char[buffsize]);
		SET_VA_LIST(b.get(),buffsize,str);
		return SetBuff(b.get(),strlen(b.get()));
	}
	bool SetString(const char *str,...){
		
		size_type buffsize = strlen(str);
		buffsize += 256;
		temporary_buffer b(new char[buffsize]);
		SET_VA_LIST(b.get(),buffsize,str);
		return SetBuff(b.get(),strlen(b.get()));
	}
	
	
};

///カッチョ悪い<>な定義を無くすため
typedef WorkSpaceBase<> WorkSpace;

//**********************************************************
	struct iterator{
		typedef BML_POOL::iterator handle;
	protected:
		BML_POOL::iterator mH;
	public:
		iterator(BML_POOL::iterator h){
			mH = h;
		}
		iterator(const iterator &it){
			mH = it.mH;
		}

		DATA_TYPE &operator*(){
			return GetPool().at((*mH));
		}
		DATA_TYPE* operator->() { 
			return &GetPool().at((*mH));
		}
		void operator++(){
			++mH;
		}
		void operator++(int){
			mH++;
		}
		
		void operator--(){
			--mH;
		}
		iterator& operator=(const iterator &i1){
        mH = i1.mH;
        return *this;
    }
		friend bool operator==(const iterator &i1,const iterator &i2){
			return (i1.mH == i2.mH);
		}
		friend bool operator !=(const iterator &i1,const iterator &i2){
			return (i1.mH != i2.mH);
		}

	};

//**********************************************************
//自称、メモリ効率の良いBulletMLRunnerの残骸
//BulletMLRunnerのメモリ使用効率を良くしようとして失敗に終わったBMLRunner...
//めちゃくちゃ遅いし、メモリリークはするし・・・。
//**********************************************************

namespace dxex{
	
//プロトタイプ宣言
class DxExBulletMLRunner01;

union uniBulletDataRelative{
	void *uniVPTR;
	int uniIntHandle;
	UINT uniUintHandle;
};


template<class RUNNER>
struct tagBulletData{
	///座標
	double x,y;
	///スピードと方向?のことか?
	//double dx,dy;
	///スピード?
	double accelx,accely;
	///角度とスピード
	double direction, speed;
	
	///なんらかのデータ関連付け用。
	uniBulletDataRelative relative;
	///これらのメンバ関数はunionにアクセスしているのを忘れてはいけない。
	int GetRelativeInt(){return relative.uniIntHandle;}
	UINT GetRelativeUint(){return relative.uniUintHandle;}
	void *GetRelativeVPTR(){return relative.uniVPTR;}
	///VanishしてBulletMLRunnerを破棄する。
	/*void ClearRunner(){
		if(bml){
			//doVanishですべてdeleteとかしてくれる。
			bml->doVanish();
		}
	}*/
	//ID
	//size_t id;
	///BulletMLRunnerの派生したもの
	RUNNER *bml;
};



//template<class DATA_ = tagBulletData<DxExBulletMLRunner01> >


///メモリープール。こいつがあれば速くメモリを確保できるよ^^もう最強レベル^^
//template<class DATA_ = tagBulletData<DxExBulletMLRunner01> >
template<class DATA_ >
class DxExBulletMLMemoryPool {
public:
	typedef dkutil::array_onebyone_ex<DATA_ > CONTAINER_TYPE;
	typedef DATA_ DATA_TYPE;
	//typedef dkutil::singleton<CONTAINER_TYPE> SINGLETON_CONTAINER_TYPE;
	typedef CONTAINER_TYPE::size_type size_type;
	//typedef typename CONTAINER_TYPE::handle handle;
	//typedef typename CONTAINER_TYPE::handle handle;
	typedef CONTAINER_TYPE::handle handle;
	typedef dkutil::set_ex<handle> POOL_ITERATOR;
	//typedef dkutil::singleton<PoolIterator> SINGLETON_POOL_ITERATOR;

	typedef std::deque<handle> VANISH_QUEUE;
	//typedef dkutil::singleton<VANISH_QUEUE> SINGLETON_VANISH_QUEUE;
private:
	CONTAINER_TYPE mC;


	//イテレータ
	POOL_ITERATOR mIte;
	//削除用キュー
	VANISH_QUEUE mVaQue;
	
	///イテレーションキーを挿入
	void insert_it(size_type iterate_key){
				
		DKUTIL_TRUE_ASSERT_OR_THROW(
			mIte.rb_insert(iterate_key)==false,
			std::runtime_error("うまく挿入出来へんかった!ヽ(`Д´)ノムキィ");
		);

	}
	///イテレーションキーを削除
	void erase_it(const size_type& iterate_key){

		mIte.erase(iterate_key);

	}
	void FreeHelper(DATA_TYPE &d){
		if(d.bml){
			delete d.bml;
			d.bml = NULL;
		}
	}

public:
		///BulletMLの管理クラスがデストラクタの時に呼び出す。
	void RealDestructor(){
		CONTAINER_TYPE &c = mC;
		const CONTAINER_TYPE::DEQUE_TYPE &q = c.get_deque();
		CONTAINER_TYPE::DEQUE_TYPE::const_iterator it = q.begin();
		for(;it != q.end();it++)
		{
			FreeHelper(mC.at((*it)));
		}
	}
	DxExBulletMLMemoryPool(){
		//static にしたのだから こんなことしちゃ ダメ!
		//CONTAINER_TYPE::reserve(512);//とりあえず、このくらい用意しておけば十分^^
	}


	///プッシュする。
	handle push(DATA_TYPE &d){
		handle h = mC.push(d);
		insert_it(h);
		return h;
	}
	///ポップ指令を出す。
	void pop(handle h){
		//DeleteBulletHelper(at(h));
		mVaQue.push_back(h);
	}
	///メモリを解放する。(1フレームに1回くらいの割合で呼び出して^^
	void arrangement_memory(){
		VANISH_QUEUE &ha = mVaQue;
		if(ha.empty()) return;
		VANISH_QUEUE::iterator it =  ha.begin();
		for(;ha.end() != it;it++){
			FreeHelper(at((*it)));
			mC.pop((*it));
			erase_it((*it));
		}
		//ここでクリアーしないと大目玉食らっちゃうよ^^;
		ha.clear();
	}
	VANISH_QUEUE &get_vanish_queue(){return mVaQue;}

	DATA_TYPE &at(handle h){
		return mC.at(h);
	}
	
	CONTAINER_TYPE &get_container(){return mC;}
	POOL_ITERATOR &get_pool_iteration(){return mIte;}
	

//以下はイテレーション系
	typedef POOL_ITERATOR::iterator iterator;
	typedef POOL_ITERATOR::const_iterator const_iterator;
	typedef POOL_ITERATOR::reverse_iterator reverse_iterator;
	typedef POOL_ITERATOR::const_reverse_iterator const_reverse_iterator;

	
	iterator begin(){return mIte.begin();}
	iterator end(){return mIte.end();}
	reverse_iterator rbegin(){return mIte.rbegin();}
	reverse_iterator rend(){return mIte.rend();}
	bool empty(){return mIte.empty();}
};

//**********************************************************


template<class DATA_T >
struct BulletMLMemoryPoolAdapter{
public:
	typedef DxExBulletMLMemoryPool< DATA_T> POOL_TYPE;
	typedef dkutil::singleton<POOL_TYPE> SINGLETON_POOL_TYPE;
private:
	static SINGLETON_POOL_TYPE mPool;
public:
	typedef POOL_TYPE::handle handle;
	typedef POOL_TYPE::DATA_TYPE DATA_TYPE;
	typedef POOL_TYPE::iterator iterator;
	typedef POOL_TYPE::const_iterator const_iterator;
	typedef POOL_TYPE::reverse_iterator reverse_iterator;
	typedef POOL_TYPE::const_reverse_iterator const_reverse_iterator;

	iterator begin(){return mPool->begin();}
	iterator end(){return mPool->end();}
	reverse_iterator rbegin(){return mPool->rbegin();}
	reverse_iterator rend(){return mPool->rend();}
	bool empty(){return mPool->empty();}


	///プッシュする。
	handle push(DATA_TYPE &d){
		return mPool->push(d);
	}
	///ポップ指令を出す。
	void pop(handle h){
		mPool->pop(h);
	}
	DATA_TYPE &at(handle h){
		return mPool->at(h);
	}
	void arrangement_memory(){
		mPool->arrangement_memory();
	}
	void RealDestructor(){
		mPool->RealDestructor();
	}
	void DoubleEntryKill()
	{
			//二重登録しているのを抹殺。
			POOL_TYPE::VANISH_QUEUE &q = mPool->get_vanish_queue();
			//std::sort(q.begin(),q.end());
			POOL_TYPE::VANISH_QUEUE::iterator it=q.begin(),it2 = q.begin();
			for(;it == q.end();++it)
			{
				for(it2 = q.begin();it2 != q.end();it2++)
				{
					if(it != it2){
						if((*it) == (*it2)){
							it = q.erase(it2);
							break;
						}
					}
				}

			}
		}


};

template<class  DATA_T >
//dkutil::singleton<DxExBulletMLMemoryPool< DATA_T> >
BulletMLMemoryPoolAdapter<DATA_T>::SINGLETON_POOL_TYPE
	 BulletMLMemoryPoolAdapter< DATA_T>::mPool;




//**********************************************************

///@todo この構造体はいつか、変わるかもしれない。
struct DxExBulletMLPlayerData{
	//プレイヤーの座標データ
	//int x,y;
	///プレイヤーの当たり判定データ(絶対座標)
	RECT collision;
	///関数の成功フラグ trueで成功
	bool result;
	inline int getX(){
		return collision.left + ((collision.right - collision.left) / 2);// >> 1
	}
	inline int getY(){
		return collision.top + ((collision.bottom - collision.top)	/ 2);// >> 1
	}
};

/*!
以下廃止。
<s>
こんな感じのインターフェイスのプレイヤーの座標をゲットするもの。
まぁ、簡単に言えば、ファンクター
struct PlayerToDelegation{
	inline void operator()(
		DxExBulletMLRunner01<PlayerData> *Set,
		DxExBulletMLPlayerData *GetPlayerData
	);
}
</s>
*/
///BulletMLの実態
//template<class PLAYER_FUNCTOR>


struct DxExBulletMLRunnerStaticMemberVariable{
//**********************************************************
//static member
		///弾の数
	static UINT mBulletNum;
	static int mFrame;
	///毎フレーム呼び出してください。
	static void IncrementFrame(){mFrame++;}
	static void ClearFrame(){mFrame = 0;}


	static int GetFrame(){return mFrame;}
	static UINT GetBulletNum(){return mBulletNum;}
};



typedef void (*DxExBulletMLRunnner01_GetPlayerCollisionFunctionPtr)
	(DxExBulletMLRunner01 *,DxExBulletMLPlayerData *);

typedef BulletMLMemoryPoolAdapter<tagBulletData<DxExBulletMLRunner01> >
	POOL_ADAPTER_TYPE;


class DxExBulletMLRunner01 : 
	public BulletMLRunner ,
		POOL_ADAPTER_TYPE,
		DxExBulletMLRunnerStaticMemberVariable
{
public:
	///弾のデータのタイプ
	typedef POOL_ADAPTER_TYPE POOL_TYPE;
	typedef POOL_TYPE::DATA_TYPE DATA_TYPE;

	typedef DxExBulletMLRunnner01_GetPlayerCollisionFunctionPtr GET_COLLISION_FP;
protected:
	//int no;
	//typedef POOL_TYPE::size_type size_type;
	///領域を見つけるときのID
	POOL_TYPE::handle mId;
	///汎用型変数。(あとは各自でこの中身を関連付けてください。)
	uniBulletDataRelative mRelative;
	///プレイヤーへのコリジョンを頂く関数へのポインタ
	GET_COLLISION_FP mCfp;

	//double x,y;
	//double accelx,accely;
	//double dir, spd;
	



	double getX_(){
		return POOL_TYPE::at(getID()).x;
	}
	double getY_(){
		return POOL_TYPE::at(getID()).y;
	}
public:
//独自実装

	///IDを返す
	POOL_TYPE::handle getID()const{return mId;}
	///IDを入れる。(これ大切!!
	void setID(POOL_TYPE::handle id){mId = id;}

	uniBulletDataRelative GetRelativeData()const{	return mRelative;}

	void setRelative(uniBulletDataRelative r){
		mRelative = r;
	}

	///弾の数をインクリメント
	void IncBulletNum(){mBulletNum++;}
	///同じくデクリメント
	void DecBulletNum(){mBulletNum--;}
	///@return プレイヤーへの当たり判定を取得できる関数へのポインタをGET
	GET_COLLISION_FP GetPlayerCollisionFunctionPtr()const{
		DKUTIL_TRUE_ASSERT(NULL==mCfp);
		return mCfp;
	}


		
//end

  DxExBulletMLRunner01(BulletMLParser* bulletml,uniBulletDataRelative rel
		, GET_COLLISION_FP cfp) 
		: BulletMLRunner(bulletml) 
	{
		mRelative =rel;
		DKUTIL_TRUE_ASSERT(NULL==cfp);
		mCfp = cfp;
		//mId = 0;
		
  }
  DxExBulletMLRunner01(BulletMLState* state,uniBulletDataRelative rel
		, GET_COLLISION_FP cfp)
		: BulletMLRunner(state)
	{
		mRelative =rel;
		DKUTIL_TRUE_ASSERT(NULL==cfp);
		mCfp = cfp;
		//mId = id;
		
  }
  ~DxExBulletMLRunner01() {
		//ここでdoVanish();なんか呼び出すと、コピーコンストラクタが呼び出されたとき
		//Vanishされちゃうのでやめてください。
	}

  ///ここのatan2は遅いからどうにかせんと・・・。
	double getAimDirection() 
	{
		int dx, dy;
		//PLAYER_FUNCTOR func;
		DxExBulletMLPlayerData data={0};
		mCfp(this,&data);
		//func(this,&data);
		DKUTIL_TRUE_ASSERT_OR_THROW(
			false==data.result,
			std::runtime_error(
				"DxExBulletMLRunner01::getAimDirection : functorがエラー値を返した。"
			)
		);
	
		dx = (int)POOL_TYPE::at(mId).x - data.getX();
		dy = data.getY() - (int)POOL_TYPE::at(mId).y;
		if((dx==0)&&(dy==0))
		{
			return 180;
		}
		else
		{
			return atan2((double)dx, (double)dy) / gTrig.getDoublePAI()*180 + 180;
		}
		
  }
//  double getAimDirection() {return 0;}

	double getBulletDirection() {
		return POOL_TYPE::at(mId).direction;
	}
  double getBulletSpeed() {
		return POOL_TYPE::at(mId).speed;
	}
	///デフォルトのスピードを得る。
  double getDefaultSpeed() {return 1;}
	///ランクを得る?
  double getRank() {return 0.5;}
	///シンプルな弾を生成する。
  void createSimpleBullet(double direction, double speed) {
		DATA_TYPE data;
		data.x = getX_();
		data.y = getY_();
		//ここら編間違っているかも!?
		data.accelx = gTrig.fsin(direction/ 180 * gTrig.getDoublePAI())*speed ;
		data.accely = -gTrig.fcos(direction / 180 * gTrig.getDoublePAI())*speed;
		//data.accelx = gTrig.AngleToSin(direction)*speed;
		//data.accely = -gTrig.AngleToCos(direction)*speed;
		data.direction = direction;//getBulletDirection();
		data.speed = speed;//getBulletSpeed();
		data.bml = NULL;
		//関連付けデータを保存。
		data.relative = GetRelativeData();

		//プールに入れる
		POOL_TYPE::handle h = POOL_TYPE::push(data);
		//自分のに入れればいいのかな?
		//setID(h);

		//弾が増えちゃいました。
		mBulletNum++;

	}

	///結構複雑な弾を生成する
  void createBullet(BulletMLState* state, double direction, double speed) {
		DxExBulletMLRunner01 *com;
		///今までのデータのコピーをコンストラクタの引数にする。
		com = new DxExBulletMLRunner01(
			state,
			GetRelativeData(),
			GetPlayerCollisionFunctionPtr()
			);
		if(!com){
			throw std::runtime_error("DxExBulletMLRunner01<PLAYER_FUNCTOR>::createBullet out of memory");
		}
		DATA_TYPE data;
		data.bml = com;
		data.x = getX_();
		data.y = getY_();
		data.accelx = gTrig.fsin(direction/ 180 * gTrig.getDoublePAI())*speed ;
		data.accely = -gTrig.fcos(direction / 180 * gTrig.getDoublePAI())*speed;
		data.direction = direction;//getBulletDirection();
		data.speed = speed;//getBulletSpeed();
		//関連付けデータをセット
		data.relative = com->GetRelativeData();
		

		POOL_TYPE::handle h = POOL_TYPE::push(data);
		//内部を参照しているのを忘れずに^^これでpush後のdata内も変わっている。
		//このIDを入れないと、内部でデータがアクセスできず、Access Violation...
		com->setID(h);

		//弾が増えちゃいました。
		mBulletNum++;

	}
  ///ターン(フレーム)をゲットする。
	int getTurn(){
		return mFrame;

	}
	///弾が壊された。
  void doVanish() {
		
		//ぽっぷしてサヨナラ^^
		POOL_TYPE::pop(mId);
		//弾減りました。
		mBulletNum --;

		
		//		printf("Vanished %d\n",no);
		
	
	}


	///Directionを変える。
  void doChangeDirection(double direction) {
		POOL_TYPE::at(mId).direction = direction;
		//dir = direction;///Speedを変える。
  void doChangeSpeed(double speed) {
		POOL_TYPE::at(mId).speed = speed;
		//spd = speed; 
	}
	///Xを変える。
  void doAccelX(double dx) {
		POOL_TYPE::at(mId).accelx = dx;
		//accelx = dx; 
	}
	///Yを変える。
  void doAccelY(double dy) {
		POOL_TYPE::at(mId).accely = dy;
		//accely = dy; 
	}

	///ここ以下、間違っているかも。変な動きをしたら直して^^;
  inline double getBulletSpeedX() {
		DATA_TYPE &data = POOL_TYPE::at(mId);
		//double tmp =  gTrig.AngleToSin(data.direction)*data.speed + data.accelx;
		//double tmp2 = sin(data.direction/180*3.14)*data.speed  + data.accelx;
		/*if(tmp!=tmp2){
			MB("予想道理");
		}*/
		//return sin(data.direction/180*3.14)*data.speed  + data.accelx;
		//return gTrig.AngleToSin(data.direction)*data.speed + data.accelx;
		return gTrig.fsin(data.direction/ 180 * gTrig.getDoublePAI())*data.speed + data.accelx;
	}
  inline double getBulletSpeedY() {
		DATA_TYPE &data = POOL_TYPE::at(mId);
		return -gTrig.fcos(data.direction/ 180 * gTrig.getDoublePAI())*data.speed + data.accely; 
		//return -gTrig.AngleToCos(data.direction)*data.speed + data.accely; 
		//return -cos(data.direction/180*3.14)*data.speed  + data.accelx;
	}


};


/*!
@note
BulletMLParserTinyXMLの代わり。
暗号化してあったXMLをデコード後、文字列として渡すことの出来るパーサー
*/
class BulletMLParserDxEx : public BulletMLParserTinyXML{
	//const char *mPtr;
	std::string mStr;
	bool mFromFileFlag;
public:
	BulletMLParserDxEx(const char *xmlbuff) : 
			BulletMLParserTinyXML("文字列渡してご機嫌をとる")
	{
		//mPtr = xmlbuff;
		//mStr = xmlbuff;
		set_string_buff(xmlbuff);
		mFromFileFlag = false;
	}
	virtual ~BulletMLParserDxEx(){}
	virtual void parse(){
		if(mStr.empty()){
			throw std::runtime_error("BulletMLParserDxEx 文字列バッファ先がNULLだ!エラーだ!");
		}
		if(mFromFileFlag )
		{//ファイルネームからの場合。
			TiXmlDocument doc(mStr.c_str());
			doc.LoadFile();
			BulletMLParserTinyXML::parseImpl(doc);
		}else{
			//XML文字列からの場合。
			TiXmlDocument doc;
			
			doc.Parse(mStr.c_str());
			//こいつは、プライベートだから、ここはprotected:にでも改造しておく
			BulletMLParserTinyXML::parseImpl(doc);
		}
	}
	///コンストラクタの代わり。
	virtual void set_string_buff(const char *buff){
		mStr = buff;
	}
	///これを呼び出すと強制的にファイルから読み出すようになる。
	virtual void parse_from_file(const char *filename){
		//xmlFile_ = filename;
		mStr = filename;
		mFromFileFlag  = true;
	}

};


}//end of dxex namespace




namespace stg{

//extern void GetPlayerCollision(RECT *rect);


//プロトタイプ宣言
struct GetPlayerDataFunctor;

typedef dxex::DxExBulletMLRunner01 BULLETML_TYPE;





class BulletMLManager {
public:
	///共有BulletML用メモリプール
	typedef dxex::POOL_ADAPTER_TYPE BML_POOL;
	///今回使う特殊カスタマイズ済み、XMLParser
	typedef dxex::BulletMLParserDxEx BULLETML_PARSER;
	///スマートポインタ付XMLパーサー
	typedef smart_ptr<BULLETML_PARSER> DXEX_XMLPARSER_PTR;
	///XMLパーサーのコンテナ
	typedef dkutil::array_onebyone_ex<DXEX_XMLPARSER_PTR> PARSED_XML_CONTAINER;
	///そのコンテナのハンドル
	typedef  PARSED_XML_CONTAINER::handle handle;
	///キャッシュ機構に使おうと思ったけど、断念。
	typedef dkutil::map_ex<std::string,handle> CACHE_PARSED_XML;
	///弾とその他の物を関連付けるときに使うもの。
	typedef dxex::uniBulletDataRelative RELATIVE_UNION;
	
	typedef BULLETML_TYPE::GET_COLLISION_FP GET_COLLISION_FP;

	typedef BML_POOL::DATA_TYPE DATA_TYPE;

	typedef dxex::DxExBulletMLRunnerStaticMemberVariable BML_STATIC_DATA;

private:
	static BML_POOL mBmlPool;
	static BML_STATIC_DATA mBmlStaticData;
	PARSED_XML_CONTAINER mXMLC;
	CACHE_PARSED_XML mXMLCache;

	
	void DeleteBulletHelper(DATA_TYPE &d){
		if(d.bml){
			//handle h = d.bml->getID();
			//d.bml->doVanish();
			//delete d.bml;
			//内部でやってくれる事になった。

			mBmlPool.pop(d.bml->getID());

		}
	}
	///もう使われていないメモリを整理する。
	void FreeMemoryHelper(){
		mBmlPool.arrangement_memory();
	}
	void clear(){
		if(empty()) return;
		iterator it = begin();
		for(;it != end();it++)
		{
			DeleteBulletHelper((*it));
		}
	}
public:
	static int GetFrame(){
		return mBmlStaticData.GetFrame();
	}
	static void IncFrame(){
		mBmlStaticData.IncrementFrame();
	}
	static void ClearFrame(){
		mBmlStaticData.ClearFrame();
	}
	static UINT GetBulletNum(){
		return mBmlStaticData.GetBulletNum();
	}
		
	


	static BML_POOL &GetPool(){
		return mBmlPool;
	}
	
	struct iterator{
		typedef BML_POOL::handle handle;
	protected:
		BML_POOL::iterator mH;
	public:
		iterator(BML_POOL::iterator h){
			mH = h;
		}
		iterator(const iterator &it){
			mH = it.mH;
		}

		DATA_TYPE &operator*(){
			return GetPool().at((*mH));
		}
		DATA_TYPE* operator->() { 
			return &GetPool().at((*mH));
		}
		void operator++(){
			++mH;
		}
		void operator++(int){
			mH++;
		}
		
		void operator--(){
			--mH;
		}
		iterator& operator=(const iterator &i1){
        mH = i1.mH;
        return *this;
    }
		friend bool operator==(const iterator &i1,const iterator &i2){
			return (i1.mH == i2.mH);
		}
		friend bool operator !=(const iterator &i1,const iterator &i2){
			return (i1.mH != i2.mH);
		}

	};
		

	iterator begin(){return iterator(mBmlPool.begin());}
	iterator end(){return iterator(mBmlPool.end());}
	bool empty()const{return mBmlPool.empty();}
	BulletMLManager(){}
	virtual ~BulletMLManager(){
		clear();

		GetPool().DoubleEntryKill();
		FreeMemoryHelper();
		//GetPool().RealDestructor();
	}


	
	
	DXEX_XMLPARSER_PTR &ReferenceBML(handle h){
		return mXMLC.at(h);
	}
	/*!
	@param filename[in] ファイルの名前
	@return ロード済みXMLのハンドルを返す。
	*/
	handle LoadBMLFile(const char *filename);

	/*!
	@return ロード済みXMLのハンドルを返す。
	*/
	handle LoadBML(const char *memory_image_str);
	/*!
	@param xml_handle[in] ロード済みXMLのハンドルを入れる。
	@param x[in] 絶対座標X
	@param y[in] 絶対座標Y
	@param uni[in] 後々イテレーションするときに使う関連付けデータ。
	@param fp[in] プレイヤーへのコリジョンデータを取得できる関数へのポインタ。
	@note
	GET_COLLISION_FP 型の変数のタイプが分からなかったら、
	VCの場合、右クリックで定義の表示をたどっていけば良い。^^
	*/
	bool CreateBullet(handle xml_handle,int x,int y,RELATIVE_UNION uni,GET_COLLISION_FP fp){
		BML_POOL::DATA_TYPE data;
	
		data.x = x;
		data.y = y;
		data.relative = uni;



		//DXEX_XMLPARSER_PTR p = ReferenceBML(xml_handle);
		//data.bml = new BULLETML_TYPE(p.get(),uni);
		data.bml = new BULLETML_TYPE(ReferenceBML(xml_handle).get(),uni,fp);
		if(!data.bml){
			throw std::runtime_error("Out of Memory:BULLETML_TYPEが作成できない。");
		}
		data.accelx = data.bml->getDefaultSpeed();
		data.accely = data.bml->getDefaultSpeed();
		data.direction = 0;
		data.speed = data.bml->getDefaultSpeed();
		//if(false==data.bml){return false;}
		//return true;
		BML_POOL::handle h = GetPool().push(data);
		//これ忘れちゃ行けない!!
		data.bml->setID(h);

		return (data.bml != NULL);
	}
	///XMLをアンロードする。@param h[in] ロード済みのXMLのハンドル(LoadBMLとかで取得した奴
	bool UnloadBML(handle h);

	void DrawTest(int Color){
		iterator it = begin();
		for(;it != end();it++){
			int x=(*it).x;
			int y=(*it).y;
			::DrawBox(x,y,x+4,y+4,Color,TRUE);
		}
	}
	void Move(){
		FreeMemoryHelper();

		iterator it = begin();
		for(;it != end();it++)
		{
			if((*it).bml){
				if((*it).bml->isEnd()) {
					//この関数ですべて解決。
					DeleteBulletHelper((*it));
					
					continue;
				}
				else
				{
					
					(*it).x += (*it).bml->getBulletSpeedX() * (*it).bml->getDefaultSpeed();
					(*it).y += (*it).bml->getBulletSpeedY() * (*it).bml->getDefaultSpeed();
					(*it).bml->run();
				}
			}else{
				(*it).x += (*it).accelx * 1;
				(*it).y += (*it).accely * 1;
			}
		}

	}
	


};


namespace dxex{
	

///static member var:bullet num

UINT DxExBulletMLRunnerStaticMemberVariable::mBulletNum = 0;

///frame の数

int DxExBulletMLRunnerStaticMemberVariable::mFrame = 0;


}//end of dxex namespace


namespace stg{

///static member (pool)
BulletMLManager::BML_POOL BulletMLManager::mBmlPool;

///static member (static variable reference)
BulletMLManager::BML_STATIC_DATA BulletMLManager::mBmlStaticData;


BulletMLManager::handle BulletMLManager::LoadBMLFile(const char *filename)
{
	if(false==dkutil::FileExist(filename)){
		throw std::runtime_error("存在しないファイルを引数に入れるな!");
	}

	DXEX_XMLPARSER_PTR p = DXEX_XMLPARSER_PTR(
		new BULLETML_PARSER("none"));

	try {
		p->parse_from_file(filename);
		//↓この処理が結構時間を食う
		p->build();
	}catch (BulletMLError be) {
		dkutil::dODS(be.what());
		throw;//また投げる^^;;;
	}
	//コンテナにぶち込む
	return mXMLC.push(p);
	
}



BulletMLManager::handle BulletMLManager::LoadBML(const char *memory_image_str)
{
	if(!memory_image_str){
		throw std::runtime_error("NULLを引数に入れるな!");
	}
	DXEX_XMLPARSER_PTR p = DXEX_XMLPARSER_PTR(
		new BULLETML_PARSER(memory_image_str));
	try {
		p->parse();
		//↓この処理が結構時間を食う
		p->build();
	}catch (BulletMLError be) {
		dkutil::dODS(be.what());
		throw;//また投げる^^;;;
	}
	//コンテナにぶち込む
	return mXMLC.push(p);
}

bool BulletMLManager::UnloadBML(BulletMLManager::handle h){
	//本当にスマートポインタは処理してくれるのだろうか?(結果。処理してくれるようだ。)
	mXMLC.pop(h);
	return true;
}

}//end of namespace

//**********************************************************
//**********************************************************
//**********************************************************
template<class Impl>
class smart_resource_handle{
	int mH;
	Impl mCreater;
	ref_obj *mpRef;
	///Non thread safe
	void inc_ref(){
		mpRef->inc_ref();
	}
	void dec_ref(){
		mpRef->dec_ref();
	}
	void construct_ref(){
		mpRef = NULL;
		mpRef = new ref_obj;
	}
	void dectory_ref(){
		if(mpRef){
			delete mpRef;
			mpRef = NULL;
		}
	}
public:
	typedef smart_resource_handle<Impl> self_type;

	smart_resource_handle(const smart_resource_handle<Impl> &x){
		mH = x.mH;

	}
	smart_resource_handle(int handle){
		mH = handle;

	}
	smart_resource_handle(const char *filename){
		int mH = mCreater.construct(filename);
		if(-1 == mH)
		{//まぁ、コンストラクタ内でTHROWは邪道だけど、許して^^;
			throw std::runtime_error("なんかハンドルが無効ってますが"); 
		}

	}
	virtual ~smart_resource_handle(){
		clear();
	}
	int get(){mCount++;return mH;}
	void free(){

		if(mCount < 0){
			throw std::runtime_error("freeした回数が多い。");
		}
		clear();
	}

	void clear(){
		if(0 == mCount){
			if(-1==mHandle){
				a.destroy(mHandle);
			}
		}
	}
};




//**********************************************************
//キーの検索高速化を考えた残骸


/*!
なんか意味なさそう・・・
*/

template<class K1,class K2,
class CONTAINER_1 = dkutil::map_ex<K1,K2> ,
class CONTAINER_2 = dkutil::map_ex<K2,K1> >
class double_linked_map{
public:
	typedef CONTAINER_1 CONTAINER1_TYPE;
	typedef CONTAINER_2 CONTAINER2_TYPE;
	typedef K1 KEY1_TYPE;
	typedef K2 KEY2_TYPE;
	typedef std::pair<K1,K2> DATA_TYPE;
private:
	MAP_KEY_TYPE mK;
	MAP_DATA_TYPE mD;
public:
	double_linked_map(){}
	~double_linked_map(){}

	//double_linked_map(
	void insert(const DATA_TYPE &x){
		




};

template<class K1,class K2,class T,class ARRAY_ONEBYONE_=dkutil::array_onebyone_ex<T> >
class double_key_map{
public:
	typedef ARRAY_ONEBYONE_ CONTAINER_TYPE;
	typedef typename CONTAINER_TYPE::size_type size_type;
	typedef typename CONTAINER_TYPE::handle handle;
	typedef K1 KEY1_TYPE;
	typedef K2 KEY2_TYPE;
	typedef std::multimap<K1,handle> KEY1_MAP;
	typedef std::multimap<K2,handle> KEY2_MAP;
	typedef boost::tuple<K1,K2,T> DATA_TYPE;
	
	//typedef std::pair<KEY1_MAP::iterator,bool> KEY1_RESULT;
	//typedef std::pair<KEY2_MAP::iterator,bool> KEY2_RESULT;
	typedef KEY1_MAP::iterator KEY1_RESULT;
	typedef KEY2_MAP::iterator KEY2_RESULT;
	struct RESULT{
		KEY1_RESULT key1_result;
		KEY2_RESULT key2_result;
	};
private:
	KEY1_MAP mK1;
	KEY2_MAP mK2;
	CONTAINER_TYPE mC;
public:
	double_key_map(){}
	virtual ~double_key_map(){}

	RESULT insert(const DATA_TYPE &x){
		

	}
	void erase(iterator position);                  // positionの位置の要素を削除。
	size_type erase(const key_type& x);             // xの値を持つ要素を削除。

	void clear(){}
};


///タスク処理対応にしてしまった。
class IResourceCache : public IOneFrameTask{
	UINT mLimit;
public:
	///キャッシュのデータ
	struct CHACH_DATA{
		CHACH_DATA(UINT ref) : ref_count(ref){}
		///ハンドル
		int handle;
		///参照カウント
		UINT ref_count;
		///オペレータ
		friend bool operator==(const CHACH_DATA &x,const CHACH_DATA &y){
			return (x.handle == y.handle);
		}
		friend bool operator<(const CHACH_DATA &x,const CHACH_DATA &y){
			return (x.handle < y.handle);
		}
		friend bool operator>(const CHACH_DATA &x,const CHACH_DATA &y){
			return (x.handle > y.handle);
		}
	};
	///グリエーター
	
	struct CHACH_FUNCTOR_GREATER{
		inline bool operator()(const CHACH_DATA &x,const CHACH_DATA &y)const{
			return (x.handle > y.handle);
		}
	};
	///内部コンテナの定義
	typedef dkutil::map_ex<std::string,CHACH_DATA> 	CONTAINER_TYPE;
protected:
	///キャッシュの溜める場所
	CONTAINER_TYPE mChach;
	///削除待ちキュー
	std::vector<int> mDelQueue;

	void  CacheHandle(int handle){
		if(-1==handle) throw std::runtime_error("こんなものキャッシュできん!ヽ(`Д´)ノムキィ");

	}
public:

	ResourceCache(){
		mLimit = 0;
	}
	virtual ~ResourceCache(){}
	///ロードするリミットを設定。
	void SetUpperLimit(UINT size){mLimit = size;}
	UINT void GetUpperLimit()const{return mLimit;}
	///キャッシュする(参照カウントをインクリメントする。)
	void  CacheHandle(int handle){
		
		CONTAINER_TYPE::iterator it = mCache.find(handle);
		if(it != mCache.end())
		{//キャッシュにすでに在った
			(*it).ref_count++;//カウンタをインクリメント
			return;//おしまい。
		}
		//キャッシュマップにぶち込む^^
		mCache.SetData(handle,CACHE_DATA(0));
		return;//end of proc
	}
	/*CONTAINER_TYPE::iterator find(const char *filename){
		return mCache.find(filename);
	}*/
	///キャッシュする
	void Cache(const char *filename){
		CONTAINER_TYPE::iterator it = mCache.find(handle);
		if(it != mCache.end())
		{//キャッシュにすでに在った
			(*it).ref_count++;//カウンタをインクリメント
			return;//おしまい。
		}
		//キャッシュマップにぶち込む^^
		mCache.SetData(filename,CACHE_DATA(0));

	}
		///キャッシュしている参照カウントをマイナスする
	virtual void Uncache(int handle) = 0;
	virtual void Uncache(const char *filename) = 0;

	///ロードする。(そして内部でキャッシュする)
	virtual int Load(const char *filename) = 0;
	///今、キャッシュしているサイズを返す。
	virtual UINT CacheSize() = 0;
	///強制削除する。参照カウントとは0になる。
	virtual void Unload(int handle) = 0;
	virtual void Unload(const char *filename) = 0;

};

//**********************************************************
//レジスト理系 since 2002/12/7
//**********************************************************


/*lpSubKey サブキーの名前 
lpValueName レジストリの名前
dwType タイプを設定する。詳しくはRegSetValueExにて
lpData Dataを入れる
cdData Dataのサイズを指定する
*/
bool SaveRegData(LPCTSTR lpSubKey,LPCTSTR lpValueName,DWORD dwType,CONST BYTE *lpData,	DWORD cbData){
	LONG r=ERROR_SUCCESS; 
	HKEY regKeyH;//レジストリのキーらしい
	DWORD sized;
	//レジストリから調べる
	r=RegCreateKeyEx(
		HKEY_CURRENT_USER,
		lpSubKey,//"DxLibSaverData\\Path",
		NULL, 
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		(PHKEY)&regKeyH,
		(LPDWORD)&sized 
		);
	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリを作れませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}

	r= RegSetValueEx(
		regKeyH,		// 現在オープンしているキーのハンドル
		lpValueName,	// 値の「名前」が入った文字列へのポインタ
		NULL,		// 予約パラメータ。0を指定する
		dwType,		// 値の「種類」を指定する。NULLで終わる文字列はREG_SZ、32ビット値はREG_DWORD
		(CONST BYTE *)lpData,	// 格納する値の「データ」が入ったバッファへのポインタ
		cbData		// lpDataのサイズを指定する
	);
	if(r!=ERROR_SUCCESS ){
		MessageBox(NULL, "レジストリに値を設定できませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	RegCloseKey(regKeyH);

	return true;
}

/*
lpSubKey,      サブキーの名前
lpValueName レジストリの名前
lpType 受け取るタイプ
lpData 受け取るデータ
lpcdData   lpDataのサイズを指定する。関数実行後はlpDataにコピーされたデータのサイズになる
*/
bool GetRegData(LPCTSTR lpSubKey,LPTSTR lpValueName,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData){
	LONG r=ERROR_SUCCESS; 
	HKEY regKeyH;//レジストリのキーらしい
	DWORD sized;
	//レジストリから調べる
	r=RegCreateKeyEx(
		HKEY_CURRENT_USER,
		lpSubKey,//"DxLibSaverData\\Path",
		NULL, 
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		(PHKEY)&regKeyH,
		(LPDWORD)&sized 
		);
	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリを作れませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	r= RegQueryValueEx(
		regKeyH,		// 現在オープンしているキーのハンドル
		 lpValueName,	// 取得する値の「名前」が入った文字列へのポインタ
		NULL,	// 予約パラメータ。NULLを指定する
		lpType,		// 値の「種類」を受け取る
		lpData,		// 値の「データ」を受け取る。NULLを指定することも可能だが、データは受け取れない
		lpcbData		// lpDataのサイズを指定する。関数実行後はlpDataにコピーされたデータのサイズになる
	);
	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリの中身を抜き取れませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	RegCloseKey(regKeyH);
	return true;
}

bool DeleteValueRegData(LPCTSTR lpSubKey,LPTSTR lpValueName)
//LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData
{
	LONG r=ERROR_SUCCESS; 
	HKEY regKeyH;//レジストリのキーらしい
	DWORD sized;
	//レジストリから調べる
	r=RegCreateKeyEx(
		HKEY_CURRENT_USER,
		lpSubKey,//"DxLibSaverData\\Path",
		NULL, 
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		(PHKEY)&regKeyH,
		(LPDWORD)&sized 
		);
	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリを作れませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	r=RegDeleteValueA(
			regKeyH,       //キーのハンドル
			lpValueName  //削除する値の名前
	);

	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリの中身を初期化(削除)できませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	RegCloseKey(regKeyH);
	return true;
}

//9x系では,下のキーを全て削除してしまうので気をつけるように。
bool DeleteRegData(LPCTSTR lpSubKey)
//LPTSTR lpValueName,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData
{
	LONG r=ERROR_SUCCESS; 
	HKEY regKeyH;//レジストリのキーらしい
	DWORD sized;
	//レジストリから調べる
	r=RegCreateKeyEx(
		HKEY_CURRENT_USER,
		lpSubKey,//"DxLibSaverData\\Path",
		NULL, 
		"",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS,
		NULL,
		(PHKEY)&regKeyH,
		(LPDWORD)&sized 
		);

	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリを作れませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	r=RegDeleteKey(
		HKEY_CURRENT_USER,
		lpSubKey
	);

	if(r!=ERROR_SUCCESS){
		MessageBox(NULL, "レジストリを初期化(削除)できませんでした。""設定値取得エラー", MB_OK);
		RegCloseKey(regKeyH);
		return(false);
	}
	RegCloseKey(regKeyH);
	return true;
}






//**********************************************************
//zlib の エンコードデコード(仕様に難あり よって使えない。)
//**********************************************************

/*!
@param z[in][out] z_stream構造体へのポインタ
@param encode_option[in] エンコード時のオプション(Z_FINISHとかZ_NO_FLUSHとか
@param src[in] 圧縮対象
@param srcsize[in] srcのサイズ
@param dest[out] 圧縮後の出力バッファ
@param dest[in] destのサイズ
@param result[out] 戻り値がfalseの時、ここに入れた変数が
 edk_FAILEDだとzlibのエラー。
 edk_BufferOverFlowだと出力バッファがなくなった(完全に出力できていない)事を示す。
@return trueだと成功
*/
///zlibでsrcバッファを圧縮し、destバッファに溜める
inline bool zlib_encode(z_stream *z,int encode_option,char *src,size_t srcsize,char *dest,size_t destsize,int *result)
{
	//input
	z->avail_in = srcsize;     // 入力バッファ中のデータのバイト数
	z->next_in = (BYTE *)src;
	//output
	z->next_out = (BYTE *)dest;// 出力ポインタ //
	z->avail_out = destsize;    // 出力バッファのサイズ //
	
	int state;//deflate result
	bool r = false;//result
	int tre = edk_SUCCEEDED;//extend result
	//::memset(dest,0,destsize);
	while(true){
		if(z->avail_in == 0)
		{//入力尽きたら終了
			tre = edk_InputBufferWasLost;
			break;
		}
		state =  ::deflate(z, encode_option); // 圧縮する //
		if (state == Z_STREAM_END){
			r = true;
			break//完了 
		}
		if (z->avail_out == 0)
		{ //出力バッファが尽きれば無事終了
			tre = edk_OutputBufferWasLost;
			break;
		}
		if (state != Z_OK)
		{
			tre = edk_FAILED;
			break;
		}
	}


	if(result){//insert extend result
		*result = tre;
	}
	
	return r;
}
/*!
@param z[in][out] z_stream構造体へのポインタ
@param src[in] 解凍対象
@param srcsize[in] srcのサイズ
@param dest[out] 解凍後の出力バッファ
@param dest[in] destのサイズ
@param result[out] 戻り値がfalseの時、ここに入れた変数が
 edk_FAILEDだとzlibのエラー。
 edk_BufferOverFlowだと出力バッファがなくなった(完全に出力できていない)事を示す。
@return trueだと成功
*/
///zlibでsrcバッファを圧縮し、destバッファに溜める
inline bool zlib_decode(z_stream *z,char *src,size_t srcsize,char *dest,size_t destsize,int *result=NULL)
{
	z->next_out = (BYTE *)dest;        // 出力ポインタ //
	z->avail_out = destsize;    // 出力バッファ残量 //
	int status = Z_OK;//inflate result
	bool r = false;//result
	int tre = edk_SUCCEEDED;//extend result
#error これはnext_outとかavail_outとかに再挿入しているから。直す事。

	//memset(dest,0,destsize);//まったく馬鹿なやつだ。
	z->next_in = (BYTE *)src;
	z->avail_in = srcsize;
	while (status != Z_STREAM_END)
	{
		if (z->avail_in == 0) {  // 入力残量がゼロになれば //
			tre = edk_InputBufferWasLost;
			break;
		}
		status = ::inflate(z, Z_SYNC_FLUSH ); // 展開 //
		if (status == Z_STREAM_END){
			r = true;
			break// 完了 //
		}
	//	DKUTIL_TRUE_ASSERT_OR_THROW(status != Z_OK,dkutil_exception("zlib inflate:%s",
		if (status != Z_OK) {
			// エラー //
			if(status == Z_DATA_ERROR)
			{	//エラーの復旧
				int lre = inflateSync(z); 
				/*
				フルフラッシュ地点が見つかれば、inflateSync は Z_OK を返す。入力デー
				タの供給がない場合は、Z_BUF_ERROR を返す。ファッシュ地点が見つから
				なければ、Z_DATA_ERROR を返す。ストリームの構造体がおかしな状態になっ
				ていれば、Z_STREAM_ERROR を返す。成功した場合、その時点で total_in
				の値は正しい圧縮データが見つかった位置を示すので、アプリケーション
				はその値を記憶しておくと良いかも知れない。エラーになった場合は、呼
				び出しが成功するか入力データの末尾に到達するまで、アプリケーション
				はさらに入力データを供給しながら繰り返し inflateSync を呼び出すと
				良い。
				*/
				if(lre==Z_OK) continue;
				if(lre==Z_DATA_ERROR)
				{//入力データが悪い!!
					tre = edk_InputBufferWasLost;
					break;
				}


			}
			
			tre = edk_FAILED;
			break;

		}
		if (z->avail_out == 0) 
		{// 出力バッファが尽きる
		//(つまり、一回でバッファに出力できない。もったいないけどエラー扱い。

			tre=edk_BufferOverFlow;
	
			break;
		}
	}

	if(result){//insert extend result
		*result=tre;
	}
	return r;
}


//**********************************************************


//**********************************************************
/*!

どちら様か、BNF記法の詳しいサイトどうか教えてください<(。_。)> ぺこぺこ
誰かboost::spiritで書いてください≦(._.)≧ ペコ(懇願<br>
*/

class INIManager{
public:
	struct DATA_TYPE{
		boost::any Any;
	};

	typedef	boost::spirit::file_iterator<char> file_iterator;
	typedef map_ex<std::string,DATA_TYPE> KEY_MAP;
	typedef KEY_MAP::DATA_TYPE KEY_DATA;
	typedef KEY_MAP::const_iterator const_key_iterator;
	//struct SECTION_DATA{
	//	KEY_MAP mMap;
	//};
	typedef map_ex<std::string,KEY_MAP> SECTION_MAP;
	//typedef SECTION_MAP::const_iterator const_iterator;
	typedef SECTION_MAP::DATA_TYPE SECTION_DATA;
	typedef SECTION_MAP::const_iterator const_section_iterator;
private:
	std::string mFileName;
	///入れるもの。
	SECTION_MAP mMap;
	enum NowState{
		///何もしていない
		eNone = 0,
		///セクションの括弧をロード中
		eSectionParenthesis,
		///セクションの名前をロード中
		eLoadSection,
		///キーをロード中
		eLoadKey,
		///Key=Paramのイコール部分だった。
		eEqual,
		///パラメータをロード中。
		eLoadParam,
		//スキップ文字列(スペースや改行)らしい。
		//eSkipSpace,
	};
	///今のstateの時の次の文字(c)をチェック。
	bool isErrorParsing(NowState state,char c){
		int r = false;
		switch(state){
		case eNone:
			if(!isSpace(c) || !isEnter(c) || c != '['){
				ErrorProcess();
				r = true;
			}
			break;
		case eSectionParenthesis://セクションの括弧をロード中
			if(c == ']'){
				ErrorProcess();
				r = true;
			}
			break;
		case eLoadSection:
			if(!isVisible(c) || isEnter(c)){
				ErrorProcess();
				r = true;
			}
			break;
		case eLoadKey://キーをロード中
			if(c == '[' || c == ']'){
				ErrorProcess();
				r = true;
			}
			break;
		case eEqual://Key=Paramのイコール部分だった。
			break;
		case eLoadParam://パラメータをロード中。
			if(c == '[' || c == ']'){
				ErrorProcess();
				r = true;
			}
			break;
		//case eSkipSpace://スキップ文字列(スペースや改行)らしい。
		//	break;
		default:
			DKUTIL_TRUE_ASSERT("enumに限ってありえない!");
			break;
		}
			
		return r;
	}
	void ErrorProcess(){
		DKUTIL_ASSERT(!"ERROR");
		//MB("ERROR");
	}
	bool isEnter(char c){
		if(c=='\n' || c==10 || c==14){
			return true;
		}
		return false;
	}
	std::string ScanString(file_iterator &it,file_iterator &end_it){
		std::string s;
		it++;
		for(;it != end_it;it++){
			if((*it) == '"'){it++; break;}
			if(isEnter((*it))){//変なところに改行がありあがった!えらーじゃ!
				ErrorProcess();
			}
			s += (*it);
		}
		return s;
	}
	std::string ScanParam(file_iterator &it,file_iterator &end_it)
	{
		std::string s;
		//スペース詰め
		for(;it != end_it;it++){
			if(isSpace((*it)))
				continue;
			else
				break;
		}
		//ロード
		for(;it != end_it;it++){
			
			if((*it) == '"'){
				//これはどうあがいても文字列だ!
				s = ScanString(it,end_it);
				break;
				//if(it == end_it) break;
			}else{
				s += (*it);					
			}			
			if(isEnter((*it))){//読み込み終了。
				break;
			}
		}
		return s;
		
	}
	NowState NextState(file_iterator &it,file_iterator &end_it){
		NowState sta = eNone;
		for(;it != end_it;it++){
			//スペースは飛ばすなり!
			if(isSpace((*it))){ continue;}
			//改行も飛ばすなり!
			if(isEnter((*it))){ continue;}
			//見えない文字なんか知らないなり!
			//if(false==isVisible((*it))){ continue;}
			if((*it) == ']'){
				ErrorProcess();
				break;
			}else if((*it) == '['){
				sta = eLoadSection;
				break;
			}else if(isVisible((*it))){
				sta = eLoadKey;		it--;
				break;
			}
		}

		return sta;
	}


				

	int Parsing(file_iterator &get_it)
	{
		file_iterator end_it = get_it.make_end();
		file_iterator it = get_it;

		SECTION_DATA rdata;
		KEY_DATA rkdata;

		std::string section;
		std::string key;
		std::string param;
		KEY_MAP kmap;
		//状態遷移保存
		enum NowState state = eNone;
		for(;it != end_it;it++){
			//スペースは飛ばすなり!
			if(isSpace((*it))){ continue;}
			//改行も飛ばすなり!
			if(isEnter((*it))){
				if(state == eLoadSection){
					ErrorProcess();
				}
				continue;
			}
			//見えない文字なんか知らないなり!
			if(false==isVisible((*it))){ continue;}
			
			switch(state){
			case eNone:
		
				if((*it) == '['){//お!セクション発見!
					state = eSectionParenthesis;
				}
				break;
			case eSectionParenthesis:
			case eLoadSection:
			//前の文字がセクションの括弧だった。または、セクションをロード中
				state = eLoadSection;
				if((*it) == ']'){
					state = eLoadKey;//次はキーを読み込む
					if(section.empty())
					{//何も入ってねぇ!
						ErrorProcess();
					}
					rdata.first = section;//セクション文字列をゲット
					section.clear();//読み込んだ文字をクリア
					break;
				}
				section += (*it);
				break;
			case eLoadKey:

				state = eLoadKey;
				if((*it) == '='){
					state = eEqual;//今イコールらしい。で、次はパラメータの読み込み。
					if(key.empty())
					{//何もありゃしねぇ
						ErrorProcess();
					}
					//rdata.second.first = key;//入れます^^p
					rkdata.first = key;
					key.clear();//削除
					break;
				}
				key += (*it);
				break;
			case eEqual:
			case eLoadParam:
				state = eLoadParam;
				param = ScanParam(it,end_it);
				//state = eNone;//最初の状態に戻る。administrator
				state = NextState(it,end_it);
				private_::ParsedStringToBoostAny(param.c_str(),&rkdata.second.Any);
				//private_::GetParsedStringType(param.c_str());
				//rdata.second.second.Any = param;//パラメタをセット!
				//rkdata.second.Any = param;
				//データぶち込み〜〜
				kmap.clear();
				kmap.insert(rkdata);
				rdata.second = kmap;
				if(false==mMap.isInserted( mMap.insert(rdata) ))
				{
					SECTION_MAP::iterator it = mMap.find(rdata.first);
					if(it==mMap.end()){
						ErrorProcess();
					}
					if(false == (*it).second.isInserted(
						(*it).second.insert(rkdata) 
						)){
						ErrorProcess();

					}
				}
				param.clear();

				if(it == end_it) return 0;
				break;
			default:
				break;
			}
			/*
			//何もしてないなり
			if(state == eNone){
				if((*it) == '['){//お!セクション発見!
					state = eSectionParenthesis;
				}
			}
			//前の文字がセクションの括弧だった。または、セクションをロード中
			if(state == eSectionParenthesis || state == eLoadSection)
			{
				state = eLoadSection;
				if((*it) == ']'){
					state = eLoadKey;//次はキーを読み込む
					if(section.empty())
					{//何も入ってねぇ!
						ErrorProcess();
					}
					rdata.first = section;//セクション文字列をゲット
					section.clear();//読み込んだ文字をクリア
				}
				section += (*it);
			}
			//キーをロード中
			if(state == eLoadKey)
			{
				state = eLoadKey;
				if((*it) == '='){
					state = eEqual;//今イコールらしい。で、次はパラメータの読み込み。
					if(key.empty())
					{//何もありゃしねぇ
						ErrorProcess();
					}
					//rdata.second.first = key;//入れます^^p
					rkdata.first = key;
					key.clear();//削除
				}
				key += (*it);
			}
			//イコールか、パラメータロード中
			if(eEqual==state || eLoadParam==state){
				state = eLoadParam;
				param = ScanParam(it,end_it);
				state = eNone;//最初の状態に戻る。administrator
				private_::GetParsedStringType(param.c_str());
				//rdata.second.second.Any = param;//パラメタをセット!
				rkdata.second.Any = param;
				//データぶち込み〜〜
				KEY_MAP kmap;
				kmap.insert(rkdata);
				rdata.second = kmap;
				mMap.insert(rdata);
				param.clear();

				if(it == end_it) break;



			}
			*/
			isErrorParsing(state,*(it + 1));

				
			
			
			
			
			
			

		}//end of for
		return 0;
		
	}

public:
	INIManager(const char *filename=NULL){
	}
	virtual ~INIManager(){}
	bool reset(const char *filename){
		if(FileExist(filename)==falsereturn false;
		mFileName = filename;
		mMap.clear();
		file_iterator f(filename);
		Parsing(f);
	}
	/*
	void reset(const char *str){
		mbuf = str;
		Parsing(mbuf,mC);
	}*/
	bool empty(){	return mMap.empty();}
	void clear(){mFileName.clear();mMap.clear();}
	const_section_iterator begin()const{return mMap.begin();}
	const_section_iterator end()const{return mMap.end();}

};


//**********************************************************
/*
INIOperator ... iniファイルを操作するクラスです。
なぜ、このクラスを作るのを止めたかと言うと、
Windows95系だとWin32APIを使った読み込みはちと、制限がありすぎるからです。
なので、boost::spiritでも使って書き直そうと思います^^
では〜〜。
*/
//**********************************************************
class INIOperator{
#	define ini_exception(s) std::runtime_error("INIOperator::" + s);

	std::string mFileName;
	struct Win9xData{
		bool LoadOKFlag;
	};
	map_ex<std::string,Win9xData> mMap;
	void CheckException(){
		if(mFileName.empty()){
			throw ini_exception("exist error/not defined filename")
		}
	}
	/*!
	@note
	この関数の意義<br>
	<b>GetPrivateProfileSection</b><br>
	Windows 95:<br>
	セクションのサイズは32KBを超えてはいけません。<br>
	Windows NT:<br>
	セクションのサイズに制限はありません。<br>
	@return false/このiniファイルはすべて読み込めない。
	*/
	///Windows9x系のチェック。
	bool CheckWin9x(const char *filename){
		

public:
	INIOperator(const char *filename){}
	virtual ~INIOperator(){}
	bool reset(const char *filename){
		if(false==CheckWin9x(filename)){
			return false;
		}

		mFileName = filename;
	}
	/*!
	@param SectionName[in] セクション名へのポインタ
	@param Buffer[out] バッファへのポインタ
	@param Size[in] バッファのサイズ
	@param FileName[in] ファイルの名前
	@return 
	*/
	static int LoadSectionLogic(LPCTSTR SectionName,
						LPTSTR Buffer,DWORD Size,
						LPCTSTR FileName)
	{
		DWORD r;
		if(false==CheckWin9x()){ return edk_FAILED;}
		r = GetPrivateProfileSection(SectionName,Buffer,Size,FileName);
		if(r == Size - 2){	return edk_BufferOverFlow;}
		

		return edk_SUCCEEDED;
	}


	
  ///ini ファイルからセクション全体を削除する
	bool delete_section( const char *SectionName )
	{
		CheckException();
		return WritePrivateProfileString( SectionName, NULL, NULL, mFileName.c_str() );
	}
	///  ini ファイルからキーを削除する
	bool delete_key( const char *SectionName, const char *KeyName)
	{	
		CheckException();
		return WritePrivateProfileString( SectionName, KeyName,
			NULL, mFileName.c_str() );
	}
	/// キーが ini ファイルに存在するかどうかを確かめる。
	bool exist( const char *SectionName, const char *KeyName )
	{
		CheckException(); ;
		// 指定したキーが見つからない場合、
		//関数 GetPrivateProfileInt() は1回目の呼び出しで0を、
		//2回目の呼び出しで1を返す。
		return (
			GetPrivateProfileInt(
				SectionName, KeyName, 0, mFileName.c_str() 
				) == 	GetPrivateProfileInt(
			SectionName, KeyName, 1, FileName)
			);
	}
#	undef ini_exception
};
広告 [PR]スキンケア  転職 化粧品 無料 ライブチャット