Beispiel #1
0
int SaoriClient::request(
	const vector<string>& i_argument,
	bool i_is_secure,
	string& o_result,
	vector<string>& o_value)
{
	//---------------------
	// リクエスト作成

	strpairvec data;

	int idx=0;
	for ( vector<string>::const_iterator i=i_argument.begin() ; i!=i_argument.end() ; ++i,++idx )
	{
		data.push_back( strpair(string("Argument")+itos(idx), *i) );
	}
	data.push_back( strpair("SecurityLevel", (i_is_secure ? "Local" : "External") ) );

	//---------------------
	// リクエスト実行

	strpairvec r_data;
	int return_code = this->SakuraDLLClient::request("EXECUTE", data, r_data);

	//---------------------
	// 返答を解析

	string result;

	for ( strpairvec::const_iterator i = r_data.begin() ; i != r_data.end() ; ++i )
	{
		const string& key = i->first;
		const string& value = i->second;

		if ( compare_head(key, "Value") && isdigit(key[strlen("Value")]) )
		{
			const int	pos = atoi(key.c_str() + strlen("Value"));
			if ( pos<0 || pos>65536 )
			{
				continue;
			}

			if ( o_value.size() <= pos )
			{
				o_value.resize(pos+1);
			}
			o_value[pos] = value;
		}
		else if ( key=="Result" )
		{
			o_result = value;
		}
	}

	return return_code;
}
int	Satori::request(
	const string& i_protocol,
	const string& i_protocol_version,
	const string& i_command,
	const strpairvec& i_data,
	
	string& o_protocol,
	string& o_protocol_version,
	strpairvec& o_data)
{
	SenderEnableBuffering seb(GetSender());

	//-------------------------------------------------
	// リクエスト単位のクラスメンバを初期化

	mRequestMap.clear();
	mRequestID = "";
	mReferences.clear();
	mReferences.reserve(8); // 最小値

	// 引数をクラスメンバに設定
	mRequestCommand = i_command;
	mRequestType = i_protocol;
	mRequestVersion = i_protocol_version;
	mStatusLine = i_command + " " + i_protocol + "/" + i_protocol_version;

	// 返すプロトコルのデフォルト値
	o_protocol = "SHIORI";
	o_protocol_version = "3.0";

	// 喋るごとに初期化する変数
	return_empty = false;

	surface_restore_at_talk_onetime = SR_INVALID;
	auto_anchor_enable_onetime = auto_anchor_enable;

	is_quick_section = false;

	// スクリプトヘッダ
	header_script = "";

	// プロトコルを判別
	if ( i_protocol=="SAORI" && i_protocol_version[0]>='1' )
	{
		o_protocol = i_protocol;
		o_protocol_version = "1.0";
		mRequestMode = SAORI;
	}
	else if ( i_protocol=="SHIORI" && i_protocol_version[0]>='3' )
	{
		mRequestMode = SHIORI3;
	}
	else if ( i_protocol=="SHIORI" && i_protocol_version[0]=='2' )
	{
		mRequestMode = SHIORI2;
			// 2.xにもバージョンとしては3.0を返す
	}
	else if ( i_protocol=="MAKOTO" && i_protocol_version[0]>='2' )
	{
		o_protocol = i_protocol;
		o_protocol_version = "2.0";
		mRequestMode = MAKOTO2;
	}
	else if ( i_protocol=="UNKNOWN" )
	{
		mRequestMode = UNKNOWN;
	}
	else
	{
		// 未対応のプロトコルだった。
		return	400;
	}

	// データ部をmRequestMapに格納。
	// SHOIRI/3.0以外のプロトコルの場合、SHOIRI/3.0に変換を行う。
	for ( strpairvec::const_iterator it = i_data.begin() ; it != i_data.end() ; ++it )
	{
		string key = it->first;
		const string& value = it->second;

		switch ( mRequestMode ) {
		case SAORI:
			if ( compare_head(key, "Argument") ) {
				int	n = stoi_internal(key.c_str()+8);
				if ( n==0 )
					key = "ID";
				else
					key = "Reference" + itos(n-1);
			}
			break;
		case SHIORI2:	// こっちはてきとー
			if ( key=="Event" )
				key="ID";
			break;
		case MAKOTO2:
			if ( key=="String" )
				key="Reference0";
			break;
		default:
			break;
		}

		mRequestMap[key] = value;
		if ( compare_head(key, "Reference") ) {
			int	n = stoi_internal(key.c_str()+9);
			if ( n>=0 && n<65536 ) {
				if ( n>=mReferences.size() )
					mReferences.resize(n+1);
				mReferences[n]=value;
			}
		}
	}

	if ( mRequestMode == MAKOTO2 )
	{
		mRequestMap["ID"] = "OnMakoto";
	}

	mRequestID = mRequestMap["ID"];
	mIsMateria = ( mRequestMap["Sender"] == "embryo" );
	mIsStatusHeaderExist = ( mRequestMap["Sender"] == "SSP" );

	//-------------------------------------------------
	// リクエストを解釈

	if ( mRequestCommand=="GET Version" )
	{
		if ( mRequestMode == SHIORI2 )
		{
			o_data.push_back( strpair("ID", gSatoriName) );
			o_data.push_back( strpair("Craftman", gSatoriCraftman) );
			o_data.push_back( strpair("Version", gSatoriVersion) );
		}
		return 200;
	}


	// 選択分岐記録を変数に代入。ref0を元に戻す。
	if ( compare_head(mRequestID, "OnChoice") ) // OnChoiceSelect/OnChoiceEnterの両方
	{
		strvec	vec;
		int	ref_no = ( mRequestID=="OnChoiceEnter" || mRequestID=="OnChoiceSelectEx" )?1:0;
		string&	info = mRequestMap[string("Reference")+itos(ref_no)];
		if ( split(info, byte1_dlmt, vec)==3 ) // \1区切りの3文字列であるならば
		{
			info=mReferences[ref_no]=variables["選択ID"]=vec[0];
			variables["選択ラベル"]=vec[1];
			variables["選択番号"]=vec[2];
		}
	}

	// ログについて色々
	bool log_disable_soft = ( mRequestID=="OnSurfaceChange" || mRequestID=="OnSecondChange" || mRequestID=="OnMinuteChange"
		|| mRequestID=="OnMouseMove" || mRequestID=="OnTranslate");

	bool log_disable_hard = ( /*compare_tail(mRequestID, "caption") || */compare_tail(mRequestID, "visible")
		|| compare_head(mRequestID, "menu.") || mRequestID.find(".color.")!=string::npos );

	GetSender().next_event();

	if(fRequestLog)
	{
		GetSender().sender() << "--- Request ---" << std::endl << mStatusLine <<std::endl; // << iRequest <<std::endl;
		for(strmap::const_iterator i=mRequestMap.begin() ; i!=mRequestMap.end() ; ++i)
			if ( !i->first.empty() && !i->second.empty()
				&& i->first!="SecurityLevel" 
				&& i->first!="Sender" 
				&& i->first!="Charset" ) {
				GetSender().sender() << i->first << ": " << i->second <<std::endl;
			}
	}

	// せきゅあ?
	strmap::const_iterator it = mRequestMap.find("SecurityLevel");
	secure_flag = ( it!=mRequestMap.end() && stricmp(it->second.c_str(), "local")==0 );

	// メイン処理
	GetSender().sender() << "--- Operation ---" << std::endl;

	int status_code = 500;
	if ( mRequestID=="enable_log" || mRequestID=="enable_debug" ) {
		if ( secure_flag ) {
			bool flag = false;
			if ( mReferences.size() > 0 ) {
				flag = atoi(mReferences[0].c_str()) != 0;
			}

			if ( mRequestID=="enable_debug" ) {
				fDebugMode = flag;
			}
			else {
				GetSender().validate(flag);
			}
			status_code = 200;
		}
		else {
			GetSender().sender() << "local/Localでないので蹴りました: ShioriEcho" <<std::endl;
			status_code = 403;
		}
	}
	else if ( mRequestID=="ShioriEcho" ) {
		// ShioriEcho実装
		if ( fDebugMode && secure_flag ) {
			string result = SentenceToSakuraScriptExec_with_PreProcess(mReferences);
			if ( result.length() ) {
				static const char* const dangerous_tag[] = {"\\![updatebymyself]",
					"\\![vanishbymyself]",
					"\\![enter,passivemode]",
					"\\![enter,inductionmode]",
					"\\![leave,passivemode]",
					"\\![leave,inductionmode]",
					"\\![lock,repaint]",
					"\\![unlock,repaint]",
					"\\![biff]",
					"\\![open,browser",
					"\\![open,mailer",
					"\\![raise",
					"\\j["};

				std::string replace_to;
				for ( int i = 0 ; i < (sizeof(dangerous_tag)/sizeof(dangerous_tag[0])) ; ++i ) {
					replace_to = "¥[";
					replace_to += dangerous_tag[i]+2; //\をヌキ
					replace(result,dangerous_tag[i],replace_to);
				}

				//Translate(result); - Translateは後でかかる
				mResponseMap["Value"] = result;
				status_code = 200;
			}
			else {
				status_code = 204;
			}
		}
		else {
			if ( fDebugMode ) {
				GetSender().sender() << "local/Localでないので蹴りました: ShioriEcho" <<std::endl;
				status_code = 403;
			}
			else {
				static const std::string dbgmsg = "デバッグモードが無効です。使用するためには$デバッグ=有効にしてください。: ShioriEcho";
				GetSender().sender() << dbgmsg <<std::endl;

				mResponseMap["Value"] = "\\0" + dbgmsg + "\\e";
				status_code = 200;
			}
		}
	}
	else if (mRequestID == "SatolistEcho"){
#ifndef POSIX
		// さとりすとデバッガ実装
		if (fDebugMode && secure_flag) {

			//R0は除去される
			strvec customRef;
			for (int i = 1; i < mReferences.size(); i++){
				customRef.push_back(mReferences[i]);
			}

			string result = SentenceToSakuraScriptExec_with_PreProcess(customRef);
			if (result.length()) {
				result = string("SSTP 200 OK\r\nCharset: Shift_JIS\r\nResult: ") + result + "\r\n\r\n";
			}
			else{
				//情報なし
				result = string("SSTP 204 No Content\r\nCharset: Shift_JIS\r\n\r\n");
			}

			char* copyData = new char[result.length() + 1];
			strcpy(copyData, result.c_str());

			COPYDATASTRUCT cds;
			cds.dwData = 0;
			cds.cbData = result.length() + 1;
			cds.lpData = copyData;
			DWORD ret;

			SendMessageTimeout((HWND)stoi_internal(mReferences[0]), WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds, 0, 1000, &ret);

			//ここで204を返すと非対応時のエラーを出すので200で通知メッセージを表示する
			status_code = 200;
			mResponseMap["Value"] = "\\0\\_q■情報を送信しました。\\e";
		}
		else {
			if (fDebugMode) {
				GetSender().sender() << "local/Localでないので蹴りました: SatolistEcho" <<std::endl;
				status_code = 403;
			}
			else {
				static const std::string dbgmsg = "デバッグモードが無効です。使用するためには$デバッグ=有効にしてください。: SatolistEcho";
				GetSender().sender() << dbgmsg <<std::endl;

				mResponseMap["Value"] = "\\0" + dbgmsg + "\\e";
				status_code = 200;
			}
		}
#endif // POSIX
	}
	else {
		status_code = CreateResponse(mResponseMap);
	}

	// 後処理1
	default_surface = next_default_surface;

	//--------------------------------------------------------------------

	// Valueに対する最終処理
	if ( status_code==200 ) {	// && compare_head(mRequestID, "On")
		strmap::iterator i = mResponseMap.find("Value");
		if ( i!=mResponseMap.end() ) {
			if ( return_empty ) {
				status_code = 204;
				mResponseMap.erase(i);
			}
			else {
				if ( !Translate(i->second) ) {
					status_code = 204;
					mResponseMap.erase(i);
				} 
				else {
					second_from_last_talk = 0;
					if ( compare_head(mRequestID, "On") ) {
						mResponseHistory.push_front(i->second);
						if ( mResponseHistory.size() >= RESPONSE_HISTORY_SIZE )
							mResponseHistory.pop_back();
					}
				}
			}
		}
	}

	GetSender().sender() << "status code : " << itos(status_code) <<std::endl;

	//--------------------------------------------------------------------

	for(strmap::const_iterator i=mResponseMap.begin() ; i!=mResponseMap.end() ; ++i)
	{
		string	key=i->first, value=i->second;

		switch ( mRequestMode ) {
		case SAORI:
			if ( key=="Value" ) {
				key = "Result";
				value = header_script + value;
			}
			else if ( compare_head(key, "Reference") ) {
				key = string() + "Value" + (key.c_str()+9);
			}
			break;
		case SHIORI2:
			if ( key=="Value" ) {
				key = "Sentence";
				value = header_script + value;
			}
			break;
		case MAKOTO2:
			if ( key=="Value" ) {
				key = "String";
				value = header_script + value;
			}
			break;
		default:
			if ( key=="Value" ) {
				value = header_script + value;
			}
			break;
		}
		o_data.push_back( strpair(key, value) );
	}

	if ( GetSender().errsender().get_log_mode() ) {
		const std::vector<string> &errlog = GetSender().errsender().get_log();

		std::string errmsg;
		std::string errlevel;

		for ( std::vector<string>::const_iterator itr = errlog.begin() ; itr != errlog.end(); ++itr ) {
			errmsg += "SATORI - ";
			errmsg += mRequestID;
			errmsg += " > ";
			errmsg += *itr;
			errmsg += "\1";
			errlevel += "critical\1";
		}

		if ( errmsg.length() ) {
			errmsg.erase(errmsg.end()-1,errmsg.end());
			errlevel.erase(errlevel.end()-1,errlevel.end());

			o_data.push_back( strpair("ErrorLevel",errlevel) );
			o_data.push_back( strpair("ErrorDescription",errmsg) );
		}
		GetSender().errsender().clear_log();
	}

	GetSender().validate();
	if(fResponseLog)
	{
		GetSender().sender() << "--- Response ---" <<std::endl << mResponseMap <<std::endl;
	}
	mResponseMap.clear();

	if ( log_disable_hard ) {
		GetSender().delete_last_request();
	}
	else if ( log_disable_soft ) {
		if ( status_code != 200 ) {
			GetSender().delete_last_request();
		}
	}

	GetSender().flush();

	//--------------------------------------------------------------------

	// リロード処理
	if ( reload_flag )
	{
		reload_flag = false;
		string	tmp = mBaseFolder;
		GetSender().sender() << "■■reloading." <<std::endl;
		unload();
		load(tmp);
		GetSender().sender() << "■■reloaded." <<std::endl;

		GetSender().flush();
	}

	return	status_code;
}
Beispiel #3
0
int		Satori::CreateResponse(strmap& oResponse)
{
	// NOTIFYであれば値を保存
	/*strmap	mNotifiedMap;
	if ( mRequestCommand=="NOTIFY" )
		mNotifiedMap[mRequestID] = mRequestMap["Reference0"];*/
	if ( mRequestCommand=="NOTIFY" ) {
		if ( mRequestID=="hwnd" ) {
#ifndef POSIX
			strvec	vec;
			const int max = split(mReferences[0], byte1_dlmt, vec);
			if ( max > 0 ) {
				characters_hwnd.clear();
			}
			for (int n=0 ; n<max ; ++n) {
				characters_hwnd[n] = (HWND)(stoi(vec[n]));
				sender << "里々は id:" << n << " のhWndを取得しました。" << endl;
			}
#endif
		}
		else if ( mRequestID=="capability" ) {
			bool isErrorHeader = false;
			for ( strvec::const_iterator it = mReferences.begin() ; it != mReferences.end(); ++it ) {
				if ( *it == "response.errorlevel" ) {
					isErrorHeader = true;
				}
			}
			errsender.set_log_mode(isErrorHeader);
		}
	}

	string	result;

	//喋り変換部初期化
	reset_speaked_status();

	//実際の呼び出し開始
	if ( mRequestID == "OnDirectSaoriCall" ) {
		string	str;
		int	n=0;
		bool	isfirst = true;
		for (strvec::const_iterator i=mReferences.begin() ; i!=mReferences.end() ; ++i, ++n)
			if ( i->empty() && mRequestMap.find( string("Reference")+itos(n) )==mRequestMap.end() )
				break;
			else
				if ( isfirst ) {
					str = *i;
					isfirst = false;
				}
				else
					str += "," + *i;
		//while ( compare_tail(str, ",") )
		//	str.assign( str.substr(0, str.size()-2)+"]" );
		string	temp;
		if ( secure_flag ) {
			sender << "[DirectCall]" << endl;
			Call(str, temp);
			return	204;
		}
		else {
			sender << "local/Localでないので蹴りました: " << str << endl;
			return	204;
		}
	}
	else if ( compare_head(mRequestID, "On") ) {
		if ( words.is_exist(mRequestID) )
			return	Call(mRequestID, oResponse["Value"]) ? 200 : 204;
		return	EventOperation(mRequestID, oResponse);
	}
	else if ( mRequestID == "version" )
		result = gSatoriVersion;
	else if ( mRequestID == "craftman" )
		result = gSatoriCraftman;
	else if ( mRequestID == "craftmanw" )
		result = gSatoriCraftmanW;
	else if ( mRequestID == "name" )
		result = gSatoriName;
	else if ( mRequestID.find(".recommendsites") != string::npos || mRequestID=="sakura.portalsites" ) {
		if ( !GetURLList(mRequestID, result) )	// URLリストの取得
			return	204;
	} 
	else if ( !Call(mRequestID, result) ) {
		return	204;
	}
	else {
	}

	if ( result.empty() )
		return	204;

	oResponse["Value"] = result;
	return	200;
}
Beispiel #4
0
bool	Satori::Translate(string& ioScript) {

	if ( ioScript.empty() )
		return	false;

	const bool is_OnTranslate = (mRequestID=="OnTranslate");

	// さくらスクリプトとそれ以外を分割して処理を加える
	vector<string>	vec;
	string	acum;
	bool	content=false;	// 文に中身があるのか
	bool	is_first_question = true; // 選択分岐記録の消去処理用。
	int	last_speaker=0;
	const char* p = ioScript.c_str();
	while (*p) {
		string	c=get_a_chr(p);	// 全角半角問わず一文字取得し、pを一文字すすめる
		
		if ( c=="\\" || c=="%" ) {
			if (*p=='\\'||*p=='%') {	// エスケープされた\, %
				acum += c + *p++;
				continue;
			}
			
			const char*	start=p;
			string	cmd="",opt="";
	
			while (!_ismbblead(*p) && (isalpha(*p)||isdigit(*p)||*p=='!'||*p=='*'||*p=='&'||*p=='?'||*p=='_'))
				++p;
			cmd.assign(start, p-start);
	
			if (*p=='[') {
				const char* opt_start = ++p;
				while (*p!=']') {
					if (p[0]=='\\' && p[1]==']')	// エスケープされた]
						++p;
					p += _ismbblead(*p) ? 2 : 1;
				}
				opt.assign(opt_start, p++ -opt_start);
			}
			
			// 選択分岐ラベルに対する特殊処理
			if ( !is_OnTranslate && 
				cmd=="q" && opt!="" && count(opt, ",")>0 && 
				mRequestID!="OnHeadlinesense.OnFind") {

				// 選択分岐があるスクリプトであれば、その初回で選択分岐記録をクリア
				if ( is_first_question ) {
					question_record.clear();	
					is_first_question = false;
				}

				// 選択分岐を記録
				{
					strvec	vec;
					split(opt, ",", vec);
					if ( vec.size()==1 )	// countとsplitの罠。
						vec.push_back("");	// 
					string	label=vec[0], id=vec[1];

					if ( false == compare_head(id, "On") )
					{ 
						// Onで始まるものはOnChoiceSelectを経由されないため、対象外とする

						int	count = question_record.size()+1;
						question_record[id] = pair<int,string>(count, label);

						// ラベルIDに書き戻し
						opt = label+","+id+byte1_dlmt+label+byte1_dlmt+itos(count);
						for (int i=2;i<vec.size();++i)
							opt += string(",") + vec[i];
					}
				}
			}
			else if ( cmd=="0" || cmd=="h" ) { last_speaker=0; }
			else if ( cmd=="1" || cmd=="u" ) { last_speaker=1; }
			else if ( cmd=="p" && aredigits(opt) ) {
				last_speaker=stoi(opt);
				if ( mIsMateria || last_speaker<=1 ) {
					cmd = (opt=="0") ? "0" : "1";
					opt = "";
				}
			}
			else if ( cmd=="s" && !opt.empty() ) {
				last_talk_exiting_surface[last_speaker]=stoi(opt);
			}
			else if ( cmd.size()==2 && cmd[0]=='s' && isdigit(cmd[1]) ) {
				last_talk_exiting_surface[last_speaker]=cmd[1]-'0';
			}
						
			if ( !acum.empty() )
				vec.push_back(acum);

			if ( opt=="" )
				vec.push_back(c + cmd);
			else
				vec.push_back(c + cmd + "[" + opt + "]");
			acum="";

			static	set<string>	nc_cmd;	// 有効と数えないさくらスクリプト群
			static	bool	initialized=false;
			if (!initialized) {
				initialized=true;
				nc_cmd.insert("0"); nc_cmd.insert("1"); nc_cmd.insert("h"); nc_cmd.insert("u"); nc_cmd.insert("p");
				nc_cmd.insert("n"); nc_cmd.insert("w"); nc_cmd.insert("_w"); nc_cmd.insert("e");
			}
			if ( nc_cmd.find(cmd)==nc_cmd.end() )
				content = true;

		}
		else {
			content = true;
			acum += c;
		}
	}
	if ( !acum.empty() )
		vec.push_back(acum);

	if (!content)
		return	false;	// 中身の無いスクリプト(実行してもしなくても一緒)と判断。

	ioScript="";

	for (vector<string>::iterator i=vec.begin() ; i!=vec.end() ; ++i) {
		if ( i->at(0)!='\\' && i->at(0)!='%' ) {
			// さくらスクリプト以外の文への処理

			// アンカー挿入
			if ( !is_OnTranslate )
				for ( set<string>::iterator j=anchors.begin() ; j!=anchors.end() ; ++j )
					replace(*i, *j, string("\\_a[")+*j+"]"+*j+"\\_a");
		}
		ioScript += *i;
	}


	// 事後置き換え辞書を適用
	if ( !is_OnTranslate )
		for ( strmap::iterator di=replace_after_dic.begin() ; di!=replace_after_dic.end() ; ++di )
			replace(ioScript, di->first, di->second);

	diet_script(ioScript);	// ラストダイエット

	// エスケープしてあった文字を戻す
	m_escaper.unescape(ioScript);

	return	true;
}
Beispiel #5
0
bool	Satori::system_variable_operation(string key, string value, string* result)
{
	// mapにしようよ。
	
	if ( key == "喋り間隔" ) {
		talk_interval = zen2int(value);
		if ( talk_interval<3 ) talk_interval=0; // 3未満は喋らない
		
		// 喋りカウント初期化
		int	dist = static_cast<int>(talk_interval*(talk_interval_random/100.0));
		talk_interval_count = ( dist==0 ) ? talk_interval : (talk_interval-dist)+(random(dist*2));
		
		return true;
	}
	
	if ( key == "喋り間隔誤差" ) {
		talk_interval_random = zen2int(value);
		if ( talk_interval_random>100 ) talk_interval_random=100;
		if ( talk_interval_random<0 ) talk_interval_random=0;
		
		// 喋りカウント初期化
		int	dist = int(talk_interval*(talk_interval_random/100.0));
		talk_interval_count = ( dist==0 ) ? talk_interval : 
		(talk_interval-dist)+(random(dist*2));
		
		return true;
	}
	
	if ( key =="見切れてても喋る" ) {
		is_call_ontalk_at_mikire= (value=="有効");
		return true;
	}

	if ( key == "今回は喋らない" ) {
		return_empty=(value=="有効");
		return true;
	}
	
	if ( key == "スクリプトの一番頭" ) {
		header_script = value;
		return true;
	}

	if ( key == "呼び出し回数制限" ) {
		m_nest_limit = zen2int(value);
		if ( m_nest_limit < 0 ) { m_nest_limit = 0; }
		return true;
	}

	if ( key == "ジャンプ回数制限" ) {
		m_jump_limit = zen2int(value);
		if ( m_jump_limit < 0 ) { m_jump_limit = 0; }
		return true;
	}
	
	if ( key == "スコープ切り換え時" ) {
		append_at_scope_change = zen2han(value);
		return true;
	}

	if ( key == "さくらスクリプトによるスコープ切り換え時" ) {
		append_at_scope_change_with_sakura_script = zen2han(value);
		return true;
	}

	if ( key == "トーク開始時" ) {
		append_at_talk_start = zen2han(value);
		return true;
	}

	if ( key == "トーク終了時" ) {
		append_at_talk_end = zen2han(value);
		return true;
	}

	if ( key == "選択肢開始時" ) {
		append_at_choice_start = zen2han(value);
		return true;
	}
	
	if ( key == "選択肢終了時" ) {
		append_at_choice_end = zen2han(value);
		return true;
	}

	if ( key == "会話時サーフェス戻し" || key == "会話時サーフィス戻し" ) {
		if ( value == "有効" ) {
			surface_restore_at_talk = SR_NORMAL;
		}
		else if ( value == "強制" ) {
			surface_restore_at_talk = SR_FORCE;
		}
		else {
			surface_restore_at_talk = SR_NONE;
		}
		return true;
	}

	if ( key == "今回は会話時サーフェス戻し" || key == "今回は会話時サーフィス戻し" ) {
		if ( value == "有効" ) {
			surface_restore_at_talk_onetime = SR_NORMAL;
		}
		else if ( value == "強制" ) {
			surface_restore_at_talk_onetime = SR_FORCE;
		}
		else {
			surface_restore_at_talk_onetime = SR_NONE;
		}
		return true;
	}
	
	if ( key == "自動アンカー" ) {
		if ( value == "有効" ) {
			auto_anchor_enable = true;
			auto_anchor_enable_onetime = auto_anchor_enable;
		}
		else {
			auto_anchor_enable = false;
			auto_anchor_enable_onetime = auto_anchor_enable;
		}
		return true;
	}

	if ( key == "今回は自動アンカー" ) {
		if ( value == "有効" ) {
			auto_anchor_enable_onetime = true;
		}
		else {
			auto_anchor_enable_onetime = false;
		}
		return true;
	}
	
	if ( compare_head(key,  "サーフェス加算値") && aredigits(key.c_str() + const_strlen("サーフェス加算値")) ) {
		int n = zen2int(key.c_str() + const_strlen("サーフェス加算値"));
		surface_add_value[n]= zen2int(value);
		
		variables[string()+"デフォルトサーフェス"+itos(n)] = value;
		next_default_surface[n] = zen2int(value);
		if ( !is_speaked_anybody() )
			default_surface[n]=next_default_surface[n];
		return true;
	}

	if ( compare_head(key,  "デフォルトサーフェス") && aredigits(key.c_str() + const_strlen("デフォルトサーフェス")) ) {
		int n = zen2int(key.c_str() + const_strlen("デフォルトサーフェス"));
		next_default_surface[n]= zen2int(value);
		if ( !is_speaked_anybody() )
			default_surface[n]=next_default_surface[n];
		return true;
	}

	if ( compare_head(key,  "BalloonOffset") && aredigits(key.c_str() + const_strlen("BalloonOffset")) ) {
		int n = stoi(key.c_str() + const_strlen("BalloonOffset"));
		BalloonOffset[n] = value;
		validBalloonOffset[n] = true;
		return true;
	}

	if ( key == "トーク中のなでられ反応") {
		insert_nade_talk_at_other_talk= (value=="有効");
		return true;
	}
	
	if ( key == "なでられ持続秒数") {
		nade_valid_time_initializer = zen2int(value);
		return true;
	}

	if ( key == "なでられ反応回数") {
		nade_sensitivity = zen2int(value);
		return true;
	}

	if ( key == "デバッグ" ) {
		fDebugMode = (value=="有効");
		return true;
	}

	if ( key == "Log" ) {
		Sender::validate(value=="有効");
		return true;
	}

	if ( key == "RequestLog" ) {
		fRequestLog = (value=="有効");
		return true;
	}

	if ( key == "OperationLog" ) {
		fOperationLog = (value=="有効");
		return true;
	}
	
	if ( key == "ResponseLog" ) {
		fResponseLog = (value=="有効");
		return true;
	}
	
	if ( key == "自動挿入ウェイトの倍率" ) {
		rate_of_auto_insert_wait= zen2int(value);
		rate_of_auto_insert_wait = min(1000, max(0, rate_of_auto_insert_wait));
		variables["自動挿入ウェイトの倍率"] = int2zen(rate_of_auto_insert_wait);
		return true;
	}
	
	if ( key == "自動挿入ウェイトタイプ" ) {
		if ( value == "一般" ) {
			type_of_auto_insert_wait = 2;
			variables["自動挿入ウェイトタイプ"] = "一般";
		}
		else if ( value == "無効" ) {
			type_of_auto_insert_wait = 0;
			variables["自動挿入ウェイトタイプ"] = "無効";
		}
		else /* if ( value == "里々" ) */ {
			type_of_auto_insert_wait = 1;
			variables["自動挿入ウェイトタイプ"] = "里々";
		}
		return true;
	}
	
	if ( key == "辞書フォルダ" ) {
		strvec	words;
		split(value, ",",dic_folder);
		reload_flag=true;
		return true;
	}
	
	if ( key == "セーブデータ暗号化" ) {
		fEncodeSavedata = (value=="有効");
		return true;
	}
	
	if ( compare_head(key,"単語群「") && compare_tail(key,"」の重複回避") ) {
		variables.erase(key);
		words.setOC( string(key.c_str()+8, key.length()-8-12), value );
		return true;
	}

	if ( compare_head(key,"文「") && compare_tail(key,"」の重複回避") ) {
		variables.erase(key);
		talks.setOC( string(key.c_str()+4, key.length()-4-12), value );
		return true;
	}
	
	if ( key == "次のトーク" ) {
		variables.erase(key);
		int	count=1;
		while ( reserved_talk.find(count) != reserved_talk.end() )
			++count;
		reserved_talk[count] = value;
		sender << "次回のランダムトークが「" << value << "」に予\x96\xf1されました。" << endl;
		return true;
	}
	
	if ( compare_head(key,"次から") && compare_tail(key,"回目のトーク") ) {
		variables.erase(key);
		int	count = zen2int( string(key.c_str()+6, key.length()-6-12) );
		if ( count<=0 ) {
			sender << "トーク予\x96\xf1、設定値がヘンです。" << endl;
		}
		else {
			while ( reserved_talk.find(count) != reserved_talk.end() )
				++count;
			reserved_talk[count] = value;
			sender << count << "回後のランダムトークが「" << value << "」に予\x96\xf1されました。" << endl;
		}
		return true;
	}

	if ( key=="トーク予\x96\xf1のキャンセル" ) {
		if ( value=="*" )
			reserved_talk.clear();
		else
			for (map<int, string>::iterator it=reserved_talk.begin(); it!=reserved_talk.end() ; )
				if ( value == it->second )
					reserved_talk.erase(it++);
				else
					++it;
		return true;
	}

	if ( key == "SAORI引数の計算" ) {
		if (value=="有効")
			mSaoriArgumentCalcMode = SACM_ON;
		else if (value=="無効")
			mSaoriArgumentCalcMode = SACM_OFF;
		else
			mSaoriArgumentCalcMode = SACM_AUTO;
		return true;
	}
	
	if ( key == "辞書リロード" && value=="実行") {
		variables.erase(key);
		reload_flag=true;
		return true;
	}
	
	if ( key == "手動セーブ" && value=="実行") {
		variables.erase(key);
		if ( is_dic_loaded ) {
			this->Save();
		}
		return true;
	}
	
	if ( key == "自動セーブ間隔" ) {
		mAutoSaveInterval = zen2int(value);
		mAutoSaveCurrentCount = mAutoSaveInterval;
		if ( mAutoSaveInterval > 0 )
			sender << ""  << itos(mAutoSaveInterval) << "秒間隔で自動セーブを行います。" << endl;
		else
			sender << "自動セーブは行いません。" << endl;
		return true;
	}
	
	if ( key == "全タイマ解除" && value=="実行") {
		variables.erase(key);
		for (strintmap::const_iterator i=timer.begin();i!=timer.end();++i)
			variables.erase(i->first + "タイマ");
		timer.clear();
		return true;
	}
	
	if ( key == "教わること" ) {
		variables.erase(key);
		teach_genre=value;
		if ( result != NULL )
			*result += "\\![open,teachbox]";
		return true;
	}
	
	if ( key.size()>6 && compare_tail(key, "タイマ") ) {
		string	name(key.c_str(), strlen(key.c_str())-6);
		/*if ( sentences.find(name) == sentences.end() ) {
		result = string("※ タイマ終了時のジャンプ先 *")+name+" がありません ※";
		// セーブデータ復帰時を考慮
		}
		else */{
		int sec = zen2int(value);
		if ( sec < 1 ) {
			variables.erase(key);
			if ( timer.find(name)!=timer.end() ) {
				timer.erase(name);
				sender << "タイマ「"  << name << "」の予\x96\xf1がキャンセルされました。" << endl;
			} else
				sender << "タイマ「"  << name << "」は元から予\x96\xf1されていません。" << endl;
		} else {
			timer[name] = sec;
			sender << "タイマ「"  << name << "」が" << sec << "秒後に予\x96\xf1されました。" << endl;
		}
		}
		return true;
	}

	if ( key == "引数区切り追加" && value.size()>0 ) {
		variables.erase(key);
		mDelimiters.insert(value);
		return true;
	}
	
	if ( key == "引数区切り削除" && value.size()>0 ) {
		variables.erase(key);
		mDelimiters.erase(value);
		return true;
	}
	
	if ( compare_head(key, "Value") && aredigits(key.c_str() + 5) )
	{
		variables.erase(key);
		if(value!=""){
			mResponseMap[string()+"Reference"+key.substr(5)] = value;
		}else{
			mResponseMap.erase(string()+"Reference"+key.substr(5));
		}
		return true;
	}

	return	false;
}
Beispiel #6
0
int Satori::SentenceToSakuraScriptInternal(const strvec &vec,string &result,string &jump_to,ptrdiff_t &ip)
{
    // 再帰管理
    static	int nest_count=0;
    ++nest_count;
    //DBG(sender << "enter SentenceToSakuraScriptInternal, nest-count: " << nest_count << ", vector_size: " << vec.size() << endl);

    if ( m_nest_limit > 0 && nest_count > m_nest_limit ) {
        sender << "呼び出し回数超過" << endl;
        --nest_count;
        return 0;
    }

    static const int basewait=3;

    strvec::const_iterator it = vec.begin();
    std::advance(it,ip);

    for ( ; it != vec.end() ; ++it) {
        const char*	p = it->c_str();
        //DBG(sender << nest_count << " '" << p << "'" << endl);

        if ( it==vec.begin() && strncmp(p, "→", 2)==0 ) {
            p+=2;
            updateGhostsInfo();	// ゴースト情報を更新

            if ( ghosts_info.size()>=2 ) {	// そもそも自分以外にゴーストはいるのか。
                string	temp = p;
                vector<strmap>::iterator i=ghosts_info.begin();
                ++i; // 自分は飛ばす
                for ( ; i!=ghosts_info.end() ; ++i ) {
                    string	name = (*i)["name"];
                    sender << "ghost: " << name <<endl;
                    if ( compare_head(temp, name) ) {// 相手を特定
                        mCommunicateFor = name;
                        p += mCommunicateFor.size();
                        break;
                    }
                }


                if ( i==ghosts_info.end() ) {	// 特定しなかった場合
                    // ランダム
                    //int n = random(ghosts_info.size()-1))+1;
                    //assert( n>=1 && n < ghosts_info.size());
                    mCommunicateFor = (ghosts_info[1])["name"];

                    // あかん、隣で起動している〜〜にならん
                }
            }
        }

        // 選択肢	\q?[id,string]
        if ( strncmp(p, "_", 2)==0 ) {
            if ( strlen(p)>1023 )
                continue;
            char	buf[1024];
            strncpy(buf, p+2, sizeof(buf) / sizeof(buf[0]));

            char*	choiced = buf;
            char*	id = (char*)strstr_hz(buf, "\t"); // 選択肢ラベルとジャンプ先の区切り

            result += append_at_choice_start;
            if ( id == NULL ) {
                string	str=UnKakko(choiced);
                //result += string("\\q")+itos(question_num++)+"["+str+"]["+str+"]";
                result += "\\q["+str+","+str+"]";
            } else {
                *id++='\0';
                while ( *id=='\t' ) ++id; // 選択肢ラベルとジャンプ先の区切り
                //result += string("\\q")+itos(question_num++)+"["+UnKakko(id)+"]["+UnKakko(choiced)+"]";
                result += "\\q["+UnKakko(choiced)+","+UnKakko(id)+"]";
            }
            result += append_at_choice_end;

            continue;
        }

        // ちょっと微妙な存在意義。
        if ( strncmp(p, "\\s", 2)==0 ) {
            if ( !is_speaked(speaker) ) {
                if ( surface_changed_before_speak.find(speaker) == surface_changed_before_speak.end() ) {
                    surface_changed_before_speak.insert(map<int,bool>::value_type(speaker,is_speaked_anybody()) );
                }
            }
        }

        // ジャンプ
        if ( strncmp(p, ">", 2)==0 || strncmp(p, "≫", 2)==0 ) {
            strvec	words;
            split(p+2, "\t", words, 2); // ジャンプ先とジャンプ条件の区切り

            if ( words.size()>=2 ) {
                string	r;
                if ( !calculate(words[1], r) )
                    break;
                if ( zen2int(r) == 0 ) {
                    sender << "*計算結果が0だったため、続行します。" << endl;
                    continue;
                }
            }

            if ( words.size() >= 1 ) {
                jump_to = UnKakko(words[0].c_str(),false,true);
            }
            else {
                jump_to.erase();
            }

            if ( strncmp(p, "≫", 2)==0 ) {
                ip = std::distance(vec.begin(),it) + 1;
                --nest_count;
                return 2;
            }
            else {
                ip = std::distance(vec.begin(),it) + 1;
                --nest_count;
                return 1;
            }
        }

        // 変数を設定
        if ( strncmp(p, "$", 2)==0 ) {
            const char* v;
            string	value;
            bool	do_calc=false;
            p+=2;
            if ( (v=strstr_hz(p, "\t"))!=NULL ) { // 変数名と変数に設定する内容の区切り
                value = UnKakko(v+1,false,true);
            }
            else if ( (v=strstr_hz(p, "="))!=NULL || (v=strstr_hz(p, "="))!=NULL ) {
                value = UnKakko(v+((*v=='=') ? 1 : 2),false,true);
                do_calc=true;
            }
            else {
                //v = p+strlen(p);
                //value="";
                result += "\\n※ $による変数代入文には、タブによる区切りか、=による計算式が必要です ※\\n\\n[half]'" + value +"'";
                break;
            }

            string	key(p, v-p);
            key = UnKakko(key.c_str(),false,true);

            if ( key=="" ) {
                result += "$"; // $そのまま表示
                speaked_speaker.insert(speaker);
            }
            else if ( aredigits(zen2han(key)) ) {
                sender << "$" << key << " 数字のみの変数名は扱えません." << endl;
                erase_var(key);	// 存在抹消
            }
            else if ( value=="" ) {
                sender << "$" << key << "/cleared." << endl;
                erase_var(key);	// 存在抹消
                system_variable_operation(key, "", &result);//存在抹消したものがシステム変数かも!
            }
            else {
                bool isOverwritten;
                bool isSysValue;

                // "0"は代入先を先に参照する時、エラーを返さないように。
                string *pstr = GetValue(key,isSysValue,true,&isOverwritten,"0");

                if ( do_calc ) {
                    if ( !calculate(value, value) )
                        break;
                    if ( aredigits(value) ) {
                        value = int2zen(stoi(value));
                    }
                }

                sender << "$" << key << "=" << value << "/" <<
                       (isOverwritten ? "written." : "overwritten.")<< endl;

                if ( pstr ) {
                    *pstr = value;
                }
                system_variable_operation(key, value, &result);
            }
            continue;
        }

        // 通常処理
        while ( p[0] != '\0' ) {
            string	c=get_a_chr(p);	// 全角半角問わず一文字取得し、pを一文字すすめる

            if ( c=="(" ) {	// 何かを取得・挿入
                character_wait_exec;
                result += KakkoSection(p);
            }
            else if ( c=="\xff" ) {	//内部特殊表現
                c=get_a_chr(p);
                if ( c=="\x01" ) { //0xff0x01=スコープ切り替え 後に半角数値が1文字続く
                    c=get_a_chr(p);
                    int speaker_tmp = stoi(c.c_str());
                    if ( is_speaked(speaker) && speaker != speaker_tmp ) {
                        result += append_at_scope_change;
                        chars_spoken += 2;
                    }
                    speaker = speaker_tmp;
                    character_wait_clear(2);
                    if ( speaker == 0 ) {
                        result += "\\0";
                    }
                    else if ( speaker == 1 ) {
                        result += "\\1";
                    }
                    else {
                        result += "\\p[" + c + "]";
                    }
                }
            }
            else if ( c==":" ) {	// スコープ切り替え - ここは二人を想定。
                if ( is_speaked(speaker) ) {
                    result += append_at_scope_change;
                    chars_spoken += 2;
                }
                speaker = (speaker==0) ? 1 : 0;
                character_wait_clear(2);
                result += (speaker ? "\\1" : "\\0");
            }
            else if ( c=="\\" || c=="%" ) {	// さくらスクリプトの解釈、というか解釈のスキップ。

                if (*p=='\\'||*p=='%') {	// エスケープされた\, %
                    result += c + *p++;
                    continue;
                }

                const char*	start=p;
                string	cmd="",opt="";

                while (!_ismbblead(*p) && (isalpha(*p)||isdigit(*p)||*p=='!'||*p=='-'||*p=='*'||*p=='&'||*p=='?'||*p=='_'))
                    ++p;
                cmd.assign(start, p-start);

                if ( cmd == "_?" || cmd == "_!" ) { //エスケープ処理 この間に自動タグ挿入はしない
                    const char* e1 = strstr(p,"\\_?");
                    if ( ! e1 ) {
                        e1 = strstr(p,"\\_!");
                    }

                    if ( e1 ) {
                        character_wait_exec;
                        result += c;
                        result += cmd;

                        opt.assign(p,e1-p+3);
                        opt = UnKakko(opt.c_str());

                        p = e1 + 3; //endtag

                        result += opt;
                        continue;
                    }
                }

                if (*p=='[') {
                    const char* opt_start = ++p;
                    while (*p!=']') {
                        if (p[0]=='\\' && p[1]==']')	// エスケープされた]
                            ++p;
                        p += _ismbblead(*p) ? 2 : 1;
                    }
                    opt.assign(opt_start, p++ -opt_start);
                    opt=UnKakko(opt.c_str());
                }

                if ( cmd=="n" ) {
                    // 改行
                    character_wait_clear(2);
                }
                else if ( ( (cmd=="0" || cmd=="h") && speaker==1) || ( (cmd=="1" || cmd=="u") && speaker==0) ) {
                    // スコープ切り替え
                    if ( is_speaked(speaker) ) {
                        result += append_at_scope_change_with_sakura_script;
                        chars_spoken += 2;
                    }
                    speaker = stoi(cmd);
                    character_wait_clear(2);
                }
                else if ( cmd=="p" && aredigits(opt) ) {
                    int spktmp = stoi(opt);
                    if ( speaker != spktmp ) {
                        // スコープ切り替えonSSP/CROW
                        if ( is_speaked(speaker) ) {
                            result += append_at_scope_change_with_sakura_script;
                            chars_spoken += 2;
                        }
                        speaker = spktmp;
                        character_wait_clear(2);
                    }
                }
                else if ( cmd=="s" ) {
                    //サーフィス切り替えの前にウェイトは済ませておくこと
                    character_wait_exec;
                }
                else if ( cmd=="_q" ) {
                    if ( ! is_quick_section ) { //これからクイックセクションなのでウエイトを全部消化
                        character_wait_exec;
                    }
                    is_quick_section = ! is_quick_section;
                }

                if ( opt!="" ) {
                    //sender << "ss_cmd: " << c << "," << cmd << "," << opt << endl;
                    result += c + cmd + "[" + opt + "]";
                } else {
                    //sender << "ss_cmd: " << c << "," << cmd << endl;
                    result += c + cmd;
                }


                //result += string(start, p-start);
            }
            else {	// 通常の一文字
                character_wait_exec;

                speaked_speaker.insert(speaker);
                result += c;
                chars_spoken += c.size();
                if ( c=="。" || c=="、" ) {
                    character_wait_clear(c=="、"?1:2);
                }
            }

        }
        character_wait_clear(2);
        result += "\\n";
    }

    //DBG(sender << "leave SentenceToSakuraScriptInternal, nest-count: " << nest_count << endl);
    --nest_count;
    return 0;
}
Beispiel #7
0
int main( int argc, char *argv[ ], char *envp[ ] )
{
	// 実行ファイルのあるフォルダ名を取得
	TCHAR	szPath[MAX_PATH]="";
	::GetModuleFileName(NULL, szPath, MAX_PATH);
	char*	p = FindFinalChar(szPath, '\\');
	if ( *p == NULL )
		return	1;
	*p='\0';
	base_folder = szPath;
	sender << "[sodate]" << endl;
	sender << "ディスク上の対象フォルダは " << base_folder << "です。" << endl;

	::SetCurrentDirectory(base_folder.c_str());

	// 設置場所の確認
	if ( !isExistFolder( (base_folder+"\\ghost\\master").c_str() ) ) {
		error("ghost/masterが見つかりません。設置位置を確認してください。");
		return	false;
	}
	if ( !isExistFolder( (base_folder+"\\shell\\master").c_str() ) ) {
		error("shell/masterが見つかりません。設置位置を確認してください。");
		return	false;
	}

	// 設定ファイルの読み込み
	sender << "設定ファイル sodate.dat を読み込みます。" << endl;
	if ( !strmap_from_file(conf, base_folder+"\\sodate.dat", byte_value_1) ) {
		error("先に sodate_setup.exe を実行してください。");
		return	false;
	}

	// 暗号保存されたパスワードをデコード
	string	str = decode(conf["password"]);
	int	len = str.size()/2;
	byte*	buf = new byte[len+1];
	buf[len]='\0';
	string_to_binary(str, buf);
	xor_filter(buf, len, 186);
	conf["password"] = decode( (char*)buf );

	// 古いupdates2.dauを削除
	::DeleteFile( (base_folder+"\\updates2.dau").c_str() );
	::DeleteFile( (base_folder+"\\ghost\\master\\updates2.dau").c_str() );

	// 対象ファイル選定
	cout << "対象ファイルを選定中" << endl;
	strvec	allow_files_vec, deny_files_vec;
	stringset	deny_files_set;
	split(conf["allow_files"], byte_value_2, allow_files_vec);
	split(conf["deny_files"], byte_value_2, deny_files_vec);

	// 除外ファイルが(存在すれば)set化
	for (strvec::iterator i=deny_files_vec.begin() ; i!=deny_files_vec.end() ; ++i) {
		string	full_path = base_folder+"\\"+*i;
		replace(full_path, "/", "\\");
		string	folder_name = get_folder_name(full_path);

		WIN32_FIND_DATA	fd;
		HANDLE	h = ::FindFirstFile(full_path.c_str(), &fd);
		if ( h == INVALID_HANDLE_VALUE )
			continue;
		
		do {
			if ( fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY )
				continue;
			deny_files_set.insert(folder_name+"\\"+fd.cFileName);
		} while ( ::FindNextFile(h, &fd) );
		::FindClose(h);
	}

	// 対象ファイルを、除外対象に一致しないことを確認しつつfiles化
	for (strvec::iterator i=allow_files_vec.begin() ; i!=allow_files_vec.end() ; ++i) {

		string	full_path = base_folder+"\\"+*i;
		replace(full_path, "/", "\\");
		string	folder_name = get_folder_name(full_path);

		WIN32_FIND_DATA	fd;
		HANDLE	h = ::FindFirstFile(full_path.c_str(), &fd);
		if ( h == INVALID_HANDLE_VALUE ) {
			sender << *i << "に該当するファイルがありません。" << endl;
			continue;
		}
		
		int	n=0;
		do {
			if ( fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY )
				continue;
			string	filename=folder_name+"\\"+fd.cFileName;
			if ( deny_files_set.find(filename) == deny_files_set.end() ) {
				files.push_back(filename);
				++n;
			}
		} while ( ::FindNextFile(h, &fd) );
		::FindClose(h);

		if ( n==0 ) {
			sender << *i << "に該当するファイルがありません。" << endl;
			continue;
		}
	}

	if ( files.size()==0 ) {
		error("対象となるファイルが存在しません。");
		return	1;
	}
	else {

		// 本家のupdates2.dauに構造を合わせるためのリストのソート

		list<string>	OLD = files;	// 複製を作る
		files.clear();
		list<string>&	NEW = files;	// 空っぽのほう

		// まずは単なるアルファベットソート
		files.sort();		

		// まずはshellフォルダの中身を移行
		list<string>::iterator	i;;
		for (i=OLD.begin(); i!=OLD.end() ;) {
			if ( compare_head(get_folder_name(*i), base_folder+"\\shell\\") ) {
				NEW.push_back(*i);
				i=OLD.erase(i);
			} else
				++i;
		}

		// 続いてghostフォルダの中身を移行
		for (i=OLD.begin(); i!=OLD.end() ;) {
			if ( compare_head(get_folder_name(*i), base_folder+"\\ghost\\") ) {
				NEW.insert(NEW.begin(), *i);	// 反転しないように
				i=OLD.erase(i);
			} else
				++i;
		}

		// ghost, shell,ルート以外のフォルダの中身を移行(あるのか?)
		for (i=OLD.begin(); i!=OLD.end() ;) {
			if ( !compare_head(get_folder_name(*i), base_folder) ) {
				NEW.push_back(*i);
				i=OLD.erase(i);
			} else
				++i;
		}

		// 残り。ルートフォルダの中身を移行
		NEW.insert(NEW.end(), OLD.begin(), OLD.end());
		OLD.clear();
	}



	sender << "updates2.dauを作成中" << endl;
	bool	makeUpdates2(string base_folder, const list<string>& files);
	if ( !makeUpdates2(szPath, files) ) {
		error("updates2.dauが作成できませんでした。");
		return	1;
	}
	sender << "updates2.dauを作成完了" << endl;
	// 同じものをコピー
	::CopyFile( (base_folder+"\\updates2.dau").c_str(), (base_folder+"\\ghost\\master\\updates2.dau").c_str(), FALSE );


	if ( conf["is_create_archive"]!="0") {
		sender << "zip/narアーカイブを作成中" << endl;

		if ( !is_exist_file(base_folder+"\\install.txt") ) {
			error("zip/narアーカイブを作成するためには、ゴーストのルートフォルダにinstall.txtが必要です。");
			return	false;
		}

		SYSTEMTIME	st;
		char	buf[10];
		::GetLocalTime(&st);
		sprintf(buf, "%02d", st.wYear%100);
		replace(conf["archive_filename"], "%year", buf);
		sprintf(buf, "%04d", st.wYear);
		replace(conf["archive_filename"], "%year4", buf);
		sprintf(buf, "%02d", st.wMonth);
		replace(conf["archive_filename"], "%month", buf);
		sprintf(buf, "%02d", st.wDay);
		replace(conf["archive_filename"], "%day", buf);
		sprintf(buf, "%02d", st.wHour);
		replace(conf["archive_filename"], "%hour", buf);
		sprintf(buf, "%02d", st.wMinute);
		replace(conf["archive_filename"], "%minute", buf);
		sprintf(buf, "%02d", st.wSecond);
		replace(conf["archive_filename"], "%second", buf);

		if ( (conf["archive_local_folder"])[ conf["archive_local_folder"].size()-1 ] != '\\' )
			conf["archive_local_folder"] += "\\";

		string	archive_filename = conf["archive_local_folder"]+conf["archive_filename"];

		// 既にあるなら削除しておく
		::DeleteFile(archive_filename.c_str());

		/*
		string	cmd = "zip.exe";
		string	opt = "-r " + archive_filename;
		for (list<string>::const_iterator i=files.begin(); i!=files.end() ; ++i ) {
			string	filename(*i);
			opt += string(" ") + (filename.c_str()+base_folder.size()+1);
		}
		opt += " ghost\\master\\updates2.dau";
		if ( opt.find(" install.txt")==string::npos )
			opt += " install.txt";	// nar時には必須なので。
		opt += " > nul";
		*/
		//system((cmd+" "+opt).c_str());
		//::ShellExecute(NULL, NULL, (cmd+" "+opt).c_str(), NULL, NULL, SW_SHOW);
		//if ( !is_exist_file(archive_filename) ) {

		list<string>	zip_files;
		bool	exist_install_txt=false;
		for (list<string>::const_iterator i=files.begin(); i!=files.end() ; ++i ) {
			zip_files.push_back(i->c_str()+base_folder.size()+1);
			if ( zip_files.back()=="install.txt" )
				exist_install_txt = true;
		}
		zip_files.push_back("ghost\\master\\updates2.dau");
		if ( !exist_install_txt )
			zip_files.push_back("install.txt");

		if ( !makeZip(archive_filename, zip_files) ) {
			error("アーカイブファイル'"+archive_filename+"'が作成できませんでした。");
		}
		else {
			sender << "zip/narアーカイブ '" << archive_filename << "' を作成完了" << endl;
		}
	}

	files.push_back(base_folder+"\\updates2.dau");
	// フォルダ別に分離格納 as global
	//		map<string, set<string> >	files_on_dir;	// dirname : filenames
	{
		for (list<string>::iterator i=files.begin(); i!=files.end() ; ++i) {
			string	rel_path = (i->c_str()+base_folder.size()+1);
			files_on_dir[ get_folder_name(rel_path) ].insert( get_file_name(rel_path) );
		}
	}

	bool	uploadFiles(const string&, list<string>&);
	if ( conf["is_upload"]!="0")
		uploadFiles(szPath, files);

	// ルートのupdates2.dauはアップロードした後に削除。
	::DeleteFile( (base_folder+"\\updates2.dau").c_str() );

	return	0;
}