/**
@filename zlib.hpp
@note
zlibのラッパー
zlibのプロジェクトを加えて依存関係などを設定してコンパイルすると
zlibの情報もデバッガで見る事が出来ます。

*/
#ifndef DKUTIL_COMPRESSION_ZLIB_HPP
#define DKUTIL_COMPRESSION_ZLIB_HPP

#include <dkutil/compression/interface.hpp>
#include <dkutil/memory/memory_stream.hpp>
#include <zlib/zlib.h>
#include <dkutil/boost/utility.hpp>

#ifdef WIN32
#	if defined(_DEBUG) || defined(DEBUG)
#		pragma comment(lib,"zlibd")
#	else
#		pragma comment(lib,zlib)
#	endif
#endif

#define dkcdZLIB_SIGNATURE 'zlib'


namespace dkutil{

namespace detail{



///@return zlibの出力したメッセージを返す。
inline const char *zlib_get_message(z_stream *z){
	static const char *mes="??? no message";
	static const char *logic_err="z_stream structure is null";
	if(!z) return logic_err;
	return ((z->msg) ? z->msg : mes);
}

inline void zlib_exception_throw(z_stream *z){
	std::string str = "zlib:";
	str += zlib_get_message(z);
	throw compression_error(str);
}

template<typename PTR1>
inline void zlib_set_output_buffer(z_stream *z,PTR1 *dest,size_t destsize)
{
#	ifdef _DEBUG
	if(dest==NULL || destsize==0)
		throw std::invalid_argument("zlib_set_output_buffer:argument is invalid!!");
#	endif
	//output
	z->next_out = (BYTE *)dest;// 出力ポインタ //
	z->avail_out = destsize;    // 出力バッファのサイズ //
}

template<typename PTR1>
inline void zlib_set_input_buffer(z_stream *z,PTR1 src,size_t srcsize)
{
#	ifdef _DEBUG
	if(src==NULL || srcsize==0)
		throw std::invalid_argument("zlib_set_input_buffer:argument is invalid!!");
#	endif
	//input
	z->avail_in = srcsize;     // 入力バッファ中のデータのバイト数
	z->next_in = (BYTE *)src;

}

inline bool zlib_is_error(int result){
	if(Z_OK > result) return true;
	return false;
}


/*!
@param z[in][out] z_stream構造体へのポインタ
*/
///zlibをencode modeで初期化する。
inline bool zlib_encode_init(z_stream *z,int compress_mode=Z_BEST_SPEED){
	z->zalloc = Z_NULL;
  z->zfree = Z_NULL;
  z->opaque = Z_NULL;
	/*if (::deflateInit(z, compress_mode) != Z_OK) {
		return false;
	}
	return true;*/
	return ::deflateInit(z, compress_mode) == Z_OK;
}
/*!
@param z[in][out] z_stream構造体へのポインタ
@param encode_option[in] エンコード時のオプション(Z_FINISHとかZ_NO_FLUSHとか

@param result[out] 戻り値がfalseの時、ここに入れた変数が
 edk_FAILEDだとzlibのエラー。
 edk_BufferOverFlowだと出力バッファがなくなった(完全に出力できていない)事を示す。
@return trueだと成功
*/
///zlibでsrcバッファを圧縮し、destバッファに溜める
inline int zlib_encode(z_stream *z,int encode_option)
{
	return ::deflate(z, encode_option); // 圧縮する
}



/*!
@param z[in][out] z_streamへのポインタ
*/
///zlibのエンコードモードを終了する
inline bool zlib_encode_end(z_stream *z){
	return (::deflateEnd(z) == Z_OK);
}

inline bool zlib_decode_init(z_stream *z){
	// すべてのメモリ管理をライブラリに任せる //
	z->zalloc = Z_NULL;
	z->zfree = Z_NULL;
	z->opaque = Z_NULL;

	// 初期化 //
	z->next_in = Z_NULL;
	z->avail_in = 0;
	return (::inflateInit(z) == Z_OK);
}
/*!
@param z[in][out] z_stream構造体へのポインタ
@return inflateのReturn Value
*/
///zlibでsrcバッファを圧縮し、destバッファに溜める
inline int zlib_decode(z_stream *z,int option)
{
	return ::inflate(z, option ); // 展開 //
}



inline bool zlib_decode_end(z_stream *z){
	return (::inflateEnd(z) == Z_OK) ;
}


/*
}//end of detail


namespace policy{
*/



class zlib_encoder{
protected:
	z_stream m_encode;
	bool m_flag;
	int m_state;
	void check_error(int result){
		if(zlib_is_error(result)){
			zlib_exception_throw(&m_encode);
		}
	}
public:
	zlib_encoder(){m_flag=false;m_state = 0;}
	~zlib_encoder(){end();}

