Artifact Content

Not logged in

Artifact 6032eb8a0710b17d3d86d2bfc0f56ae5fbd0aaa2



#include "stdafx.h"
#include "ArcB2e.h"
#include "resource.h"
#include "NoahApp.h"

//----------------- ArcB2eクラス全体的な処理 ------------------------------

char CArcB2e::st_base[MAX_PATH];
int  CArcB2e::st_life=0;
CArcB2e::CB2eCore* CArcB2e::rvm=NULL;

const char* CArcB2e::init_b2e_path()
{
	kiPath dir( kiPath::Exe );
	ki_strcpy( st_base, dir+="b2e\\" );
	return st_base;
}

CArcB2e::CArcB2e( const char* scriptname ) : CArchiver( scriptname )
{
	st_life++;
	exe = NULL;
	m_LstScr = m_DcEScr = m_EncScr =
	m_DecScr = m_SfxScr = m_LoadScr= m_ScriptBuf = NULL;
}

CArcB2e::~CArcB2e()
{
	if( !(--st_life) )
		delete rvm;
	delete [] m_ScriptBuf;
}

//------------------- スクリプト側にあまり関係しない部分 -------------------------

bool CArcB2e::v_ver( kiStr& str )
{
	if( !exe )
		return false;
	exe->ver( str );

	kiStr tmp;
	for( int i=0,e=m_subFile.len(); i<e; ++i )
	{
		str += "\r\n";
		CArcModule(m_subFile[i]).ver( tmp );
		str += tmp;
	}
	return true;
}

bool CArcB2e::v_check( const kiPath& aname )
{
	return exe ? exe->chk( aname ) : false;
}

int CArcB2e::v_contents( const kiPath& aname, kiPath& dname )
{
	return exe ? exe->cnt( aname, dname ) : aUnknown;
}

//------------------- スクリプトを読み込み&eval( load: ) -------------------

bool CArcB2e::load_module( const char* name )
{
	exe = new CArcModule( name, m_usMode );
	return exe->exist();
}

int CArcB2e::v_load()
{
	//-- 拡張スクリプトファイルを開く
	kiStr fname( st_base ); fname += mlt_ext();
	kiFile fp;
	if( fp.open( fname ) )
	{
		//-- ファイル全体を読み込み
		unsigned int ln=fp.getSize();
		m_ScriptBuf = new char[ ln+1 ];
		ln = fp.read( (unsigned char*)m_ScriptBuf, ln );
		m_ScriptBuf[ ln ] = '\0';

		//-- section毎に切り分ける
		bool pack1,chk=false;
		for( char* p=m_ScriptBuf; *p; p++ )
		{
			switch( *p )
			{
			case 'c': case 'd': case 'e': case 'l': case 's':
				if( ki_memcmp(p,"load:",5) )
					*p='\0', m_LoadScr = (p+=4)+1;
				else if( ki_memcmp(p,"encode:",7) )
					*p='\0', m_EncScr = (p+=6)+1, pack1=false;
				else if( ki_memcmp(p,"encode1:",8) )
					*p='\0', m_EncScr = (p+=7)+1, pack1=true;
				else if( ki_memcmp(p,"decode:",7) )
					*p='\0', m_DecScr = (p+=6)+1;
				else if( ki_memcmp(p,"sfx:",4) )
					*p='\0', m_SfxScr = (p+=3)+1, m_SfxDirect=false;
				else if( ki_memcmp(p,"sfxd:",5) )
					*p='\0', m_SfxScr = (p+=4)+1, m_SfxDirect=true;
				else if( ki_memcmp(p,"check:",6) )
					*p='\0', (p+=5), chk=true;
				else if( ki_memcmp(p,"decode1:",8) )
					*p='\0', m_DcEScr = (p+=7);
				else if( ki_memcmp(p,"list:",5) )
					*p='\0', m_LstScr = (p+=4);
			}
			while( *p && *p!='\n' && *p!='\r' )
				p++;
			if( *p=='\0' )
				break;
		}

		//-- [load:]を実行!
		if( m_LoadScr )
		{
			//-- RythpVM 起動
			if( !rvm )
				rvm = new CB2eCore;

			//-- 初期化
			m_Result=0;
			rvm->setPtr( this,mLod );

			//-- 実行
			rvm->eval( m_LoadScr );

			//-- 結果
			if( m_Result==0 )
				return (m_DecScr?aMelt|(m_DcEScr?aList|aMeltEach:0)|(chk?aCheck:0):0)
					 | (m_EncScr?aCompress|(pack1?0:aArchive)|(m_SfxScr?aSfx:0):0);
		}
	}
	return 0;
}

