/**
@filename pack.hpp
@brief ファイルのヘッダを暗号化してアーカイブにする
@note
ファイルのヘッダを暗号化してパックする
<PRE>
ファイル先頭にシグネチャあり
デフォルトでヘッダに暗号化あり
SHA512によるチェックサム付き
1要素毎にキーのサイズ＋etc のヘッダ
ファイルは数ギガのまで対応可能（理論上）
</PRE>
物好きならこれを元に改造しちゃうでしょう。

@section dkutil_archive_pack_hpp_history 更新履歴
<PRE>
2005/10/08:四苦八苦してとりあえず完成 
2005/10/05:作成開始 すぐに飽きて終了
</PRE>
*/
#ifndef DKUTIL_ARCHIVE_PACK_HPP
#define DKUTIL_ARCHIVE_PACK_HPP

#include <dkutil/archive/reserve.hpp>
#include <dkutil/filesystem/littleendian_filestream.hpp>
#include <dkutil/dktl/adapters.hpp>
#include <dkutil/parser/string_util.hpp>
#include <dkutil/signature/sha512.hpp>
#include <dkutil/signature/signature_buffer.hpp>
#include <dkutil/filesystem/utility.hpp>
#include <dkutil/cryptograph/arcfour.hpp>
#include <dkutil/archive/extract.hpp>

namespace dkutil{

	struct CPackArchiveDefine{
		BOOST_STATIC_CONSTANT(uint32,signature = eda_Pack);
		typedef big_filestream fs_type;
		typedef signature_buffer_bin<CSHA512> sha512buffer_type;
		typedef CArcfourStreamCipherConvert header_cipher_encoder;
		typedef CArcfourStreamCipherConvert header_cipher_decoder;
		struct header_type{
			uint32 a_signature;
			uint64 b_listnum;
			//datalistのSHA512
			signature_buffer_bin<CSHA512> c_datalists_sha;
			uint64 d_datalists_size;
			///pack archiveのバージョン
			uint32 f_version;
			void serialize(ISerializeStream *p)
			{
				*p << a_signature;
				*p << b_listnum;
				c_datalists_sha.serialize(p);
				*p << d_datalists_size;
				*p << f_version;
			}
			///@return シリアライズする時のファイルに出力するサイズを返す。
			size_t size()const{
				size_t size = sizeof(a_signature);
				size += sizeof(b_listnum);
				size += c_datalists_sha.size();
				size += sizeof(d_datalists_size);
				size += sizeof(f_version);
				return size;
			}
			bool seek_next(fs_type *p)const
			{
				return p->seek(size(),seek_current);
			}
		};
		typedef size_t size_type;
		
		///データの並び構造
		struct data_list{
			///キーデータ名
			shared_buffer a_key;
			///ファイルの先頭から何byteか？
			uint64 b_length;
			///ファイルのサイズ
			uint64 c_filesize;
			///このデータのSHA512値
			signature_buffer_bin<CSHA512> d_sha512;

			bool setKey(uint8 *key,size_t keysize){
				if(false==a_key.reset(keysize)) return false;
				
				memcpy(a_key.get(),key,a_key.size());
				return true;
			}
			bool setSHA(uint8 *sha512,size_t sha512size)
			{	
				if(sha512size != d_sha512.size()) return false;
				memcpy(d_sha512.get(),sha512,d_sha512.size());
				return true;
			}
			void serialize(ISerializeStream *p)
			{	
				//*p << a_key;
				a_key.serialize(p);
				*p << b_length;
				*p << c_filesize;
				d_sha512.serialize(p);
			}
			void crypt_serialize(IConvertSerializeStream::convert_ptr obj,
				IConvertSerializeStream *p)
			{
				p->setConvertStream(obj);
				serialize(p);
			}