	bool init(int mode=Z_BEST_SPEED ){
		if(m_flag){
			if(false==end())//一回終了
				return false;//error
		}
		DKUTIL_RETURN_FALSE(zlib_encode_init(&m_encode,mode));
		m_flag = true;
		return true;
	}
	bool process(int encode_option)
	{
		if(false==m_flag) return false;
		int result=0;
		result = zlib_encode(&m_encode,encode_option);
		m_state = result;
		check_error(result);
		return true;
	}
	bool end(){
		if(false==m_flag){return false;}
		DKUTIL_RETURN_FALSE(zlib_encode_end(&m_encode));
		//check_error(r);
		m_flag=false;
		return true;
	}
	const int get_state()const{return m_state;}
	const z_stream &get_stream()const{return m_encode;}
	void set_stream(z_stream &s){m_encode = s;}
	z_stream *get_stream_ptr(){return &m_encode;}
};

class zlib_decoder{
protected:
	z_stream m_decode;
	bool m_flag;
	int m_state;
	void check_error(int result){
		if(zlib_is_error(result)){
			zlib_exception_throw(&m_decode);
		}
	}
public:
	zlib_decoder(){m_flag=false;m_state=0;}
	~zlib_decoder(){end();}
	bool init(int mode=Z_BEST_SPEED ){
		if(m_flag){
			if(false==end())
				return false;//error
		}
		DKUTIL_RETURN_FALSE(zlib_decode_init(&m_decode));
		m_flag = true;
		return true;
	}
	bool process(int flush_option=Z_NO_FLUSH){
		if(false==m_flag) return false;
		int result=0;
		//result = zlib_decode(&m_decode,flush_option);
		result = zlib_decode(&m_decode,Z_SYNC_FLUSH );
		m_state = result;
		check_error(result);
		return true;
	}
	bool end(){
		if(false==m_flag){return false;}
		DKUTIL_RETURN_FALSE(zlib_decode_end(&m_decode));
		//check_error(r);
		m_flag=false;
		return true;
	}
	const int get_state()const{return m_state;}
	const z_stream &get_stream()const{return m_decode;}
	void set_stream(z_stream &s){m_decode = s;}
	z_stream *get_stream_ptr(){return &m_decode;}
};

/*}//end of policy namespace



namespace detail{*/
/*!

@param srclocalbuffsize[in] 内部で使う読み込みバッファのサイズ
@param destlocalbuffsize[in] 内部で使う書き込みバッファのサイズ
@param zlib[in] zlib_encoder や zlib_decoder等のクラス
@param 
@note

・ZLIB_OPERATION zlib_encoder や zlib_decoder等のクラス。<br>
・READ_BUFFER_LISTENER 読み込みbufferを操作するリスナークラス。<br>
・WRITE_BUFFER_LISTENER 書き込みbufferを操作するリスナークラス。<br>
<br>
BUFFER_LISTENER系のテンプレートには
file_operator系(事前にreset(コンストラクタ呼び出し)して初期化しておく必要がある。)
*/
template<class ZLIB_OPERATION,class READ_BUFFER_LISTENER,class WRITE_BUFFER_LISTENER>
struct zlib_general_purpose_process
{//VC6のバグ対策のためFUNCTORで･･･