int CArcB2e::exec_script( const char* scr, scr_mode mode )
{
	//-- 初期化
	m_Result = 0;
	rvm->setPtr( this, mode );

	//-- 実行
	char* script = new char[ki_strlen(scr)+8];
	ki_strcpy( script, "(exec " );
	ki_strcat( script, scr );
	ki_strcat( script, ")" );
	rvm->eval( script );
	delete [] script;

	//-- 結果
	return m_Result;
}

//-------------------- リストアップ eval( list: ) -----------------------

bool CArcB2e::v_list( const arcname& aname, aflArray& files )
{
	//-- スクリプト無しで何とかできるならする。
	if( !exe )
		return false;
	else if( exe->isdll() )
		return exe->lst_dll( aname, files );
	else if( !m_LstScr )
		return false;

//-- リスティングスクリプトに必要なデータ

	// 書庫名
	m_psArc = &aname;
	// ファイルリスト
	m_psAInfo = &files;

//-- 実行! ---------------------

	return 0==exec_script( m_LstScr, mLst );
}

//-------------------- 展開処理 eval( decode: ) -----------------------

int CArcB2e::v_melt( const arcname& aname, const kiPath& ddir, const aflArray* files )
{
//-- 解凍スクリプトに必要なデータ

	// カレント
	::SetCurrentDirectory( ddir );
	// 書庫名
	m_psArc = &aname;
	// 出力先ディレクトリ
	m_psDir = &ddir;
	// ファイルリスト
	m_psAInfo = files;

//-- 実行! ---------------------

	return exec_script( files ? m_DcEScr : m_DecScr,
						files ? mDc1     : mDec );
}

//-------------------- 圧縮処理 eval( encode: sfx: ) -----------------------

int CArcB2e::cmpr( const char* scr, const kiPath& base, const wfdArray& files, const kiPath& ddir, const int method )
{
//-- 圧縮スクリプトに必要なデータ

	arcname aname(
		ddir,
		files[0].cAlternateFileName,
		files[0].cFileName );
	int mhd=method+1;

	// カレント
	::SetCurrentDirectory( base );
	// 書庫名
	m_psArc = &aname;
	// ベースディレクトリ
	m_psDir = &base;
	// メソッド
	m_psMhd = &mhd;
	// リスト
	m_psList = &files;

//-- 実行! --------------------

	return exec_script( scr, mEnc );
}

bool CArcB2e::arc2sfx( const kiPath& temp, const kiPath& dest )
{
//-- SFX変換スクリプトに必要なデータ

	kiFindFile f;
	WIN32_FIND_DATA fd;
	kiPath wild( temp );
	f.begin( wild += "*" );
	if( !f.next( &fd ) )
		return false;
	kiPath from, to, oldname( fd.cFileName );
	arcname aname( temp, fd.cAlternateFileName[0] ? fd.cAlternateFileName : fd.cFileName, fd.cFileName );

	// カレント
	::SetCurrentDirectory( temp );
	// 書庫名
	m_psArc = &aname;
	// ディレクトリ
	m_psDir = &temp;

//-- 実行! ----------------------

	if( 0x8000<=exec_script( m_SfxScr, mSfx ) )
		return false;

//-- コピー ----------------------

	bool skipped=false, ans=false;
	f.begin( wild );
	while( f.next( &fd ) )
	{
		if( !skipped && oldname == fd.cFileName ) // テンポラリ書庫はコピーしない。
		{
			skipped=true;
			continue;
		}
		from = temp, from += fd.cFileName;
		to   = dest, to   += fd.cFileName;
		if( ::CopyFile( from, to, FALSE ) )
			ans = true;
	}
	return ans;
}