			void load_sig(ISignature *ps)
			{
				CEndianIndependentStreamAdapter e;
				CSignatureLoadStreamAction loader(ps);
				e.reset(&loader,
					CEndianIndependentStreamAdapter::isLittleEndian(),
					CSignatureLoadStreamAction::is_read
				);
				/*
				ps->load(a_key,sizeof(a_key));
				ps->load(&b_length,sizeof(b_length));
				ps->load(&c_filesize,sizeof(c_filesize));
				ps->load(d_sha512.get(),d_sha512.size());
				*/
				a_key.serialize(&e);
				e << b_length;
				e << c_filesize;
				d_sha512.serialize(&e);
			}
			///@return シリアライズする時のファイルに出力するサイズを返す。
			size_t size()const{
				size_t t = 0;
				t += a_key.serialize_size();
				t += sizeof(b_length) + sizeof(c_filesize);
				t += d_sha512.serialize_size();
				return t;
			}
			bool seek_next(fs_type *p)const{
				return p->seek(size(),seek_current);
			}
			friend bool operator<(const data_list &x,const data_list &y)
			{
				bool r = (x.a_key.get() < y.a_key.get());
				//bool r = memcmp(x.a_key.get(),y.a_key.get();
				return r;
			}
			friend bool operator==(const data_list &x,const data_list &y)
			{
				if(x.a_key.size() != y.a_key.size()) return false;
				bool r = 0==memcmp(x.a_key.get(),y.a_key.get(),x.a_key.size());
				return r;
			}
			friend bool operator!=(const data_list &x,const data_list &y)
			{
				return !operator==(x,y);
			}

				
		};
		struct data_list_fast_less : public std::binary_function<const data_list,const data_list,bool>
		{
			bool operator()(const data_list &x,const data_list &y)
			{
				bool r = (x.a_key.get() < y.a_key.get());
				return r;
			}
		};
		
		///SHA512を計算させると共にwrite()する。
		typedef write_with_hash_calculate_functor<fs_type,CSHA512> write_withSHA512_functor;
		class write_withSHA512_callback_functor /*: public write_withSHA512_functor*/
		{
			IdKingyoArchiveCallback *mpcb;
			CSHA512 *mpsha;
			fs_type *mpfs;
			size_t mCurrentOffset,mCurrentSize,mCurrentBegin;
			IdKingyoArchiveGenerate *mpThis;
			const void *mpKey;
			size_t mKeySize;
		public:
			write_withSHA512_callback_functor(fs_type *fs,CSHA512 *psha,
				IdKingyoArchiveCallback *pcb,
				size_t target_file_size,size_t currentBegin,IdKingyoArchiveGenerate *pThis,
				const void *pKey,size_t KeySize) 
			{
				mpcb = pcb;
				mpsha = psha;
				mpfs = fs;
				mCurrentOffset = 0;
				mCurrentSize = target_file_size;
				mCurrentBegin = currentBegin;
				mpThis = pThis;
				mpKey = pKey;
				mKeySize = KeySize;
			}
			bool operator()(/*const*/ uint8 *buff,size_t size){
				mpsha->load(buff,size);
				if(mpcb)
				{
					dKingyoArchiveCallbackArg arg;
					arg.mCurrentSize = mCurrentSize;
					arg.mCurrentOffset = mCurrentOffset;
					arg.mCurrentBegin = mCurrentBegin;

					arg.mCurrentWorkBuffer = buff;
					arg.mCurrentWorkBufferSize = size;

					arg.mCurrentKey = (const void *)mpKey;
					arg.mCurrentKeySize = mKeySize;

					//今のアーカイブのサイズ
					arg.mArchiveSize = mpfs->size();
					arg.mArchiveOffset = mpfs->tell();


					//今処理しているアーカイブの名前
					arg.archive_name = mpfs->filename();

					//callbacking
					mpcb->callback(static_cast<void *>(mpThis),&arg);
				}
				return mpfs->write(buff,size);
			}

		};
		typedef read_with_hash_calculate_functor<fs_type,CSHA512> read_withSHA512_functor;
	};
	/**
	仕様：little endian base
	*/
	template<class DEFINE_T = CPackArchiveDefine>
	class CdKingyoArchiveGenerate : public CArchiveGenerateReserve , public DEFINE_T
	{
	public:
		