	inline bool operator()(size_t srclocalbuffsize,size_t destlocalbuffsize,
									 //ZLIB_OPERATION get_zlib,BUFFER_LISTENER get_listener,
									 ZLIB_OPERATION &zlib,READ_BUFFER_LISTENER read_listener,WRITE_BUFFER_LISTENER write_listener,
									 int compress_mode=Z_BEST_SPEED )
	{
		//variable

		//get_listener listener;
		//get_zlib zlib;
		if(destlocalbuffsize==0 || srclocalbuffsize==0)
			throw compression_error("dkutil::zlib_general_purpose_process::localbuffer size was zero");
		scoped_buffer destlocalbuff(destlocalbuffsize);
		scoped_buffer srclocalbuff(srclocalbuffsize);
		

		//procedure
		
		 //initialize
		DKUTIL_RETURN_FALSE(zlib.init(compress_mode));
		//file open
		//DKUTIL_RETURN_FALSE(read_listener.open());
		//DKUTIL_RETURN_FALSE(write_listener.open());
		
		//最初はこのencodeオプションで
		int encode_option =  Z_NO_FLUSH;
		//実際に読み込んだサイズ
		size_t ReadSize = 0;
		//read data
		{
			size_t read_size;
			read_size=read_listener.read(
				srclocalbuff.get(),srclocalbuff.size()
				);
			if(read_size==0) return false;
			if( srclocalbuff.size() > read_size)
			{//少なく読み込んだ。
				//なのでエンコードオプションを最終用に変える。
				encode_option= Z_FINISH;
			}
			//読み込んだサイズを保存
			ReadSize = read_size;
			//読み込みバッファを設定する
			zlib_set_input_buffer(zlib.get_stream_ptr(),srclocalbuff.get(),read_size);
		}
		//書き込みバッファを設定する
		zlib_set_output_buffer(zlib.get_stream_ptr(),destlocalbuff.get(),destlocalbuff.size());
		


		while (true) 
		{

			//int result=0;
			int lre = zlib.get_state();
			z_stream *z = zlib.get_stream_ptr();
			if(z->avail_in == 0){
				size_t read_size;
				read_size = read_listener.read(srclocalbuff.get(),srclocalbuff.size());
				if( srclocalbuff.size() > read_size)
				{//少なく読み込んだ。
					//なのでエンコードオプションを最終用に変える。
					encode_option= Z_FINISH;
		
					//zlib.process(encode_option);
					//if(zlib.get_state()==Z_STREAM_END) break;
				}
				
				ReadSize = read_size;
				//読み込みバッファを設定する
				if(read_size != 0){
					zlib_set_input_buffer(
						zlib.get_stream_ptr(),srclocalbuff.get(),
						read_size
					);
				}
				//z->next_in = (BYTE *)srclocalbuff.get();  // 入力ポインタを入力バッファの先頭に //
				//z->avail_in = read_size;//読み込んだサイズでGO!!
			}
			zlib.process(encode_option);
			if(zlib.get_state()==Z_STREAM_END)
			{
				break;
			}
			/*if(zlib.get_state()==Z_NEED_DICT){
				MB("??");
			}*/
			if (z->avail_out == 0) 
			{
				//バッファがオーバーした。
				// まとめて書き出す //
				size_t Size;
				Size = destlocalbuff.size();

				DKUTIL_NOT_ASSERT_OR_THROW(
						write_listener.write(destlocalbuff.get(),Size) != Size,
						std::runtime_error("zlib Write error\n")
					);

				zlib_set_output_buffer(z,destlocalbuff.get(),destlocalbuff.size());
				//z->next_out = (BYTE *)destlocalbuff.get(); // 出力バッファ残量を元に戻す 
				//z->avail_out = destlocalbuff.size(); // 出力ポインタを元に戻す
			}
			
		}//end of loop
		// 残りを吐き出す
		{
			size_t count;
			if ((count = destlocalbuff.size() - zlib.get_stream().avail_out) != 0)
			{
				DKUTIL_NOT_ASSERT_OR_THROW(
					write_listener.write(destlocalbuff.get(),count) != count,
					std::runtime_error("zlib Write error\n")
				);
			}
		}
		//あとはデストラクタに任せる^^；
		//zlib.end();
		//read_listener.close();
		//write_listener.close();
		return true;
	}

};//end of functor

#if 0

void TestZlibCompress(){
	//zlib wrapper test
	try{
		std::string target;
		std::string compress;
		std::string decompress;
		{
			char buff[MAX_PATH * 2]="";
			bool r=FileOpenDialog(buff,sizeof(buff),
				"select compress target file","(*.*)*.*" ,"all files");
			if(false==r) return;
			target = buff;
		}
		//ファイル名とか
		compress = target;
		change_extension(compress,"zlibbin");
		decompress = target;
		change_extension(decompress,"unzlib");
	
		//最初にtargetのファイルを読み込んで後で比較するのにとっておく
		file_operator tmp_op(target.c_str());
		tmp_op.open();
		scoped_buffer reserve(GetFileSizeMini(target.c_str()) + 1); 
		tmp_op.read(reserve.get(),reserve.size());
		
		{
			file_operator read_operate(target.c_str(),"rb");
			file_operator write_operate(compress.c_str(),"wb");
			policy::zlib_encoder e;
			read_operate.open();
			write_operate.open();
			zlib_general_purpose_process< 
				policy::zlib_encoder,file_operator,file_operator
			>func;
			func( 1024,1024,e,read_operate,write_operate,Z_BEST_COMPRESSION);
		}

		{
			policy::zlib_decoder d;
			file_operator read_operate(compress.c_str(),"rb");
			file_operator write_operate(decompress.c_str(),"wb");
			read_operate.open();
			write_operate.open();
			zlib_general_purpose_process< 
				policy::zlib_decoder,file_operator,file_operator
			> func;
			func( 1024,1024,d,read_operate,write_operate);
		}

		scoped_buffer check(GetFileSizeMini(decompress.c_str()) + 1);
		tmp_op.reset(decompress.c_str(),"rb");
		tmp_op.open();
		tmp_op.read(check.get(),check.size());

		if(reserve.size() != check.size()){
			MB("size error");
		}
		bool result=DKUTIL_SUCCEEDED(dkmemcmp(reserve.get(),reserve.size(),check.get(),check.size()));
		if(result == false){
			MB("compare error");
		}
	}
	catch(std::runtime_error err){

		MB(err.what());
	}
	//zlib speed test

}

#endif

}//end of detail


typedef struct zlib_option{
	zlib_option(int option = Z_BEST_SPEED) : compress_option(option){} 
	int compress_option;
	void set_best_compression(){
		compress_option = Z_BEST_COMPRESSION;
	}
	void set_best_speed(){
		compress_option = Z_BEST_SPEED;
	}
}ZLIB_OPTION;

///zlibによるencode
class CInflateEncodeStream : public IStreamConvert , public boost::noncopyable{
	detail::zlib_encoder me;
	int mState;
	size_t mIBSize;
	int encode_option;
	zlib_option z_option;
public:
	typedef CInflateEncodeStream self_type;