int CArcB2e::v_compress( const kiPath& base, const wfdArray& files, const kiPath& ddir, int method, bool sfx )
{
	const char* theScript = m_EncScr;

	if( sfx )
	{
		if( m_SfxDirect )
			theScript = m_SfxScr;
		else
		{
			kiPath tmp;
			myapp().get_tempdir( tmp );

			// テンポラリへ圧縮
			int ans = cmpr( m_EncScr, base, files, tmp, method );
			if( ans < 0x8000 )
				// テンポラリに落ちてるファイルをSFXに変換&コピー!
				ans = (arc2sfx( tmp, ddir ) ? 0 : 0x8020);

			// カレントを戻しておかないと削除できない…(;_;)
			::SetCurrentDirectory( base );
			tmp.remove();
			return ans;
		}
	}

	// 出力先へ普通に圧縮
	return cmpr( theScript, base, files, ddir, method );
}

//-----------------------------------------------------------------//
//-------------------- RythpVMの方の実務 --------------------------//
//-----------------------------------------------------------------//

bool CArcB2e::CB2eCore::exec_function( const kiVar& name, const CharArray& a, const BoolArray& b, int c, kiVar* r )
{
	bool processed = false;

	if( m_mode==mLod ){ //**ロード時専用functions****************************
		if( name=="name" ){
			processed=true;

			//---------------------------//
			//-- (name module_filename)--//
			//---------------------------//
			if( c>=2 )
			{
				x->m_usMode = false;
				if( c>=3 )
				{
					getarg( a[2],b[2],&t );
					x->m_usMode = ( t=="us" );
				}

				getarg( a[1],b[1],&t );
				if( x->load_module(t) )
					*r = "exec";
				else
					*r = "", x->m_Result=0xffff;
			}

		}else if( name=="type" ){
			processed=true;

			//-----------------------------------//
			//-- (type ext method1 method2 ...)--//
			//-----------------------------------//
			for( int i=1; i<c; i++ )
			{
				getarg( a[i],b[i],&t );
				if( i==1 )
					x->set_cmp_ext( t );
				else
				{
					const char* ptr=t;
					x->add_cmp_mhd( *ptr=='*' ? ptr+1 : ptr, *ptr=='*' );
				}
			}
		}else if( name=="use" ){
			processed=true;

			//-------------------------------//
			//-- (use module1 module2 ...) --//
			//-------------------------------//
			for( int i=1; i<c; i++ )
			{
				getarg( a[i],b[i],&t );
				x->m_subFile.add( t );
			}
		}
	}else{//************ ロード時には使えないfunctions *********************
		if( ki_memcmp( (const char*)name, "arc", 3 ) ){
			processed=true;

			//---------------------------//
			//-- (arc[+-].xxx [slfrd]) --//
			//---------------------------//
			arc( ((const char*)name)+3, a, b, c, r );

		}else if( ki_memcmp( (const char*)name, "list", 4 ) ){
			processed=true;

			//----------------------------//
			//-- (list[\*|\*.*] [slfn]) --//
			//----------------------------//
			list( ((const char*)name)+4, a, b, c, r );

		}else if( name=="method" ){
			processed=true;

			//-------------------//
			//-- (method [no]) --//
			//-------------------//
			if( c>=2 )
			{
				getarg( a[1],b[1],&t );
				*r = t.getInt()==*x->m_psMhd ? "1" : "0";
			}
			else
				r->setInt( *x->m_psMhd );

		}else if( name=="dir" ){
			processed=true;

			//-----------//
			//-- (dir) --//
			//-----------//
			*r = (x->m_psDir ? *x->m_psDir : (const char*)"");

		}else if( name=="del" ){
			processed=true;

			//-------------------//
			//-- (del filenam) --//
			//-------------------//
			if( c>=2 )
			{
				getarg( a[1],b[1],&t );
				::DeleteFile( kiPath( t.unquote() ) );
			}

		}else if( ki_memcmp( (const char*)name, "resp", 4 )
			||	  ki_memcmp( (const char*)name, "resq", 4 ) ){
			processed=true;

			//----------------------------//
			//-- (resp[@|-o] (list a)) ---//
			//----------------------------//
			resp( name[3]=='p', ((const char*)name)+4, a, b, c, r );

		}else if( name=="cd" ){
			processed=true;

			//-------------------//
			//-- (cd directory)--//
			//-------------------//
			if( c>=2 )
			{
				getarg( a[1],b[1],&t );
				::SetCurrentDirectory( t.unquote() );
			}

		}else if( name=="cmd" || name=="xcmd" ){
			processed=true;

			//----------------------------//
			//-- (cmd command line ...)---//
			//-- (xcmd command line ...)--//
			//----------------------------//
			if( name[0]=='x' && c<2 )
				x->m_Result = 0xffff;
			else
			{
				CArcModule* xxx = x->exe;
				kiVar       cmd;
				int         i=1;

				if( name[0] == 'x' )
				{
					kiVar mm;
					getarg( a[i],b[i],&mm );
					i++;
					xxx = new CArcModule( mm, x->m_usMode );
				}
				for( ; i<c; i++ )
					getarg( a[i],b[i],&t ), cmd+=t, cmd+=' ';

				bool m = (mycnf().miniboot() || m_mode==mDc1);
				x->m_Result = xxx->cmd( cmd, m );
				r->setInt( x->m_Result );

				if( name[0] == 'x' )
					delete xxx;
			}
		}else if( name=="scan" || name=="xscan" ){
			processed=true;

			//----------------------------------------//
			//-- (scan BL BSL EL SL dx cmd...) -------//
			//-- (xscan BL BSL EL SL dx CMD cmd...) --//
			//----------------------------------------//
			if( c<6 || (name[0]=='x'&&c<7) )
				x->m_Result = 0xffff;
			else
			{
				CArcModule* xxx = x->exe;

				kiVar BL, EL;
				getarg( a[1],b[1],&BL );
				getarg( a[2],b[2],&t );
				int BSL = t.getInt();
				getarg( a[3],b[3],&EL );
				getarg( a[4],b[4],&t );
				int SL = t.getInt();
				getarg( a[5],b[5],&t );
				int dx = t.getInt();

				int i=6;
				if( name[0] == 'x' )
				{
					kiVar mm;
					getarg( a[i],b[i],&mm );
					i++;
					xxx = new CArcModule( mm, x->m_usMode );
				}

				kiVar cmd;
				for( ; i<c; ++i )
					getarg( a[i],b[i],&t ), cmd+=t, cmd+=' ';

				x->m_Result = xxx->lst_exe(
					cmd, *const_cast<aflArray*>(x->m_psAInfo),
					BL, BSL, EL, SL, dx ) ? 0 : -1;

				if( name[0] == 'x' )
					delete xxx;
			}
		}else if( name=="input" ){
			processed=true;

			//-------------------------//
			//-- (input MSG DEFUALT) --//
			//-------------------------//
			kiVar msg, defval;
			if( c>=2 )
				getarg( a[1],b[1],&msg );
			if( c>=3 )
				getarg( a[2],b[2],&defval );
			input( msg, defval, r );
		}else if( name=="size" ){
			processed=true;

			//---------------------//
			//-- (size FILENAME) --//
			//---------------------//
			if( c>=2 )
			{
				kiVar fnm;
				getarg( a[1],b[1],&fnm );
				r->setInt( kiFile::getSize( fnm.unquote() ) );
			}
		}else if( name=="is_file" ){
			processed=true;

			//---------------------//
			//-- (is_file) --------//
			//---------------------//
			if( c==1 )
				*r = (x->m_psList->len()==1
					  && !kiSUtil::isdir( (*x->m_psList)[0].cFileName )) ? "1" : "0";
		}else if( name=="is_folder" ){
			processed=true;

			//---------------------//
			//-- (is_folder) ------//
			//---------------------//
			if( c==1 )
				*r = (x->m_psList->len()==1
					  && kiSUtil::isdir( (*x->m_psList)[0].cFileName )) ? "1" : "0";
		}else if( name=="is_multiple" ){
			processed=true;

			//---------------------//
			//-- (is_multiple) ----//
			//---------------------//
			if( c==1 )
				*r = x->m_psList->len()>1 ? "1" : "0";
		}else if( name=="find" ){
			processed=true;

			//---------------------//
			//-- (find FILENAME) --//
			//---------------------//
			if( c>=2 )
			{
				kiVar fnm;
				getarg( a[1],b[1],&fnm );
				char buf[MAX_PATH];
				if( 0==::SearchPath( NULL,fnm.unquote(),NULL,MAX_PATH,buf,NULL ) )
					*r = "";
				else
					*r = buf, r->quote();
			}
		}
	}

	return processed ? true : kiRythpVM::exec_function(name,a,b,c,r);
}