		typedef CPackArchiveDefine::fs_type fs_type;
		typedef CArchiveGenerateReserve base_type;

		typedef CdKingyoArchiveGenerate self_type;
		typedef base_type::container_type container_type;
		typedef DEFINE_T define_type;
		//typedef define_type::write_withSHA512_functor write_withSHA512_functor;
		typedef define_type::read_withSHA512_functor read_withSHA512_functor;
		typedef define_type::header_cipher_encoder header_cipher_encoder;
		typedef define_type::write_withSHA512_callback_functor write_withSHA512_callback_functor;
		typedef define_type::data_list data_list;
		static uint32 getSignature(){
			return signature;
		}
		///これでversion1
		BOOST_STATIC_CONSTANT(uint32,version = 0x00000010);
		static uint32 getVersion(){
			return version;
		}
	protected:

		typedef std::list<data_list> archive_list;

		
		std::ostream *mPS;
		void setLog(const char *str){
			if(mPS)
				*mPS << str;
		}
		//IConvertSerializeStream::convert_ptr mCS;
	public:

		
		CdKingyoArchiveGenerate(){
			//reset(filename);
			mPS = NULL;
			//mCS = NULL;
		}
		virtual ~CdKingyoArchiveGenerate(){
			clear();
		}
		void clear(){
			base_type::clear();
		}
		void setOutputStream(std::ostream *p){
			mPS = p;
		}
		//ファイル全体の出力に変換プログラムを挿入する
		//void setConvertStream(IConvertSerializeStream::convert_ptr p){	mCS = p;}
		/**
		アーカイブを生成する
		*/
		virtual bool generate(const dKingyoArchiveGenerateOption &x)
		{
		
			uint64 al_offset;
			uint64 allsize = 0;
			uint64 data_length_count = 0;
			std::string filename = x.mFilename;
			fs_type FStream;//scope outを狙っている
			if(false==FStream.reset(filename,write_mode | binary_mode))
			{
				return false;
			}
			if(false==FStream.open()){
				return false;
			}
			

			if(FStream.error()){
				return false;
			}
			archive_list al;
			//データを読み込む
			{
				size_t size = mC.size();
				container_type::iterator it = mC.begin();
				for(;it != mC.end();it++)
				{
					const dKingyoArchiveReserveElement &a = (*it);
					data_list dl;
					if(a.mIsFile)
					{
						if(false==FileExist(a.mFilename.c_str())){
							setLog(a.mFilename.c_str());
							setLog("が存在しません。\n");
							continue;
						}
						uint64 filesize;
						if(false==GetFileSize(a.mFilename,&filesize)){
							dMB("んなあほな");
							continue;
						}
						if(0==filesize){
							setLog(a.mFilename.c_str());
							setLog("はファイルサイズが0です。\n");
						}

						allsize += filesize;

						dl.c_filesize = filesize;
						//if(a.mKey.size() > sizeof(dl.key)){
						if(false==dl.setKey(a.mKey.get(),a.mKey.size() ))
						{
							//setLog(filename);
							setLog(a.mFilename.c_str());
							setLog("keyのサイズが大きすぎます。\n");
							continue;
						}
						//dl.key = a.mKey;
						//dl.length = data_length_count;
						//dl.b_length = FStream.tell();
					
						al.push_back(dl);

					}else{//memory buffer
						dl.c_filesize = a.mBuffer.size();
						//dl.b_length = FStream.tell();

						if(false==dl.setKey(a.mKey.get(),a.mKey.size())){
							//memcpy(dl.a_key.get(),a.mKey.get(),sizeof(dl.a_key));
							std::string str;
							to_string_or_data_hex(str,a.mKey.get(),
								(a.mKey.size() > 1024) ? 1024 : a.mKey.size());
							str += "...";
							setLog("memory : ");
							setLog(str.c_str());
							setLog(" / keyのサイズが大きすぎます。\n");
							continue;
						}



						//
						al.push_back(dl);

					}//end of file or memory 

				}//end of registed element iterate



			}

			FStream.seek(0,seek_begin);
			header_type h;
			//ヘッダ準備
			{
				
				{
					uint32 sig = getSignature();
					h.a_signature = sig;
				}
				uint64 temp = al.size();
				h.b_listnum = temp;//header write
				//uint8 sha512size[SHA512_BUFFER_BIN_SIZE];
				//h.c_datalists_sha(sha512size,sizeof(sha512size));//header temp write
				
				archive_list::iterator it = al.begin();
				uint64 dl_size = 0; 
				for(;it != al.end();it++)
				{
					dl_size += (*it).size();
				}
				h.d_datalists_size = dl_size;
				h.f_version = getVersion();

				//あえて書き込み
				//h.serialize(&FStream);
				h.seek_next(&FStream);

			}
			//データリスト分シーク
			{
				archive_list::iterator it = al.begin();
				for(;it != al.end();it++)
				{
					//(*it).serialize(&FStream);
					(*it).seek_next(&FStream);
				}
			}
			//データ書き込み
			{
				container_type::iterator it = mC.begin();
				archive_list::iterator alit = al.begin();
				CSHA512 sha;
				for(;it != mC.end();it++,alit++)
				{
					const dKingyoArchiveReserveElement &a = (*it);
					data_list &dl = (*alit);

					dl.b_length = FStream.tell();
					if(a.mIsFile){
						{
							fs_type rs;
							if(false==rs.reset(a.mFilename.c_str(),read_mode | binary_mode) || 
								false==rs.open())
							{
								setLog(a.mFilename.c_str());
								setLog("がリードモードでオープンできません。\n");
								continue;
							}
							
							typedef write_withSHA512_callback_functor wwft;
							//CSHA512 sha;
							//write_withSHA512_functor func(&FStream,&sha);
							wwft func(&FStream,&sha,x.process_callback,rs.size(),
								FStream.tell(),this,dl.a_key.get(),dl.a_key.size());
							div_read_each_functor<fs_type,wwft> div_read_each;
							div_read_each(&rs,func);
							sha.final();
							dl.d_sha512.set_output(&sha);
							//sha.getSignature(dl.d_sha512,sizeof(dl.d_sha512),binary_signature);
							
						}

					}else{//memory
						{
							sha.load(a.mBuffer.get(),a.mBuffer.size());
							sha.final();
							dl.d_sha512.set_output(&sha);
							//sha.getSignature(dl.d_sha512,sizeof(dl.d_sha512),binary_signature);
						}
						if(x.process_callback){
							dKingyoArchiveCallbackArg arg;
							arg.mCurrentSize = a.mBuffer.size();
							arg.mCurrentOffset = 0;
							arg.mCurrentBegin = 0;

							arg.mCurrentWorkBuffer = (void *)a.mBuffer.get();
							arg.mCurrentWorkBufferSize = a.mBuffer.size();

							arg.mCurrentKey = (const void *)a.mKey.get();
							arg.mCurrentKeySize = a.mKey.size();

							//今のアーカイブのサイズ
							arg.mArchiveSize = FStream.size();
							arg.mArchiveOffset = FStream.tell();


							//今処理しているアーカイブの名前
							arg.archive_name = FStream.filename();

							//callbacking
							x.process_callback->callback(static_cast<void *>(this),&arg);
						}
						FStream.write(a.mBuffer.get(),a.mBuffer.size());
					}
					sha.init();
				}//eof


			}
			//ヘッダ書き込み
			{
				//巻き戻し
				FStream.seek(0,seek_begin);
				header_cipher_encoder *ttp = //new header_cipher_encoder((PasswordOption &)x,x.workbuffer_size);
					new header_cipher_encoder((PasswordOption &)x);
				//arcfourで暗号化
				IConvertSerializeStream::convert_ptr cp;
				cp.reset(ttp);
				archive_list::iterator it = al.begin();
				
				CSHA512 sh;
				for(;it != al.end();it++){
					data_list &a = (*it);
					a.load_sig(&sh);
				}
				//signature_buffer_bin<CSHA512> sbb;
				//sbb.set_output(&sh);
				h.c_datalists_sha.set_output(&sh);
				h.serialize(&FStream);//header write
				
				//data list write
				for(it = al.begin();it != al.end();it++)
				{
					data_list &a = (*it);
					a.crypt_serialize(cp,&FStream);
				}
			}
			//FStream.clear();

			return true;

		}
		
	};
	template<class DEFINE_T = CPackArchiveDefine>
	class CdKingyoArchiveExtract : public IdKingyoArchiveExtract , public DEFINE_T
	{
	public:
		typedef IdKingyoArchiveExtract base_type;
		BOOST_STATIC_CONSTANT(uint32,signature = eda_Pack);
		uint32 getSignature()const{return signature;}
		typedef DEFINE_T define_type;
		typedef define_type::fs_type fs_type;
		typedef define_type::data_list data_list;
		//typedef define_type::data_list_less data_list_less;
	