	CInflateEncodeStream(zlib_option &x,size_t inner_buffer_size = 1024 * 64){
		mState = edk_SUCCEEDED;
		if(inner_buffer_size == 0){
			inner_buffer_size = 1024 * 64;
		}
		mIBSize = inner_buffer_size;
		//最初はこのencodeオプションで
		encode_option =  Z_NO_FLUSH;
		z_option = x;
	}
	virtual ~CInflateEncodeStream()
	{
		end();
	}
	virtual bool begin(){
	
		end();
				//get_listener listener;
		DKUTIL_RETURN_FALSE(me.init(z_option.compress_option));
		mState = edk_SUCCEEDED;
		return true;
	}
	virtual bool convert(uint8 *buff,size_t size)
	{
		using namespace detail;
		detail::zlib_encoder &zlib = me;
		scoped_buffer destlocalbuff(mIBSize);
		scoped_buffer srclocalbuff(mIBSize);
		CLimitMemoryStream write_listener;
		CMemoryStreamAdapter read_listener(buff,size);
		//実際に読み込んだサイズ
		size_t ReadSize = 0;
		//read data
		{
			size_t read_size;
			read_listener.read(
				srclocalbuff.get(),srclocalbuff.size(),&read_size
				);
			if(read_size==0) return false;
			if( srclocalbuff.size() > read_size)
			{//少なく読み込んだ。
				//なのでエンコードオプションを最終用に変える。
				encode_option= Z_FINISH;
			}
			//読み込んだサイズを保存
			ReadSize = read_size;
			//読み込みバッファを設定する
			zlib_set_input_buffer(zlib.get_stream_ptr(),srclocalbuff.get(),read_size);
		}
		//書き込みバッファを設定する
		zlib_set_output_buffer(zlib.get_stream_ptr(),destlocalbuff.get(),destlocalbuff.size());
		


		while (true) 
		{
			//int result=0;
			int lre = zlib.get_state();
			z_stream *z = me.get_stream_ptr();
			if(z->avail_in == 0){
				size_t read_size;
				read_listener.read(srclocalbuff.get(),srclocalbuff.size(),&read_size);
				if( srclocalbuff.size() > read_size)
				{//少なく読み込んだ。
					//なのでエンコードオプションを最終用に変える。
					encode_option= Z_FINISH;
				}
				
				ReadSize = read_size;
				//読み込みバッファを設定する
				if(read_size != 0){
					zlib_set_input_buffer(
						zlib.get_stream_ptr(),srclocalbuff.get(),
						read_size
					);
				}
				//z->next_in = (BYTE *)srclocalbuff.get();  // 入力ポインタを入力バッファの先頭に //
				//z->avail_in = read_size;//読み込んだサイズでGO!!
			}
			zlib.process(encode_option);
			if(zlib.get_state()==Z_STREAM_END)
			{
				break;
			}
			/*if(zlib.get_state()==Z_NEED_DICT){
				MB("??");
			}*/
			if (z->avail_out == 0) 
			{
				//バッファがオーバーした。
				// まとめて書き出す //
				size_t Size,write_size;
				Size = destlocalbuff.size();
				
				write_listener.write(destlocalbuff.get(),Size,&write_size);
				if(write_size != Size)
				{
					DKUTIL_THROW_OR_NOTICE(std::runtime_error("zlib Write error\n"));
					return false;
				}

				zlib_set_output_buffer(z,destlocalbuff.get(),destlocalbuff.size());
				//z->next_out = (BYTE *)destlocalbuff.get(); // 出力バッファ残量を元に戻す 
				//z->avail_out = destlocalbuff.size(); // 出力ポインタを元に戻す
			}
			
		}//end of loop
		// 残りを吐き出す
		{
			size_t count,write_size;
			if ((count = destlocalbuff.size() - zlib.get_stream().avail_out) != 0)
			{
				write_listener.write(destlocalbuff.get(),count,&write_size);
				if(write_size != count)
				{
					DKUTIL_THROW_OR_NOTICE(std::runtime_error("zlib Write error\n"));
					return false;
				}
			}
		}
		return true;
		
	}