void CArcB2e::CB2eCore::arc( const char* opt, const CharArray& a, const BoolArray& b,int c, kiVar* r )
{
	//---------------------------//
	//-- (arc[+-].xxx [slfrd]) --//
	//---------------------------//

	// デフォルトオプション設定
	const char* anm=x->m_psArc->lname;
	enum{ full, nam, dir } part=full;
	if( m_mode==mSfx )	part=nam; // sfx

	// 指定があれば上書
	if( c>=2 )
	{
		getarg( a[1],b[1],&t );
		for( const char* p=t; *p; p++ )
			switch(*p)
			{
			case 's': anm=x->m_psArc->sname; break;
			case 'l': anm=x->m_psArc->lname; break;
			case 'f': part=full; break;
			case 'n': part=nam;  break;
			case 'd': part=dir;  break;
			}
	}

	// ディレクトリ部分
	*r = (part==nam ? (const char*)"" : x->m_psArc->basedir);

	// 名前部分
	if( part != dir )
	{
		if( *opt=='\0' || *opt=='+' )
		{
			// (arc)       : anmをそのまま返す
			*r += anm;
			// (arc+XXX)   : anmXXXを返す
			if( *opt=='+' )
				*r += (opt+1);
		}
		else
		{
			const char* ext = kiPath::ext(anm);
			const char* add = "";
			if( opt[0]=='-' && opt[1]=='.' )
			{
				// (arc-.XXX) : 末尾が.XXXだったら削除。
				//            : そうでなければ後ろに.decompressed
				if( 0!=ki_strcmpi( ext, opt+2 ) )
					ext = anm + ki_strlen(anm), add = ".decompressed";
			}
			else if( opt[1]!='\0' )
			{
				// (arc.XXX)  : 最後の拡張子を.XXXに取り替え
				add = opt;
				switch(mycnf().extnum())
				{
				case 0: ext = anm + ::lstrlen(anm);break; 
				case 1: ext = kiPath::ext(anm);    break;
				default:ext = kiPath::ext_all(anm);break;
				}
			}
			else
			{
				// (arc.)     : 拡張子を全て取り除く
				switch(mycnf().extnum())
				{
				case 0: ext = anm + ::lstrlen(anm);break; 
				case 1: ext = kiPath::ext(anm);    break;
				default:ext = kiPath::ext_all(anm);break;
				}
			}
			if( *ext )
				ext--;

			char buf[MAX_PATH];
			ki_memcpy( buf, anm, ext-anm );
			buf[ ext-anm ] = '\0';
			*r += buf;
			*r += add;
		}

		// 必要ならくくる
		if( part==full )
			r->quote();
	}
}