		typedef define_type::write_withSHA512_functor write_withSHA512_functor;
		typedef define_type::read_withSHA512_functor read_withSHA512_functor;
		typedef define_type::header_cipher_decoder header_cipher_decoder;
		typedef define_type::sha512buffer_type sha512buffer_type;
		typedef define_type::header_type header_type;
	protected:
		fs_type mFS;
		std::ostream *mPS;
//#define CdKingyoArchiveExtract_SET 1
#if CdKingyoArchiveExtract_SET
		typedef set_ex_adapter<std::set<data_list> > container_type; 
#else
		typedef map_ex_adapter<std::map<key_type,data_list> > container_type;
#endif
		///データリスト
		container_type mDL;
		typedef container_type::iterator iterator;
		typedef container_type::const_iterator const_iterator;
		void setLog(parm_string str){
			if(mPS)
				*mPS << str.c_str();
		}
		void signature_error_log(const sha512buffer_type &origin,const sha512buffer_type &c)
		{
			setLog("シグネチャが合いませんでした。\n");
			setLog("  origin :");
			setLog(toHexString(origin.get(),origin.size()));
			setLog("\n");
			setLog("  current:");
			setLog(toHexString(c.get(),c.size()));
			setLog("\n");
		}
		iterator find_it(const key_type &key){
#if CdKingyoArchiveExtract_SET
			data_list d;
			d.a_key = key;
			return mDL.find(d);
#else
			return mDL.find_by_key(key);
#endif
		}
		IConvertSerializeStream::convert_ptr mCS;
	public:	
		CdKingyoArchiveExtract(){
			mPS = NULL;
		}
		virtual ~CdKingyoArchiveExtract(){
			clear();
		}
		void setOutputStream(std::ostream *p){
			mPS = p;
		}
		///@return 対象のアーカイブファイルらしかったらtrue
		virtual bool isArchive(parm_string archive_filename){
			fs_type fs;
			bool f;
			f = fs.reset(archive_filename,read_mode | binary_mode);
			if(false==f) return false;
			f = fs.open();
			if(false==f) return false;
			uint32 t;
			fs << t;
			if(getSignature() != t) return false;
			return true;
		}