	virtual bool convert(IStream *out,IStream *in){
		scoped_buffer_byte sb(mIBSize);
		for(;false==in->eof();)
		{
			in->read(sb.get(),sb.size());
			//mState = dkcHC256EncryptNoDestDOE(mpObj,sb.get(),sb.size());
			convert(sb.get(),sb.size());
			if(DKUTIL_FAILED(mState)){
				return false;
			}
			out->write(sb.get(),sb.size());
		}
		mState = edk_SUCCEEDED;
		return true;
	}
	virtual int state()const{
		return mState;
	}
	virtual bool end(){
		return me.end();
	}
	virtual int type()const{
		return edkICS_compression_zlib;
	}
};


#if 0
/*!
@note
スレッドセーフではありません。
*/
class CZLIB : public IArrayProcess{
public:
	typedef detail::zlib_encoder encoder_type;
	typedef detail::zlib_decoder decoder_type;
	BOOST_STATIC_CONSTANT(int,best_compression = Z_BEST_COMPRESSION);
	BOOST_STATIC_CONSTANT(int,fast_compression = Z_BEST_SPEED);
	
	struct zlib_header{
		ULONG mSig;
		size_t mOriginSize;
	};
private:
	///zlibの♪圧縮(o゜▽゜)o┫Σ(￣□￣;)┣o(゜▽゜o)圧縮♪モード
	int mCompressMode;
	///シグネチャ
	ULONG mSig;
	///内部バッファに使用する予定のサイズ
	size_t mInnerBuffSize;
	///zlib encoder
	encoder_type mEncoder;
	///zlib decoder
	decoder_type mDecoder;

	bool check_sig(zlib_header *p)const{
		return (p->mSig == mSig);
	}

public:
	///@see reset()
	CZLIB(ULONG signature=dkcdZLIB_SIGNATURE){
		mSig = signature;
	}
	~CZLIB(){
		
	}
	///@param signature[in] LZSSで圧縮されていることを証明するID（デフォルトでは dkcdLZSS_SIGNATURE )
	bool reset(ULONG signature=dkcdZLIB_SIGNATURE,
		int compress_mode=fast_compression,
		size_t innner_buffer_size = 1024 * 512)
	{
		mSig = signature;
		mCompressMode = compress_mode;
		mInnerBuffSize = inner_buffer_size;
		return true;
	}
#if 0
	/*!
	@throw 致命的なエラーの場合、std::runtime_errorを投げる
	*/
	template<class BUFFER_T>
	bool encode(const BYTE *src,size_t srcsize,BUFFER_T &buff)
	{
		//バッファの先頭にヘッダファイルを入れる。
		if(buff.size() < srcsize + sizeof(mH)){
			buff.resize(srcsize + sizeof(mH));
		}
		int r = encode(src,srcsize,buff.get(),buff.size());

		return DKUTIL_SUCCEEDED_BOOL(r);
	}
	template<class BUFFER_T>
	bool decode(const BYTE *src,size_t srcsize,BUFFER_T &buff){
		int r = edk_FAILED;
		//バッファの先頭にヘッダファイルがある。
		DKC_LZSS_HEADER *hp = (DKC_LZSS_HEADER *)src;

		dkcmNOT_ASSERT(check_sig(hp)==FALSE);
		if(check_sig(hp)==FALSE){
			return r;
		}
		if(hp->mOriginSize > buff.size())
		{//バッファが足らなかったら。
			//リサイズ
			buff.resize(hp->mOriginSize);
		}		
		
		return DKUTIL_SUCCEEDED_BOOL(decode(src,srcsize,buff.get(),buff.size()));
	}
#endif