static void selfR(
	const char* writedir, const char* fullpath, bool lfn, kiVar* r )
{
	kiFindFile       f;
	WIN32_FIND_DATA fd;
	f.begin( kiStr(fullpath) += "\\*" );

	kiVar t, t2, t3;
	while( f.next(&fd) )
	{
		t = writedir;
		t+= '\\';
		t+= (lfn ? fd.cFileName : fd.cAlternateFileName);
		if( fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
		{
			t2 = t;
			t  = "";
			t3 = fullpath;
			t3+= '\\';
			t3+= (lfn ? fd.cFileName : fd.cAlternateFileName);
			selfR( t2, t3, lfn, &t );
		}
		else
		{
			if( lfn )
				t.quote();
		}
		*r += t;
		*r += ' ';
	}
}

void CArcB2e::CB2eCore::list( const char* opt, const CharArray& a, const BoolArray& b,int c, kiVar* r )
{
	//---------------------------//
	//-- (list[r|\*.*] [slfn]) --//
	//---------------------------//

	if( m_mode!=mEnc ) // 解凍の場合
	{
		*r = "";

		for( unsigned int i=0; i!=x->m_psAInfo->len(); i++ )
			if( (*x->m_psAInfo)[i].selected )
			{
				// - で始まるヤツ対策をするか?
				t = (*x->m_psAInfo)[i].inf.szFileName;
				t.quote();
				*r += t;
				*r += ' ';
			}
	}
	else // 圧縮の場合
	{
		// デフォルトオプション設定
		bool lfn=true;
		enum{ full, nam } part=nam;
		// 指定があれば上書
		if( c>=2 )
		{
			getarg( a[1],b[1],&t );
			for( const char* p=t; *p; p++ )
				switch(*p)
				{
				case 's': lfn=false; break;
				case 'l': lfn=true;  break;
				case 'f': part=full; break;
				case 'n': part=nam;  break;
				}
		}
		// 自前で再帰リストアップを行うか否か
		bool selfrecurse = (*opt=='r');

		// ディレクトリ名の後ろに付け足すもの。
		if( *opt=='\\' || *opt=='/' )
			opt++;

		// リストアップ
		kiVar t2,t3;
		*r = "";
		for( unsigned int i=0; i!=x->m_psList->len(); i++ )
		{
			// ファイル名部分
			t = ( part==full ? *x->m_psDir : (const char*)"");
			t += lfn ? (*x->m_psList)[i].cFileName : (*x->m_psList)[i].cAlternateFileName;

			if( selfrecurse && ((*x->m_psList)[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
			{
				// セルフ再帰
				t2 = t;
				t  = "";
				t3 = *x->m_psDir;
				t3+= lfn ? (*x->m_psList)[i].cFileName : (*x->m_psList)[i].cAlternateFileName;
				selfR( t2, t3, lfn, &t );
			}
			else
			{
				// ノーマル処理
				if( *opt && ((*x->m_psList)[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
					t += '\\', t += opt;
				if( lfn )
					t.quote();
			}
			*r += t;
			*r += ' ';
		}
	}

	r->removeTrailWS();
}

void CArcB2e::CB2eCore::resp( bool needq, const char* opt, const CharArray& a, const BoolArray& b,int c, kiVar* r )
{
	//-----------------------------//
	//-- (resp[@|-o] (list) ...) --//
	//-----------------------------//

	// レスポンスファイル名作成
	kiPath rspfile;
	myapp().get_tempdir(rspfile);
	rspfile += "filelist";

	// オプションと結合して返す
	*r  = opt;
	*r += rspfile;

	// ファイルへ書き込み
	kiFile fp;
	if( !fp.open( rspfile,false ) )
		return;

	kiVar tmp;
	for( int i=1; i<c; i++ )
	{
		// fpへ各引数をsplitしながら書き込む
		getarg( a[i],b[i],&tmp );

		for( const char *s,*p=tmp; *p; p++ )
		{
			// 余分な空白はスキップ
			while( *p==' ' )
				p++;
			if( *p=='\0' )
				break;

			// 引数の終わりへ…
			s=p;
			for( int q=0; *p!='\0' && (*p!=' ' || (q&1)!=0); p++ )
				if( *p=='"' )
					q++;

			// "のつじつま合わせ一号
			if( !needq && *s=='"' )
			{
				s++;
				if( p!=s && *(p-1)=='"' )
					p--;
			}

			fp.write( s, p-s );
			fp.write( "\r\n", 2 );

			// "のつじつま合わせ二号
			if( *p=='"' )
				p++;
			if( *p=='\0' )
				break;
		}
	}
}

void CArcB2e::CB2eCore::input( const char* msg, const char* defval, kiVar* r )
{
	struct CB2eInputDlg : public kiDialog
	{
		const char* msg;
		const char* def;
		kiVar*      res;

		CB2eInputDlg( const char* m, const char* d, kiVar* r )
			: kiDialog( IDD_PASSWORD ), msg(m), def(d), res(r) {}
		BOOL onInit()
			{
				sendMsgToItem( IDC_EDIT, WM_SETTEXT, 0, (LPARAM)def );
				sendMsgToItem( IDC_MESSAGE, WM_SETTEXT, 0, (LPARAM)msg );
				::ShowWindow( item(IDC_MASK), SW_HIDE );
				::ShowWindow( item(IDCANCEL), SW_HIDE );
				::EnableWindow( item(IDC_MASK), FALSE );
				::EnableWindow( item(IDCANCEL), FALSE );
				::SetFocus( item(IDC_EDIT) );
				return TRUE;
			}
		bool onOK()
			{
				char* buf = new char[32768];
				sendMsgToItem( IDC_EDIT, WM_GETTEXT, 32768, (LPARAM)buf );
				*res = buf;
				delete [] buf;
				return true;
			}
	};

	CB2eInputDlg d( msg, defval, r );
	d.doModal( app()->mainhwnd() );
}