		bool v1_analysis(const dKingyoArchiveExtractOption &x,header_type &h){
			
			CSHA512 sha;
			data_list t;
			typedef std::vector<data_list> dlvec;
			dlvec tv;
			IConvertSerializeStream::convert_ptr cp;
			
			//cp.reset(new header_cipher_decoder((PasswordOption &)x,x.workbuffer_size));
			cp.reset(new header_cipher_decoder((PasswordOption &)x));
			for(uint64 i=0;i<h.b_listnum;i++)
			{
				t.crypt_serialize(cp,&mFS);
				t.load_sig(&sha);
				tv.push_back(t);
			}
			sha512buffer_type buff;
			buff.set_output(&sha);
			if(h.c_datalists_sha != buff){
				setLog("data listのシグネチャが合わない。\n");
				signature_error_log(h.c_datalists_sha,buff);
				return false;
			}
			{for(dlvec::iterator it = tv.begin();it != tv.end();it++)
			{
#if CdKingyoArchiveExtract_SET
				if(false==mDL.rb_insert((*it))){
#else
				key_type key;
				shared_buffer &tk = (*it).a_key;
				key.copy(tk.get(),tk.size());
				tk.clear();
				if(false==mDL.SetData(key,(*it))){
#endif
					setLog("同じkeyが発見されました。このアーカイブは仕様に沿わないのでエラーとします。\n");
					return false;
				}
			}}
#ifdef _DEBUG
			{for(const_iterator it = mDL.begin();it != mDL.end();it++)
			{
				std::string str;
				
#	ifdef CdKingyoArchiveExtract_SET
				to_string_or_data_hex(str,(*it).a_key.get(),(*it).a_key.size());

#	else
				to_string_or_data_hex(str,(*it).first.get(),(*it).first.size());
#	endif
				setLog(str);
				setLog("\n");
			}}
#endif
			return true;
		}

		virtual bool open(const dKingyoArchiveExtractOption &x)
		{
			if(false==FileExist(x.mFilename)){
				setLog(x.mFilename);
				setLog("が存在しません。");
				return false;
			}
			if(false==mFS.reset(x.mFilename,read_mode | binary_mode)){
				setLog(x.mFilename);
				setLog("filestream reset error");
				return false;
			}
			if(false==mFS.open()){
				setLog(x.mFilename);
				setLog("filestream open error");
				return false;
			}
			header_type h;
			h.serialize(&mFS);
			bool r;
			switch(h.f_version){
			case 0x00000010:
				r = v1_analysis(x,h);
				break;
			default:
				setLog("未対応のVersion");
				to_hex_string_functor<uint32> hx;
				setLog(hx(h.f_version));
				setLog("\n");
				r = false;
				break;
			}

			return r;
		}
		virtual bool find(const key_type &key){
			iterator it = find_it(key);
			return it != mDL.end();
		}
		struct shared_buffer_writer{
			shared_buffer *mP;
			size_t offset;
			shared_buffer_writer(shared_buffer *p) : mP(p){}
			void write(const void *buff,size_t size){
				//if(offset + size > mP->size()){
					//mP->

				memcpy(mP->get() + offset,buff,size);
				offset += size;
			}
		};
		//typedef read_with_hash_calculate_functor<shared_,CSHA512> read_with_sha512_functor;
		virtual bool extractToMemory(shared_buffer &dest,const key_type &key){
			iterator it = find_it(key);
			if(it == mDL.end()) return false;
			
#if CdKingyoArchiveExtract_SET
			const data_list &dl = (*it);
#else
			const data_list &dl = (*it).second;
#endif
			if(false==mFS.seek(dl.b_length,seek_begin)){
				setLog("seek 失敗.\n");
				return false;
			}
			if(false==dest.reset(dl.c_filesize)){
				setLog("extractToMemory() dest / out of memory.\n");
				return false;
			}
			/*if(false==mFS.read(dest.get(),dest.size())){
				setLog("extractToMemory() read failed.\n");
				return false;
			}*/
			CSHA512 sha;
			shared_buffer_writer writer(&dest);
			typedef write_with_hash_calculate_functor<shared_buffer_writer,CSHA512> wht;
			wht rst(&writer,&sha);
			div_read_limit_functor<fs_type,wht> div_read;
			div_read(&mFS,rst,dl.c_filesize);
			sha512buffer_type buff;
			buff.set_output(&sha);
			

			if(buff != dl.d_sha512){
				setLog("extractToMemory() ");
				signature_error_log(dl.d_sha512,buff);
				return false;
			}
			
			return true;
		}
		virtual bool extractToFile(parm_string filename,const key_type &key){
			iterator it = find_it(key);
			if(it == mDL.end()) return false;
			
			
#if CdKingyoArchiveExtract_SET
			const data_list &dl = (*it);
#else
			const data_list &dl = (*it).second;
#endif
			if(false==mFS.seek(dl.b_length,seek_begin)){
				setLog("seek 失敗.\n");
				return false;
			}

			//ファイルに書き込み処理
			fs_type rs;
			if(false==rs.reset(filename,write_mode | binary_mode) || 
				false==rs.open())
			{
				setLog(filename.c_str());
				setLog("がwrite modeでオープンできません。\n");
				return false;
			}
			
			
			CSHA512 sha;
			write_withSHA512_functor func(&rs,&sha);
			div_read_limit_functor<fs_type,write_withSHA512_functor> div_read;
			div_read(&mFS,func,dl.c_filesize);
			sha.final();
			sha512buffer_type buff;
			buff.set_output(&sha);
			//sha.getSignature(dl.d_sha512,sizeof(dl.d_sha512),binary_signature);
			
			if(buff != dl.d_sha512){
				setLog(filename.c_str());
				signature_error_log(dl.d_sha512,buff);
				return false;
			}

			return true;
		}
		virtual bool clear(){
			mFS.close();
			mDL.clear();
			mPS = NULL;
			return true;
		}
		friend CExtractStream;
		
		virtual CExtractStream *createExtractStream(
			const extract_option &option,const key_type &key)
		{
			iterator it = find_it(key);
			if(mDL.end() == it) return NULL;
			
#if CdKingyoArchiveExtract_SET
			const data_list &dl = (*it);
#else
			const data_list &dl = (*it).second;
#endif
			size_t ws;
			if(option.read_once_size > option.work_buffer_size){
				ws = option.read_once_size;
			}else{
				ws = option.work_buffer_size;
			}
			CExtractStream *p = new CExtractStream(
				ws,option.read_once_size
			);
			p->setArchiveOption(dl.b_length,dl.b_length,dl.c_filesize);
			/*p->mArchiveOffset = dl.b_length;
			p->mArchiveSize = dl.c_filesize;
			p->mArchiveOffsetBegin = dl.b_length;*/
			//p->setArchiveOffset(dl.b_length);
			//p->setArchiveSize(dl.c_filesize);
			return p;
		}
		virtual bool readArchive(CExtractStream *p,size_t *readsize)
		{
			if(false==mFS.seek(p->archive_offset(),seek_begin)){
				setLog("seek 失敗.\n");
				return false;
			}
			
			scoped_buffer sb(p->get_read_size());
			
			//read operation size
			size_t ropsize;
			size_t a_offset = p->archive_offset();
			size_t a_end_offset = p->archive_offset_begin() + p->archive_size();
			
			if(TRUE==dkcCheckOverflow64(sb.size(),a_offset) 
				|| TRUE==dkcCheckOverflow64(p->archive_size(),a_offset)
				|| sb.size() + a_offset > a_end_offset)
			{
				ropsize = a_end_offset - a_offset;
			}else{
				ropsize = sb.size();
			}
			try{
				mFS.responsible_read(sb.get(),ropsize);
			}catch(stream_error e){
				setLog(e.what());
				setLog(" / CdKingyoArchiveExtract::readArchive() read error\n");
				*readsize = 0;
				return false;
			}
			size_t ws;
			//if(false==p->write(sb.get(),sb.size(),&ws)){
			if(false==p->write(sb.get(),ropsize,&ws))
			{
				setLog("CdKingyoArchiveExtract::readArchive() CExtractStream write error");
				return false;
			}
			*readsize = ropsize;
			{
				size_t ttt = p->archive_offset() + ropsize;
				p->setArchiveOffset(ttt);
			}
			//p->mArchiveOffset += ropsize;

			dkcmASSERT(ropsize == ws);
			//*readsize = sb.size();
			return true;
		}
		virtual bool destroyExtractStream(CExtractStream *p){
			if(!p) return false;
			delete p;
			return true;
		}

		//ファイル全体の出力に変換プログラムを挿入する
		//void setConvertStream(IConvertSerializeStream::convert_ptr p){mCS = p;}
	};
	typedef CdKingyoArchiveGenerate<> CPackArchiveGenerate;
	typedef CdKingyoArchiveExtract<> CPackArchiveExtract;

}//end of dkutil namespace



#endif