	///@return 元のサイズ
	size_t origin_size()const{
		return mH.mOriginSize;
	}
	///@return バッファがオーバーフローしたようならTRUE
	bool is_bufferoverflow()const{
		return edk_BufferOverFlow==mResult;
	}
	///@return 圧縮する価値が無かったらTRUE
	bool is_valueless()const{
		return edk_NoValueToProcess==mResult;
	}
	
	///エンコード後のサイズ
	virtual size_t getEncodedSize()const = 0;
	
	///エンコード時の出力予定のサイズ (普通より大きめの値を返されます。) 
	virtual size_t getEncodeOutputSize(size_t size)const = 0;
	/**
	@param pData[in] デコードする予定のデータ
	@param size[in] デコードする予定のサイズ
	@throw アクセス不可な所へアクセスしようとすると std::runtime_errorをぷっぱなす。
	*/
	///デコード時の出力予定のサイズ　
	virtual size_t getDecodeOutputSize(const void *pData,size_t size)const{

	}

	///シグネチャ
	virtual int getSignature()const{
		return mSig;
	}


	///encode または decodeが成功したらTRUE
	virtual bool isSucceeded()const{
		return DKUTIL_SUCCEEDED_BOOL(mResult);
	}
	///@return デコード後のサイズを取得
	virtual size_t decoded_size(const BYTE *src,size_t size)const{
		DKC_LZSS_HEADER *hp = (DKC_LZSS_HEADER *)src;
		if(check_sig(hp)==FALSE){
			return 0;
		}
		return hp->mOriginSize;
	}
	///@return エンコード後のサイズ
	virtual size_t encoded_size()const{
		return mH.mCompressedSize + sizeof(mH);//header 分
	}

	int decode(const BYTE *src,size_t size,BYTE *dest,size_t destsize){

		zlib_header *tp = (zlib_header *)src;
		

		if(check_sig(tp)==false)
		{//シグネチャが合わない
			return edk_FAILED;
		}

		if(destsize < tp->mDecoded)
		{//バッファが足りない
			return edk_BufferOverFlow;
		}

		BYTE *tsrc = src + sizeof(zlib_header);
		BYTE *tsize = size - sizeof(zlib_headaer);

		outer_memory_to_memorystream_adapter read_operate(tsrc,tsize);
		outer_memory_to_memorystream_adapter write_operate(dest,destsize);
		


		zlib_general_purpose_process< 
			decoder_type,file_operator,file_operator
		>func;

		size_t ibs = mInnerBuffSize;
		int cm = mCompressMode;
		
		if(false==func( ibs,ibs,mEncoder,read_operate,write_operate,cm))
		{//とりあえずシッパイシッパイ(・_・ゞ-☆ 
			return edk_FAILED;
		}

		//やったね＾＾大成功
		return edk_SUCCEEDED;

	}
	int encode(const BYTE *src,size_t size,BYTE *dest,size_t destsize){
		BYTE *tdest = dest + sizeof(zlib_header);
		size_t tdestsize = destsize - sizeof(zlib_header);
		
		outer_memory_to_memorystream_adapter read_operate(src,size);
		outer_memory_to_memorystream_adapter write_operate(tdest,tdestsize);
		
		

		zlib_general_purpose_process< 
			encoder_type,file_operator,file_operator
		>func;
		size_t ibs = mInnerBuffSize;
		int cm = mCompressMode;
		
		if(false==func( ibs,ibs,mEncoder,read_operate,write_operate,cm)){
			return edk_FAILED;
		}

		//成功したようなのでシグネチャ領域にシグネチャをねじ込む
		zlib_header *tp = (zlib_header *)dest;
		tp->mSig = mSignature;
		tp->mDecoded = size;

		return edk_SUCCEEDED;
	}	
	
	
};


#endif

}//end of dkutil namespace



#endif