text:
// Quest.cpp: implementation of the CQuest class.
//
//////////////////////////////////////////////////////////////////////
#include <boost/format.hpp>
#include "stdhdrs.h"

#include "Server.h"
#include "../ShareLib/DBCmd.h"
#include "CmdMsg.h"
#include "Quest.h"
#include "Log.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CQuestProto::CQuestProto()
{
	m_index = 0;
	m_type[0] = -1;
	m_type[1] = -1;

	m_startType = -1;
	m_startData = 0;
	m_prizeNPC = -1;

	// 필요 조건
	m_needMinLevel = 1;
	m_needMaxLevel = 60;
	m_needJob = -1;
	memset(m_needItemIndex, -1, sizeof(int) * QUEST_MAX_NEED_ITEM);
	memset(m_needItemCount, 0, sizeof(int) * QUEST_MAX_NEED_ITEM);

	m_needRvRType = 0;
	m_needRvRGrade = 0;

	// 수행 조건
	memset(m_conditionType, -1, sizeof(int) * QUEST_MAX_CONDITION);
	memset(m_conditionIndex, 0, sizeof(int) * QUEST_MAX_CONDITION);
	memset(m_conditionNum, 0, sizeof(int) * QUEST_MAX_CONDITION);
	memset(m_conditionData, 0, sizeof(m_conditionData));

	// 보상 조건
	memset(m_prizeType, -1, sizeof(int) * QUEST_MAX_PRIZE);
	memset(m_prizeIndex, 0, sizeof(int) * QUEST_MAX_PRIZE);
	memset(m_prizeData, 0, sizeof(int) * QUEST_MAX_PRIZE);

	// 보상 조건
	memset(m_optPrizeType, -1, sizeof(int) * QUEST_MAX_OPTPRIZE);
	memset(m_optPrizeIndex, 0, sizeof(int) * QUEST_MAX_OPTPRIZE);
	memset(m_optPrizeData, 0, sizeof(int) * QUEST_MAX_OPTPRIZE);

	m_prequestNum =0;
	m_startNpcZoneNum = 0;
	m_prizeNpcZoneNum = 0;
	m_needExp = 0;

	m_failValue = -1;
	m_partyScale = 0;

	memset(m_StartGiveItem, -1, sizeof(int) * QUESTITEM_MAX_ARRAYCOUNT);
	m_StartGiveKindCount = 0;
	memset(m_StartGiveNumCount, 0, sizeof(int) * QUESTITEM_MAX_ARRAYCOUNT);
}

//////////////////////////
// CQuestProtoList member

CQuestProtoList::CQuestProtoList()
{
	m_proto = NULL;
	m_nCount = 0;

	std::string tstr = "";
	for (int i = 0; i < QUEST_MAX_NEED_ITEM; ++i)
	{
		tstr = boost::str(boost::format("a_need_item%d") % i);
		a_need_item_str.push_back(tstr);

		tstr = boost::str(boost::format("a_need_item_count%d") % i);
		a_need_item_count_str.push_back(tstr);
	}

	for (int i = 0; i < QUEST_MAX_CONDITION; ++i)
	{
		tstr = boost::str(boost::format("a_condition%d_type") % i);
		a_condition_type_str.push_back(tstr);

		tstr = boost::str(boost::format("a_condition%d_index") % i);
		a_condition_index_str.push_back(tstr);

		tstr = boost::str(boost::format("a_condition%d_num") % i);
		a_condition_num_str.push_back(tstr);

		for (int j = 0; j < QUEST_MAX_CONDITION_DATA; ++j)
		{
			tstr = boost::str(boost::format("a_condition%d_data%d") % i % j);
			a_condition_data_str[i].push_back(tstr);
		}
	}

	for (int i = 0; i < QUEST_MAX_PRIZE; ++i)
	{
		tstr = boost::str(boost::format("a_prize_type%d") % i);
		a_prize_type_str.push_back(tstr);

		tstr = boost::str(boost::format("a_prize_index%d") % i);
		a_prize_index_str.push_back(tstr);

		tstr = boost::str(boost::format("a_prize_data%d") % i);
		a_prize_data_str.push_back(tstr);
	}

	for (int i = 0; i < QUEST_MAX_OPTPRIZE; ++i)
	{
		tstr = boost::str(boost::format("a_opt_prize_type%d") % i);
		a_opt_prize_type_str.push_back(tstr);

		tstr = boost::str(boost::format("a_opt_prize_index%d") % i);
		a_opt_prize_index_str.push_back(tstr);

		tstr = boost::str(boost::format("a_opt_prize_data%d") % i);
		a_opt_prize_data_str.push_back(tstr);
	}
}

CQuestProtoList::~CQuestProtoList()
{
	if (m_proto)
		delete [] m_proto;

	m_proto = NULL;
}

bool CQuestProtoList::Load()
{
	CDBCmd dbQuest;
	dbQuest.Init(&gserver->m_dbdata);
	dbQuest.SetQuery("SELECT * FROM t_quest WHERE a_enable=1 ORDER BY a_index");

	if (!dbQuest.Open())
		return false;

	m_nCount = dbQuest.m_nrecords;
	m_proto = new CQuestProto[m_nCount];

	int i, j, k;

	if(!dbQuest.MoveFirst())
		return true;

	for (i=0; i < m_nCount; i++)
	{
		dbQuest.GetRec("a_index",			m_proto[i].m_index);
		dbQuest.GetRec("a_type1",			m_proto[i].m_type[0]);
		dbQuest.GetRec("a_type2",			m_proto[i].m_type[1]);
		dbQuest.GetRec("a_start_type",		m_proto[i].m_startType);
		dbQuest.GetRec("a_start_data",		m_proto[i].m_startData);
		dbQuest.GetRec("a_prize_npc",		m_proto[i].m_prizeNPC);

		dbQuest.GetRec("a_prequest_num",		m_proto[i].m_prequestNum);
		dbQuest.GetRec("a_start_npc_zone_num",	m_proto[i].m_startNpcZoneNum);
		dbQuest.GetRec("a_prize_npc_zone_num",	m_proto[i].m_prizeNpcZoneNum);
		dbQuest.GetRec("a_need_exp",		m_proto[i].m_needExp);

		dbQuest.GetRec("a_need_min_level",	m_proto[i].m_needMinLevel);
		dbQuest.GetRec("a_need_max_level",	m_proto[i].m_needMaxLevel);
		dbQuest.GetRec("a_need_job",		m_proto[i].m_needJob);
		dbQuest.GetRec("a_need_rvr_type",	m_proto[i].m_needRvRType);
		dbQuest.GetRec("a_need_rvr_grade",	m_proto[i].m_needRvRGrade);

		dbQuest.GetRec("a_failvalue",		m_proto[i].m_failValue);
		dbQuest.GetRec("a_partyscale",		m_proto[i].m_partyScale);

		for (j=0; j < QUEST_MAX_NEED_ITEM; j++)
		{
			dbQuest.GetRec(a_need_item_str[j].c_str(), m_proto[i].m_needItemIndex[j]);
			dbQuest.GetRec(a_need_item_count_str[j].c_str(), m_proto[i].m_needItemCount[j]);
		}

		for (j=0; j < QUEST_MAX_CONDITION; j++)
		{
			dbQuest.GetRec(a_condition_type_str[j].c_str(), m_proto[i].m_conditionType[j]);
			dbQuest.GetRec(a_condition_index_str[j].c_str(), m_proto[i].m_conditionIndex[j]);
			dbQuest.GetRec(a_condition_num_str[j].c_str(),	m_proto[i].m_conditionNum[j]);

			for (k=0; k < QUEST_MAX_CONDITION_DATA; k++)
			{
				dbQuest.GetRec(a_condition_data_str[j][k].c_str(), m_proto[i].m_conditionData[j][k]);
			}
		}

		for (j=0; j < QUEST_MAX_PRIZE; j++)
		{
			dbQuest.GetRec(a_prize_type_str[j].c_str(), m_proto[i].m_prizeType[j]);
			dbQuest.GetRec(a_prize_index_str[j].c_str(), m_proto[i].m_prizeIndex[j]);
			dbQuest.GetRec(a_prize_data_str[j].c_str(), m_proto[i].m_prizeData[j]);
		}

		for (j=0; j < QUEST_MAX_OPTPRIZE; j++)
		{
			dbQuest.GetRec(a_opt_prize_type_str[j].c_str(), m_proto[i].m_optPrizeType[j]);
			dbQuest.GetRec(a_opt_prize_index_str[j].c_str(), m_proto[i].m_optPrizeIndex[j]);
			dbQuest.GetRec(a_opt_prize_data_str[j].c_str(), m_proto[i].m_optPrizeData[j]);
		}

		dbQuest.MoveNext();

		map_.insert(map_t::value_type(m_proto[i].m_index, &m_proto[i]));
	}

	return true;
}

CQuestProto* CQuestProtoList::FindProto(int index)
{
	map_t::iterator it = map_.find(index);
	return (it != map_.end()) ? it->second : NULL;
}

CQuestProto* CQuestProtoList::GetProtoIndexByNPC(int mobIndex )
{
	if( m_proto == NULL )
		return NULL;

	int i, j,  k;
	for(k=0; k<m_nCount; k++)
	{
		if( &m_proto[k] == NULL)
			continue;

		switch( m_proto[k].m_type[0] )
		{
		case QTYPE_KIND_REPEAT:
		case QTYPE_KIND_COLLECTION:
		case QTYPE_KIND_DEFEAT:
		case QTYPE_KIND_SAVE:
			break;
		default:
			continue;
		}

		for(i=0; i<QUEST_MAX_CONDITION; i++)
		{
			if ( m_proto[k].m_conditionData[i][0] <= 0)
				break;

			for(j=0; j<	QUEST_MAX_ITEM_DROP_MONSTER; j++)
			{
				if( m_proto[k].m_conditionData[i][j] <= 0 )
					break;

				if( m_proto[k].m_conditionData[i][j] == mobIndex )
					return &m_proto[k];
			}
		}
	}
	return NULL;
}

///////////////
// class CQuest
CQuest::CQuest(const CQuestProto* pQuestProto)
{
	m_pQuestProto = pQuestProto;
	m_cQuestState = QUEST_STATE_INIT;
	memset(m_nQuestValue, 0, sizeof(m_nQuestValue));
	m_bComplete1 = false;
	m_bComplete2 = false;

	m_pPrev = NULL;
	m_pNext = NULL;

	m_nFailValue = 0;
	m_nCompleteTime = 0;
}

CQuest::~CQuest()
{
	m_pQuestProto = NULL;
	m_cQuestState = QUEST_STATE_INIT;
	m_bComplete1 = false;
	m_bComplete2 = false;

	m_pPrev = NULL;
	m_pNext = NULL;
}

void CQuest::QuestUpdateData(CPC* pPC, CNPC* pNPC)
{
	int i, j;

	// 혼자 npc를 다잡았어야 진행!! 구출 퀘스트는 제외
	// TODO : npc를 혼자 다 안잡아도 막타만 치면 되도록 한다!!!
	//if (npc->m_attackList->m_damage < npc->m_totalDamage && this->m_proto->m_type[0] != QTYPE_KIND_SAVE)
	//	return;

	// 이미 완료했으면 return
	if (IsCompleted())
		return ;

	// CONDITION에 따라 검사 처음에 모두 false로 셋팅
	// 조건 검사 하면서 만족하는 조건만 true로 셋팅
	bool bComplete[QUEST_MAX_CONDITION];
	memset(bComplete, 0, sizeof(bComplete));

	switch (GetQuestType0())
	{
	// 수집형 퀘스트
	case QTYPE_KIND_COLLECTION:
	case QTYPE_KIND_MINING_EXPERIENCE:
	case QTYPE_KIND_GATHERING_EXPERIENCE:
	case QTYPE_KIND_CHARGE_EXPERIENCE:
		{
			for (i = 0; i < QUEST_MAX_CONDITION; i++)
			{
				if (m_pQuestProto->m_conditionType[i] == -1)
				{
					bComplete[i] = true;
					continue;
				}

				switch (m_pQuestProto->m_conditionType[i])
				{
				case QCONDITION_ITEM:
					{
						bool bDropNpc = false;

						if( pNPC )
						{
							// condition 부가 데이타 중에 때린 pNPC가 있으면 해당 아이템 인벤으로
							for (j = 0; j < QUEST_MAX_ITEM_DROP_MONSTER; j++)
							{
								if (m_pQuestProto->m_conditionData[i][j] == pNPC->m_proto->m_index)
								{
									bDropNpc = true;
									break;
								}
							}
						}

						// 수행조건에 해당하는 pNPC를 때린것이 아님 리턴!
						if ( pNPC && !bDropNpc)
							continue;  //return;

						// 조건보다 이상이면 더이상 아이템 안줌
						if (GetQuestValue(i) >= m_pQuestProto->m_conditionNum[i])
						{
							bComplete[i] = true;
							continue;
						}

						CItem* item = NULL;
						if (GetRandom(1, 10000) <= m_pQuestProto->m_conditionData[i][QUEST_MAX_CONDITION_DATA-1])
							item = gserver->m_itemProtoList.CreateItem(m_pQuestProto->m_conditionIndex[i], -1, 0, 0, 1);

						if (!item)
							continue;

						if (pPC->m_inventory.addItem(item) == false)
						{
							delete item;

							CNetMsg::SP rmsg(new CNetMsg);
							SysFullInventoryMsg(rmsg, 0);
							SEND_Q(rmsg, pPC->m_desc);

							return ;
						}

						// 이미 완료했으면 return
						if (IsCompleted())
							break;

						if( GetQuestValue(i) < m_pQuestProto->m_conditionNum[i] )
							IncreaseQuestValue(i);

						bComplete[i] = false;

						{
							CNetMsg::SP rmsg(new CNetMsg);
							QuestStatusMsg(rmsg, this);
							SEND_Q(rmsg, pPC->m_desc);
						}

						// LOG
						GAMELOG << init("ITEM_PICK_QUESTITEM", pPC)
								<< itemlog(item)
								<< end;

						if (GetQuestValue(i) == m_pQuestProto->m_conditionNum[i])
						{
							bComplete[i] = true;
							continue;
						}
						else if (GetQuestValue(i) < m_pQuestProto->m_conditionNum[i])
							bComplete[i] = false;
						else
							continue;
					}
					break;
				}
			}
		}
		break;

	// 전달 퀘스트
	case QTYPE_KIND_DELIVERY:
		break;

	// 반복 퀘스트
	case QTYPE_KIND_REPEAT:
		{
			for (i=0; i < QUEST_MAX_CONDITION; i++)
			{
				if (m_pQuestProto->m_conditionType[i] == -1)
				{
					bComplete[i] = true;
					continue;
				}

				switch (m_pQuestProto->m_conditionType[i])
				{
				case QCONDITION_NPC:
					{
						if (m_pQuestProto->m_conditionIndex[i] == pNPC->m_proto->m_index)
						{
							if (GetQuestValue(i) < m_pQuestProto->m_conditionNum[i])
							{
								bComplete[i] = false;
								IncreaseQuestValue(i);

								CNetMsg::SP rmsg(new CNetMsg);
								QuestStatusMsg(rmsg, this);
								SEND_Q(rmsg, pPC->m_desc);
							}

							// 같으면 bComplete true 셋팅
							if (GetQuestValue(i) == m_pQuestProto->m_conditionNum[i])
							{
								bComplete[i] = true;
								continue;
							}
							else if (GetQuestValue(i) < m_pQuestProto->m_conditionNum[i])
								bComplete[i] = false;
							else
								continue;
						}
						else if(GetQuestValue(i) == m_pQuestProto->m_conditionNum[i])
						{
							bComplete[i] = true;
							continue;
						}
					}
					break;
				}
			}
		}
		break;

	// 싱글던전2 구출 퀘스트
	case QTYPE_KIND_SAVE:
		{
			for (i=0; i < QUEST_MAX_CONDITION; i++)
			{
				if (m_pQuestProto->m_conditionType[i] == -1)
					continue;

				switch (m_pQuestProto->m_conditionType[i])
				{
				case QCONDITION_ITEM:
					{
						// 공격한 몹이 죽었고 아이템 드롭 몬스터(보스)이면 아이템 지급
						if (DEAD(pNPC) && pNPC->m_proto->m_index == m_pQuestProto->m_conditionData[i][0])
						{
							CItem * item = gserver->m_itemProtoList.CreateItem(m_pQuestProto->m_conditionIndex[i], -1, 0, 0, 1);

							if (!item)
								continue;

							if (pPC->m_inventory.addItem(item) == false)
							{
								// 인젠토리 꽉차서 못 받을 때 Drop
								item = pNPC->m_pArea->DropItem(item, pNPC);
								if (!item)
									return;

								{
									CNetMsg::SP rmsg(new CNetMsg);
									item->m_preferenceIndex = pPC->m_index;
									ItemDropMsg(rmsg, pNPC, item);
									pNPC->m_pArea->SendToCell(rmsg, GET_YLAYER(item), item->m_cellX, item->m_cellZ);
								}
							}

							IncreaseQuestValue(i);

							// LOG
							GAMELOG << init("ITEM_PICK_QUESTITEM", pPC)
									<< itemlog(item)
									<< end;

							// 구출 퀘스트의 경우 그냥 리턴
							//return; //왜 그냥 리턴을 하지???
						}
					}
					break;
				}
			}
		}
		break;

	// 싱글던전1 격파 퀘스트
	case QTYPE_KIND_DEFEAT:
		{
			/////////////////////////////////////////
			//싱글 던젼 4 처리 : BW
			//
			if(this->m_pQuestProto->m_index == 105)
			{
				if(( pNPC->m_proto->m_index == 210
						|| pNPC->m_proto->m_index == 211
						|| pNPC->m_proto->m_index == 212
						|| pNPC->m_proto->m_index == 213
						|| pNPC->m_proto->m_index == 214 ) && DEAD(pNPC) )
				{
					IncreaseQuestValue(0);
					// 랭킹 디비 마리수 업데이트
				}

				if(m_pQuestProto->m_conditionNum[0] <= GetQuestValue(0))
				{
					for(i = 0; i < QUEST_MAX_CONDITION; i++)
						bComplete[i] = true;

					// 랭킹 디비 클리어/ 시간 업데이트
				}

				break;
			}

			for (i=0; i < QUEST_MAX_CONDITION; i++)
			{
				if (m_pQuestProto->m_conditionType[i] == -1)
				{
					bComplete[i] = true;
					continue;
				}

				switch (m_pQuestProto->m_conditionType[i])
				{
				case QCONDITION_NPC:
					{
						// 공격하는 몹이 싱글던전 완료조건 몹의 인덱스와 같고 죽었으면
						if (m_pQuestProto->m_conditionIndex[i] == pNPC->m_proto->m_index && DEAD(pNPC))
						{
							bComplete[i] = true;
							IncreaseQuestValue(i);
//#ifdef GER_LOG
//							GAMELOGGEM << init( 0, "CHAR_QUEST_FINISHED")
//								<< LOG_VAL("Quest.cpp",":643") << blank
//							<< LOG_VAL("account-id", pPC->m_desc->m_idname ) << blank
//							<< LOG_VAL("character-id", pPC->m_desc->m_pChar->m_name ) << blank
//							<< LOG_VAL("quest-id", GetQuestIndex() ) << blank
//							<< LOG_VAL("zone-id", pPC->m_desc->m_pChar->m_pZone->m_index ) << blank
//							<< LOG_VAL("End-type", GetQuestProto()->m_prizeNPC ) << blank
//							<< LOG_VAL("npc-id", GetPrizeNPCIndex() ) << blank
//							<< LOG_VAL("item-id", GetQuestProto()->m_prizeIndex[i] ) << blank
//							<< LOG_VAL("amount", GetQuestProto()->m_prizeData[i] ) << blank
//							<< endGer;
//#endif //GER_LOG
						}
					}
					break;
				}
			}
		}
		break;

	default:
		return;
		break;
	}

	CheckComplete(pPC);

	// bComplete가 모두 true로 셋팅 되있어야 ㅇㅋ
	for (i=0; i < QUEST_MAX_CONDITION; i++)
	{
		if (!bComplete[i])
			return;
	}

	///////////////////////////////////
	// pd4 퀘스트이면 helper end : BW
	// MSG_HELPER_PD4_RANK_END,			// pd4 종료			 : charIndex(n) deadmonNum(n) bclear(c)
	// char index를 보냄
	if(this->m_pQuestProto->m_index == 105)
	{
		GAMELOG << init("PD4 END", pPC)
				<< GetQuestValue(0) << end;

		if (gserver->isRunHelper())
		{
			CNetMsg::SP rmsg(new CNetMsg);
			rmsg->Init(MSG_HELPER_COMMAND);
			RefMsg(rmsg) << MSG_HELPER_PD4_RANK_END
						 << pPC->m_index
						 << GetQuestValue(0)
						 << (char) 1;
			SEND_Q(rmsg, gserver->m_helper);
		}
		else
		{
			GAMELOG << init("PD4 QUEST ERROR : CANNOT FIND HELPER")
					<< pPC->m_index << end;

			return;
		}
	}

	// Complete Msg 최초전송인경우에만 전송
	if (!IsCompleted())
	{
		if(GetComplete2())
		{
			// Quest Complete Log
			GAMELOG << init("QUEST COMPLETE (QuestUpdateData)", pPC)
					<< m_pQuestProto->m_index
					<< end;
//#ifdef GER_LOG
//			for( int rewardItemCount = 0 ; rewardItemCount < 5 ; rewardItemCount++ )
//			{
//				GAMELOGGEM << init( 0, "CHAR_QUEST_FINISHED")
//					<< LOG_VAL("Quest.cpp",":723") << blank
//					<< LOG_VAL("account-id", pPC->m_desc->m_idname ) << blank
//					<< LOG_VAL("character-id", pPC->m_desc->m_pChar->m_name ) << blank
//					<< LOG_VAL("quest-id", GetQuestIndex() ) << blank
//					<< LOG_VAL("zone-id", pPC->m_desc->m_pChar->m_pZone->m_index ) << blank
//					<< LOG_VAL("End-type", GetQuestProto()->m_prizeNPC ) << blank
//					<< LOG_VAL("npc-id", GetPrizeNPCIndex() ) << blank
//					<< LOG_VAL("item-id", GetQuestProto()->m_prizeIndex[rewardItemCount] ) << blank
//					<< LOG_VAL("amount", GetQuestProto()->m_prizeData[rewardItemCount] ) << blank
//					<< endGer;
//			}
//#endif //GER_LOG
			// 완료 메시지
			CNetMsg::SP rmsg(new CNetMsg);
			QuestCompleteMsg(rmsg, this);
			SEND_Q(rmsg, pPC->m_desc);
		}
		SetComplete1(true);
	}
}

void CQuest::QuestUpdateData( CPC* pPC, CPC* tPC )
{
	int i, j;

	if (IsCompleted())
		return ;

	// 조건 검사 하면서 만족하는 조건만 true로 셋팅
	bool bComplete[QUEST_MAX_CONDITION];
	memset(bComplete, 0, sizeof(bComplete));

	switch (GetQuestType0())
	{
	// 반복 퀘스트
	case QTYPE_KIND_REPEAT:
		{
			for (i=0; i < QUEST_MAX_CONDITION; i++)
			{
				if (m_pQuestProto->m_conditionType[i] == -1)
				{
					bComplete[i] = true;
					continue;
				}

				switch (m_pQuestProto->m_conditionType[i])
				{
				case QCONDITION_PC:
					{
						if( m_pQuestProto->m_needRvRType > 0 && m_pQuestProto->m_needRvRType == tPC->getSyndicateType())
						{
							if(m_pQuestProto->m_needRvRGrade == 0)
							{
								if(m_pQuestProto->m_needRvRGrade > tPC->m_syndicateManager.getSyndicateGrade(tPC->getSyndicateType()))
									continue;
							}
							else
							{
								if(m_pQuestProto->m_needRvRGrade != tPC->m_syndicateManager.getSyndicateGrade(tPC->getSyndicateType()))
									continue;
							}
						}

						if (GetQuestValue(i) < m_pQuestProto->m_conditionNum[i])
						{
							bComplete[i] = false;
							IncreaseQuestValue(i);

							CNetMsg::SP rmsg(new CNetMsg);
							QuestStatusMsg(rmsg, this);
							SEND_Q(rmsg, pPC->m_desc);
						}
						// 같으면 bComplete true 셋팅
						if (GetQuestValue(i) == m_pQuestProto->m_conditionNum[i])
						{
							bComplete[i] = true;
							continue;
						}
						else if (GetQuestValue(i) < m_pQuestProto->m_conditionNum[i])
							bComplete[i] = false;
						else
							continue;
					}
					break;
				}
			}
		}
		break;
	default:
		return;
		break;
	}

	CheckComplete(pPC);

	// bComplete가 모두 true로 셋팅 되있어야 ㅇㅋ
	for (i=0; i < QUEST_MAX_CONDITION; i++)
	{
		if (!bComplete[i])
			return;
	}

	// Complete Msg 최초전송인경우에만 전송
	if (!IsCompleted())
	{
		if(GetComplete2())
		{
			// Quest Complete Log
			GAMELOG << init("QUEST COMPLETE (QuestUpdateData)", pPC)
					<< m_pQuestProto->m_index
					<< end;
			CNetMsg::SP rmsg(new CNetMsg);
			QuestCompleteMsg(rmsg, this);
			SEND_Q(rmsg, pPC->m_desc);
		}
		SetComplete1(true);
	}
}

void CQuest::RemoeQuestItem(CPC* pc)
{
	for (int k = 0; k < QUEST_MAX_CONDITION; k++)
	{
		// 수행조건 아이템을 찾고
		if (m_pQuestProto->m_conditionType[k] != QCONDITION_ITEM)
			continue;

		item_search_t vec;
		int search_count = pc->m_inventory.searchItemByCondition(m_pQuestProto->m_conditionIndex[k], 0, 0, vec);
		if (search_count == 0 || search_count < m_pQuestProto->m_conditionNum[k])
			continue ;

		pc->m_inventory.deleteItem(vec, m_pQuestProto->m_conditionNum[k]);
	}
}

///////////////////
// class CQuestList
CQuestList::CQuestList()
{
	m_head = NULL;
	m_nCountRun = 0;
	m_nCountDone = 0;
	m_nCountAbandon = 0;
	m_nCountComplete = 0;
}

CQuestList::~CQuestList()
{
	clear();
}

CQuest* CQuestList::AddQuest(int nQuestIndex)
{
	const CQuestProto* pQuestProto = gserver->m_questProtoList.FindProto(nQuestIndex);
	if (pQuestProto == NULL)
		return NULL;
	CQuest* pQuest = new CQuest(pQuestProto);
	pQuest->SetNextQuest(m_head);
	if (m_head)
		m_head->SetPrevQuest(pQuest);
	m_head = pQuest;
	return pQuest;
}

void CQuestList::DelQuest(CPC* pPC, int questIndex)
{
	CQuest* pDelQuest;
	CQuest* pDelQuestNext = GetNextQuest(NULL, QUEST_STATE_ALL);
	while ((pDelQuest = pDelQuestNext))
	{
		pDelQuestNext = GetNextQuest(pDelQuestNext, QUEST_STATE_ALL);
		if (pDelQuest->m_pQuestProto->m_index == questIndex)
		{
			CQuest* pPrevQuest = pDelQuest->GetPrevQuest();
			CQuest* pNextQuest = pDelQuest->GetNextQuest();
			if (pPrevQuest)
				pPrevQuest->SetNextQuest(pNextQuest);
			if (pNextQuest)
				pNextQuest->SetPrevQuest(pPrevQuest);
			if (pDelQuest == m_head)
				m_head = m_head->GetNextQuest();

			if(pDelQuest->GetQuestState() == QUEST_STATE_RUN)
				m_nCountRun--;
			else if(pDelQuest->GetQuestState() == QUEST_STATE_DONE)
				m_nCountDone--;
			else if(pDelQuest->GetQuestState() == QUEST_STATE_ABANDON)
				m_nCountAbandon--;
			return;
		}
	}
}

bool CQuestList::DelQuest(CPC* pPC, CQuest* pQuest, char cQuestState)
{
	CQuest* pDelQuest;
	CQuest* pDelQuestNext = GetNextQuest(NULL, cQuestState);
	while ((pDelQuest = pDelQuestNext))
	{
		pDelQuestNext = GetNextQuest(pDelQuestNext, cQuestState);
		if (pDelQuest == pQuest)
		{
			CQuest* pPrevQuest = pDelQuest->GetPrevQuest();
			CQuest* pNextQuest = pDelQuest->GetNextQuest();
			if (pPrevQuest)
				pPrevQuest->SetNextQuest(pNextQuest);
			if (pNextQuest)
				pNextQuest->SetPrevQuest(pPrevQuest);
			if (pDelQuest == m_head)
				m_head = m_head->GetNextQuest();

			if(cQuestState == QUEST_STATE_RUN)
				m_nCountRun--;
			else if(cQuestState == QUEST_STATE_DONE)
				m_nCountDone--;
			else if(cQuestState == QUEST_STATE_ABANDON)
				m_nCountAbandon--;
			return true;
		}
	}
	return false;
}

void CQuestList::DelQuestALL(CPC* pPC, char cQuestState)
{
	CQuest* pDelQuest;
	CQuest* pDelQuestNext = GetNextQuest(NULL, cQuestState);
	while ((pDelQuest = pDelQuestNext))
	{
		pDelQuestNext = GetNextQuest(pDelQuestNext, cQuestState);
		CQuest* pPrevQuest = pDelQuest->GetPrevQuest();
		CQuest* pNextQuest = pDelQuest->GetNextQuest();
		if (pPrevQuest)
			pPrevQuest->SetNextQuest(pNextQuest);
		if (pNextQuest)
			pNextQuest->SetPrevQuest(pPrevQuest);
		if (pDelQuest == m_head)
			m_head = m_head->GetNextQuest();

		if(cQuestState == QUEST_STATE_RUN)
			m_nCountRun--;
		else if(cQuestState == QUEST_STATE_DONE)
			m_nCountDone--;
		else if(cQuestState == QUEST_STATE_ABANDON)
			m_nCountAbandon--;
	}
}

CQuest* CQuestList::FindQuest(int nQuestIndex)
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL, QUEST_STATE_RUN);
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext, QUEST_STATE_RUN);
		if (pFindQuest->GetQuestIndex() == nQuestIndex)
			return pFindQuest;
	}
	return NULL;
}

bool CQuestList::FindQuest(int nQuestIndex, char cQuestState )
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL, cQuestState );
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext, cQuestState );
		if (pFindQuest->GetQuestIndex() == nQuestIndex)
			return true;
	}
	return false;
}

CQuest* CQuestList::FindQuestByItem(int nitemIndex)
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL, QUEST_STATE_RUN);
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext, QUEST_STATE_RUN);
		for(int i=0; i<QUEST_MAX_CONDITION; i++)
		{
			if (pFindQuest->GetQuestProto()->m_conditionType[i] == QCONDITION_ITEM_USE )
				if(pFindQuest->GetQuestProto()->m_conditionIndex[i] == nitemIndex)
					return pFindQuest;
		}
	}
	return NULL;
}

CQuest* CQuestList::FindQuestByMob(int nMobIndex)
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL, QUEST_STATE_RUN);
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext, QUEST_STATE_RUN);
		for(int i=0; i<QUEST_MAX_CONDITION; i++)
		{
			if (pFindQuest->GetQuestProto()->m_conditionType[i] == QCONDITION_NPC )
				if(pFindQuest->GetQuestProto()->m_conditionIndex[i] == nMobIndex)
					return pFindQuest;
		}
	}
	return NULL;
}

//  [2/23/2007 KwonYongDae]
// 퀘스트 타입 0 이 진행중 이면 true
bool CQuestList::IsQuestType0( int qType0 )
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL, QUEST_STATE_RUN);
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext, QUEST_STATE_RUN);
		if ( pFindQuest->GetQuestType0() == qType0 && !pFindQuest->IsCompleted() )
			return true;
	}
	return false;
}

void CQuestList::SetQuestState(CQuest* pQuest, char cQuestState)
{
	CQuest* pFindQuest;
	CQuest* pFindQuestNext = GetNextQuest(NULL);
	while ((pFindQuest = pFindQuestNext))
	{
		pFindQuestNext = GetNextQuest(pFindQuestNext);
		if (pFindQuest == pQuest)
		{
			switch (pFindQuest->GetQuestState())
			{
			case QUEST_STATE_RUN:
				m_nCountRun--;
				break;
			case QUEST_STATE_DONE:
				m_nCountDone--;
				break;
			case QUEST_STATE_ABANDON:
				m_nCountAbandon--;
				break;
			default:
				break;
			}
			pFindQuest->SetQuestState(cQuestState);
			switch (pFindQuest->GetQuestState())
			{
			case QUEST_STATE_RUN:
				m_nCountRun++;
				break;
			case QUEST_STATE_DONE:
				m_nCountDone++;
				break;
			case QUEST_STATE_ABANDON:
				m_nCountAbandon++;
				break;
			default:
				break;
			}
			return ;
		}
	}
}

CQuest* CQuestList::GetNextQuest(CQuest* pCurrentQuest, char cQuestState)
{
	if (pCurrentQuest == NULL)
		pCurrentQuest = m_head;
	else
		pCurrentQuest = pCurrentQuest->GetNextQuest();
	while (pCurrentQuest)
	{
		if (cQuestState == QUEST_STATE_ALL || pCurrentQuest->GetQuestState() == cQuestState)
			return pCurrentQuest;
		pCurrentQuest = pCurrentQuest->GetNextQuest();
	}
	return NULL;
}

void CQuestList::CheckComplete(CPC* pc)
{
	CQuest* pQuestNext;
	CQuest* pQuest;
	pQuestNext = GetNextQuest(NULL, QUEST_STATE_RUN);
	while( (pQuest = pQuestNext) )
	{
		pQuestNext = GetNextQuest(pQuestNext, QUEST_STATE_RUN);
		pQuest->CheckComplete(pc);
	}
}

void CQuestList::clear()
{
	while (m_head)
	{
		CQuest*		pQuest = m_head;
		m_head = m_head->GetNextQuest();
		delete pQuest;
	}
	m_nCountRun = 0;
	m_nCountDone = 0;
	m_nCountAbandon = 0;
	m_nCountComplete = 0;
}

bool CQuestList::isRvrQuest(CPC* pc, int questIndex)
{
	if (questIndex == 682)
	{
		// 해당 퀘스트를 가지고 있거나 해당 퀘스트를 완료했거나
		// 683 퀘스트를 완료 했거나
		if (FindQuest(questIndex, QUEST_STATE_DONE) || FindQuest(questIndex))
			return true;
		else if (FindQuest(683, QUEST_STATE_DONE) || FindQuest(683))
			return true;
	}
	else if (questIndex == 683)
	{
		// 해당 퀘스트를 가지고 있거나 해당 퀘스트를 완료했거나
		// 682 퀘스틀 완료했거나 가지고 있거나
		if (FindQuest(questIndex, QUEST_STATE_DONE) || FindQuest(questIndex))
			return true;
		else if (FindQuest(682, QUEST_STATE_DONE) || FindQuest(682))
			return true;
	}
	return false;
}

void CQuest::QuestUpdateDataForParty(CPC* pPC, CNPC* pNPC)
{
	if( GetPartyScale() == QTYPE_SCALE_PARTY && pPC->IsParty() )
	{
		int i;
		const CPartyMember* pPartyMember;
		CPC* pPartyPC;
		CQuest* quest;
		for(i = 0; i <MAX_PARTY_MEMBER; ++i)
		{
			pPartyMember = pPC->m_party->GetMemberByListIndex(i);
			if(pPartyMember && pPartyMember->GetMemberPCPtr())
			{
				pPartyPC = pPartyMember->GetMemberPCPtr();

				if(pPC->m_pArea->FindCharInCell(pPC, pPartyPC->m_index, MSG_CHAR_PC))
				{
					quest = pPartyPC->m_questList.FindQuest(GetQuestIndex());
					if(quest && quest->GetQuestState() == QUEST_STATE_RUN)
						quest->QuestUpdateData(pPartyPC, pNPC);
				}
			}
		}
	}
#ifdef _BATTLEGROUP_QUEST_BUG_PIX
	else if( GetPartyScale() == QTYPE_SCALE_BATTLEGROUP && pPC->IsExped() )
	{
		int i,j;
		CPC* pExpedPC;
		CQuest* quest;

		for (i=0; i < MAX_EXPED_GROUP; i++)
		{
			for (j=0; j < MAX_EXPED_GMEMBER; j++)
			{
				pExpedPC = pPC->m_Exped->GetMemberPCPtr(i,j);
				if (pExpedPC == NULL)
					continue;

				if(pPC->m_pArea->FindCharInCell(pPC, pExpedPC->m_index, MSG_CHAR_PC))
				{
					quest = pExpedPC->m_questList.FindQuest(GetQuestIndex());
					if(quest && quest->GetQuestState() == QUEST_STATE_RUN)
						quest->QuestUpdateData(pExpedPC, pNPC);
				}
			}
		}
	}
#endif
	else
		QuestUpdateData(pPC, pNPC);
}

void CQuest::QuestUpdateDataForParty(CPC* pPC, CNPC* pNPC, int questIndex)
{
}

bool CQuest::CheckComplete(CPC * pc)
{
	int i;

	switch ( GetQuestType0() )
	{
	case QTYPE_KIND_REPEAT:
	case QTYPE_KIND_COLLECTION:
	case QTYPE_KIND_MINING_EXPERIENCE:
	case QTYPE_KIND_GATHERING_EXPERIENCE:
	case QTYPE_KIND_CHARGE_EXPERIENCE:
	case QTYPE_KIND_PROCESS_EXPERIENCE :		//  [2/22/2007 KwonYongDae] QuestCheck
	case QTYPE_KIND_MAKE_EXPERIENCE :
		{
			bool complete = true;
			bool complete2 = true;

			for ( i=0; i<QUEST_MAX_CONDITION; i++)
			{
				if (GetQuestProto()->m_conditionType[i] != QCONDITION_ITEM_NORMAL)
					continue;

				if (GetQuestValue(i) >= GetQuestProto()->m_conditionNum[i])
					continue;

				complete2 = false;
				break;
			}

			for (i=0; i<QUEST_MAX_CONDITION; i++)
			{
				//if (pQuestProto->m_conditionType[j] != QCONDITION_ITEM)
				if (GetQuestProto()->m_conditionType[i] == -1 || GetQuestProto()->m_conditionType[i] == QCONDITION_ITEM_NORMAL)
					continue;

				if (GetQuestValue(i) >= GetQuestProto()->m_conditionNum[i])
					continue;

				complete = false;
				break;
			}

//- 이것 때문에 두번째 퀘스트 조건이 완료 되지 않아도 퀘스트가 완료된 처리르 한다.
			if(complete2)
			{
				SetComplete2(true);
			}

			if (complete)
			{
				if(complete2)
				{
					CNetMsg::SP rmsg(new CNetMsg);
					QuestCompleteMsg(rmsg, this);
					SEND_Q(rmsg, pc->m_desc);
				}
				SetComplete1(true);
			}
			else
				SetComplete1(false);
		}
		break;

	case QTYPE_KIND_DELIVERY:
		{
			bool bcomplete = true;

			if(  GetQuestProto()->m_index == 370 )
			{
				if(pc->m_teachIdx[0] > 0)
				{
					bool bcomplete = true;
				}
				else
					break;
			}

			for ( i = 0; i< QUEST_MAX_CONDITION; i++)
			{
				if (GetQuestProto()->m_conditionType[i] == QCONDITION_ITEM )
				{
					item_search_t vec;
					int search_count = pc->m_inventory.searchItemByCondition(GetQuestProto()->m_conditionIndex[i], 0, 0, vec);
					if (search_count == 0 || search_count < GetQuestProto()->m_conditionNum[i])
					{
						bcomplete = false;
						break;
					}
				}
			}

#ifdef QUEST_EXTEND_TH
			if(bcomplete)
			{
				SetComplete(0, true);
				SetComplete(1, true);

				CNetMsg::SP rmsg(new CNetMsg);
				QuestCompleteMsg(rmsg, this);
				SEND_Q(rmsg, pc->m_desc);
			}
#else
			if(bcomplete)
			{
				SetComplete1(true);
				SetComplete2(true);

				CNetMsg::SP rmsg(new CNetMsg);
				QuestCompleteMsg(rmsg, this);
				SEND_Q(rmsg, pc->m_desc);
			}
#endif
		}
		break;

	case QTYPE_KIND_DEFEAT :
	case QTYPE_KIND_SAVE :
		{
			bool complete = true;
			for ( i=0; i < QUEST_MAX_CONDITION; i++)
			{
				if (GetQuestProto()->m_conditionType[i] != QCONDITION_ITEM && GetQuestProto()->m_conditionType[i] != QCONDITION_NPC)
					continue;

				if (GetQuestValue(i) >= GetQuestProto()->m_conditionNum[i])
					continue;

				complete = false;
				break;
			}

			if(complete)
			{
#ifdef QUEST_EXTEND_TH
				SetComplete(0, true);			//싱글던전 퀘스트이므로..
				SetComplete(1, true);
#else
				SetComplete1(true);
				SetComplete2(true);
#endif
				CNetMsg::SP rmsg(new CNetMsg);
				QuestCompleteMsg(rmsg, this);
				SEND_Q(rmsg, pc->m_desc);
			}
		}
		break;
	case QTYPE_KIND_SEARCH: // 탐색 퀘스트 (특정 위치까지 갔다오는 ...)
		{
			bool complete = true;

			for (i = 0; i < QUEST_MAX_CONDITION; i++)
			{
				if (GetQuestProto()->m_conditionType[i] == -1 )
					continue;

				if (GetQuestProto()->m_conditionType[i] != QCONDITION_AREA)
				{
					complete =false;
					break;
				}

				if(GetQuestValue(i) >= GetQuestProto()->m_conditionNum[i])
					continue;
				else
				{
					complete = false;
					break;
				}
			}

			if(complete)
			{
#ifdef QUEST_EXTEND_TH
				SetComplete(0, true);
				SetComplete(1, true);
#else
				SetComplete1(true);
				SetComplete2(true);
#endif
				CNetMsg::SP rmsg(new CNetMsg);
				QuestCompleteMsg(rmsg, this);
				SEND_Q(rmsg, pc->m_desc);
			}
		}

	default:
		{
			bool complete	= true;
			bool complete2	= true;
			bool complete3	= true;

			if( GetQuestProto()->m_conditionType[0] != -1 )
			{
				if( GetQuestValue(0) < GetQuestProto()->m_conditionNum[0] )
					complete = false;
			}

			if( GetQuestProto()->m_conditionType[1] != -1 )
			{
				if( GetQuestValue(1) < GetQuestProto()->m_conditionNum[1] )
					complete2 = false;
			}

			if( GetQuestProto()->m_conditionType[2] != -1 )
			{
				if( GetQuestValue(2) < GetQuestProto()->m_conditionNum[2] )
					complete2 = false;
			}

			if( complete && complete2 && complete3 )
			{
				SetComplete1(true);
				SetComplete2(true);

				CNetMsg::SP rmsg(new CNetMsg);
				QuestCompleteMsg(rmsg, this);
				SEND_Q(rmsg, pc->m_desc);
			}
		}
		break;
	}
	return false;
}

max_stars_repo_name: openlastchaos/lastchaos-source-server

max_issues_repo_name: openlastchaos/lastchaos-source-server

max_forks_repo_name: openlastchaos/lastchaos-source-server


text:
#include <curl/curl.h>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find_iterator.hpp>

#include <elle/Exception.hh>
#include <elle/log.hh>
#include <elle/print.hh>
#include <elle/reactor/http/RequestImpl.hh>
#include <elle/reactor/http/Service.hh>
#include <elle/reactor/http/exceptions.hh>
#include <elle/reactor/scheduler.hh>
#include <utility>

ELLE_LOG_COMPONENT("elle.reactor.http.Request");

namespace elle
{
  namespace reactor
  {
    namespace http
    {
      /*--------.
      | Helpers |
      `--------*/
      namespace
      {
        template <typename Value>
        void
        setopt(CURL* handle, CURLoption option, Value parameter)
        {
          auto res = curl_easy_setopt(handle, option, parameter);
          if (res != CURLE_OK)
            throw RequestError("unable to set request option: %s",
                               curl_easy_strerror(res));
        }
      }

      /*--------------.
      | Configuration |
      `--------------*/

      Request::Configuration::Configuration(
        DurationOpt timeout,
        DurationOpt stall_timeout,
        Version version,
        bool keep_alive,
        boost::optional<Configuration::Proxy> proxy)
        : _version(version)
        , _keep_alive(keep_alive)
        , _proxy(std::move(proxy))
        , _timeout(std::move(timeout))
        , _stall_timeout(std::move(stall_timeout))
        , _headers()
          // XXX: not supported by wsgiref and <=nginx-1.2 ...
        , _chunked_transfers(false)
        , _expected_status()
        , _ssl_verify_host(true)
      {}

      Request::Configuration::~Configuration()
      = default;

      void
      Request::Configuration::header_add(std::string const& header,
                                         std::string const& content)
      {
        this->_headers.emplace(header, content);
      }

      void
      Request::Configuration::header_remove(std::string const& header)
      {
        this->_headers.erase(header);
      }

      /*---------------.
      | Implementation |
      `---------------*/

      Request::Impl::Impl(Request& request,
                          std::string const& url,
                          Method method,
                          Configuration conf)
        : _request(&request)
        , _conf(std::move(conf))
        , _headers(nullptr, &curl_slist_free_all)
        , _progress_changed()
        , _input_done(false)
        , _input()
        , _input_current()
        , _input_available("input available")
        , _output_done(false)
        , _output(0)
        , _output_available(false)
        , _output_offset(0)
        , _curl(boost::asio::use_service<Service>(
                  reactor::scheduler().io_service()))
        , _url(url)
        , _method(method)
        , _query_string()
        , _handle(curl_easy_init())
        , _pause_count(0)
        , _debug(0)
        , _debug2(0)
        , _bt_frozen()
        , _bt_unfrozen()
        , _bt_unfrozen_reason()
        , _bt_waited()
        , _slot_frozen()
        , _slot_unfrozen()
      {
        if (!this->_handle)
          throw RequestError(url, "unable to initialize request");
        // Weird clang macos bug, using 'this->_error' causes a SEGV for
        // some offset of the _error in the class.
        memset(&this->_error[0], 0, CURL_ERROR_SIZE);
        setopt(this->_handle, CURLOPT_ERRORBUFFER, this->_error);
        // Set version.
        auto version = this->_conf.version() == Version::v11
          ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0;
        setopt(this->_handle, CURLOPT_HTTP_VERSION, version);
        // Set IPv4 only.
        setopt(this->_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        // Set proxy.
        using ProxyType = reactor::network::ProxyType;
        if (this->_conf.proxy()
            && this->_conf.proxy().get().type() != ProxyType::None
            && !this->_conf.proxy().get().host().empty()
            && this->_conf.proxy().get().port() != 0)
        {
          auto proxy = this->_conf.proxy().get();
          setopt(this->_handle, CURLOPT_PROXY, proxy.host().c_str());
          setopt(this->_handle, CURLOPT_PROXYPORT, proxy.port());
          // curl expects a long for the proxy type.
          long proxy_type = [&]{
            switch (proxy.type())
            {
              case ProxyType::None:
                ELLE_ERR("{}: cannot set proxy with type None", this);
                elle::unreachable();
              case ProxyType::HTTP:
                return CURLPROXY_HTTP;
              // HTTPS is still an HTTP proxy but on port 443.
              case ProxyType::HTTPS:
                return CURLPROXY_HTTP;
              case ProxyType::SOCKS:
                return CURLPROXY_SOCKS5;
            }
            elle::unreachable();
          }();
          setopt(this->_handle, CURLOPT_PROXYTYPE, proxy_type);
          if (!proxy.username().empty())
            setopt(this->_handle,
                   CURLOPT_PROXYUSERNAME, proxy.username().c_str());
          if (!proxy.password().empty())
            setopt(this->_handle,
                   CURLOPT_PROXYPASSWORD, proxy.password().c_str());
          setopt(this->_handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
        }
        // Set timeout.
        auto const& timeout = this->_conf.timeout();
        auto const timeout_seconds
          = timeout ? elle::num_seconds(std::max(elle::Duration{1s}, *timeout))
          : 0;
        setopt(this->_handle, CURLOPT_TIMEOUT, timeout_seconds);
        // Set stall timeout
        if (auto const& stall_timeout = this->_conf.stall_timeout())
        {
          // Timeout if bandwith is below 1 byte/second for given duration.
          // Note: CURL seems to wait for the test to fail some amount of
          // successive times to actually abort the operation (observed: 3, 6).
          auto const t = (long)elle::num_seconds(std::max(elle::Duration{1s},
                                                          *stall_timeout));
          setopt(this->_handle, CURLOPT_LOW_SPEED_TIME, t);
          setopt(this->_handle, CURLOPT_LOW_SPEED_LIMIT, 1L);
        }
        // Set SSL options.
        if (!this->_conf.ssl_verify_host())
          setopt(this->_handle, CURLOPT_SSL_VERIFYHOST, 0);
        // Set method.
        switch (this->_method)
        {
        case Method::DELETE:
          setopt(this->_handle, CURLOPT_CUSTOMREQUEST, "DELETE");
          break;
        case Method::GET:
          setopt(this->_handle, CURLOPT_HTTPGET, 1);
          break;
        case Method::HEAD:
          setopt(this->_handle, CURLOPT_CUSTOMREQUEST, "HEAD");
          break;
        case Method::OPTIONS:
          setopt(this->_handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
        case Method::POST:
          setopt(this->_handle, CURLOPT_POST, 1);
          break;
        case Method::PUT:
          setopt(this->_handle, CURLOPT_UPLOAD, 1);
          break;
        }
        // Set socket callbacks.
        setopt(this->_handle, CURLOPT_OPENSOCKETFUNCTION, &Impl::open_socket);
        setopt(this->_handle, CURLOPT_OPENSOCKETDATA, this);
        setopt(this->_handle, CURLOPT_CLOSESOCKETFUNCTION, &Impl::close_socket);
        setopt(this->_handle, CURLOPT_CLOSESOCKETDATA, &this->_curl);
        // Set input / output callbacks.
        setopt(this->_handle, CURLOPT_WRITEFUNCTION, &Impl::write_callback);
        setopt(this->_handle, CURLOPT_WRITEDATA, this);
        setopt(this->_handle, CURLOPT_READFUNCTION, &Impl::read_callback);
        setopt(this->_handle, CURLOPT_READDATA, this);
        // Set header callbacks
        setopt(this->_handle, CURLOPT_HEADERFUNCTION, &Impl::header_callback);
        setopt(this->_handle, CURLOPT_WRITEHEADER, this);
        // Progress callback
        setopt(this->_handle, CURLOPT_NOPROGRESS, 0);
        setopt(this->_handle, CURLOPT_XFERINFOFUNCTION,
               &Impl::progress_callback);
        setopt(this->_handle, CURLOPT_XFERINFODATA, this);
        // XXX: Don't check SSL peer until we find a solution for managing
        // trusted CAs.
        // http://bugs.python.org/issue17128
        setopt(this->_handle, CURLOPT_SSL_VERIFYPEER, 0L);
        // Accept all forms of compression that we support.
        setopt(this->_handle, CURLOPT_ACCEPT_ENCODING, "");
        if (this->_conf.keep_alive())
          this->header_add("Connection", "keep-alive");
      }

      Request::Impl::~Impl()
      {
        this->_slot_frozen.disconnect();
        this->_slot_unfrozen.disconnect();
        this->_request->_status = static_cast<StatusCode>(0);
        ELLE_TRACE_SCOPE("%s: terminate", *this->_request);
        if (this->_curl._requests.find(this->_handle) !=
            this->_curl._requests.end())
          this->_curl.remove(*this->_request);
        curl_easy_cleanup(this->_handle);
      }

      std::unordered_map<std::string, std::string>
      Request::Impl::cookies(CURL* handle)
      {
        auto cookies = std::unordered_map<std::string, std::string>{};
        struct curl_slist* cookies_list = nullptr;
        CURLcode res = curl_easy_getinfo(handle,
                                         CURLINFO_COOKIELIST,
                                         &cookies_list);
        if (res != CURLE_OK)
          throw elle::Exception(elle::print("retrieval of cookies failed: %s",
                                            curl_easy_strerror(res)));
        for (curl_slist* it = cookies_list; it; it = it->next)
        {
          auto chunks = std::vector<std::string>{};
          boost::algorithm::split(chunks, it->data,
                                  boost::algorithm::is_any_of("\t"));
          auto name = chunks[chunks.size() - 2];
          auto value = chunks[chunks.size() - 1];
          cookies[name] = value;
        }
        curl_slist_free_all(cookies_list);
        return cookies;
      }

      std::unordered_map<std::string, std::string>
      Request::Impl::cookies() const
      {
        return this->cookies(this->_handle);
      }

      void
      Request::Impl::cookie_add(std::string const& name,
                                std::string const& value)
      {
        static auto const fmt = boost::format("Set-Cookie: %s=%s; path=/;");
        auto line = str(boost::format(fmt) % name % value);
        auto res = curl_easy_setopt(this->_handle,
                                    CURLOPT_COOKIELIST, line.c_str());
        if (res != CURLE_OK)
          throw elle::Exception(elle::print("failed to set cookie: %s",
                                            curl_easy_strerror(res)));
      }

      void
      Request::Impl::start()
      {
        // Set URL.
        if (!this->_query_string.empty())
          this->_url = elle::print("%s?%s", this->_url, this->_query_string);
        setopt(this->_handle, CURLOPT_URL, this->_url.c_str());
        for (auto const& cookie: this->_conf.cookies())
          this->cookie_add(cookie.first, cookie.second);
        for (auto const& header: this->_conf.headers())
          this->header_add(header.first, header.second);
        setopt(this->_handle, CURLOPT_HTTPHEADER, this->_headers.get());
        this->_curl.add(*this->_request);
      }

      /*--------.
      | Headers |
      `--------*/

      void
      Request::Impl::header_add(std::string const& header,
                                std::string const& content)
      {
        ELLE_DEBUG("%s: add header %s: %s", *this, header, content);
        auto line = elle::print("%s: %s", header, content);
        this->_headers.reset(curl_slist_append(this->_headers.release(),
                                               line.c_str()));
      }

      void
      Request::Impl::header_remove(std::string const& header)
      {
        ELLE_DEBUG("%s: remove header %s", *this, header);
        auto line = elle::print("%s:", header);
        this->_headers.reset(curl_slist_append(this->_headers.release(),
                                               line.c_str()));
      }

      size_t
      Request::Impl::header_callback(void *ptr,
                                     size_t chunks,
                                     size_t count,
                                     void* userdata)
      {
        auto& self = *reinterpret_cast<Request::Impl*>(userdata);
        auto size = chunks * count;
        self.read_header(elle::WeakBuffer(ptr, size));
        return size;
      }

      void
      Request::Impl::read_header(elle::ConstWeakBuffer const& data)
      {
        auto separator =
          boost::algorithm::find_first(data, elle::ConstWeakBuffer(":"));
        if (separator.begin() != data.end())
          this->_request->_headers.emplace(
              std::string(data.begin(), separator.begin()),
              boost::algorithm::trim_copy(
                std::string(separator.end(), data.end())));
      }

      /*-------.
      | Socket |
      `-------*/

      int
      Request::Impl::open_socket(void* data,
                                 curlsocktype purpose,
                                 struct curl_sockaddr *address)
      {
        auto& self = *reinterpret_cast<Request::Impl*>(data);
        if (purpose == CURLSOCKTYPE_IPCXN)
        {
          if (address->family != AF_INET && address->family != AF_INET6)
            return CURL_SOCKET_BAD;
          auto proto = address->family == AF_INET ?
            boost::asio::ip::tcp::v4(): boost::asio::ip::tcp::v6();
          auto& service = self._curl.get_io_service();
          auto socket = std::make_shared<Service::Socket>(service, proto);
          auto fd = socket->native_handle();
          ELLE_TRACE_SCOPE("%s: open socket %s for %s", self._curl, fd, self);
          Service::Socket::_sockets.emplace(fd, socket);
          ELLE_ASSERT_NCONTAINS(self._curl._sockets, fd);
          self._curl._sockets.emplace(fd, socket);
          return fd;
        }
        else
          return CURL_SOCKET_BAD;
      }

      int
      Request::Impl::close_socket(void* data, curl_socket_t fd)
      {
        // Beware, curl_multi keeps reference to the socket and destroy it
        // *after* the Request and its easy handle have been disposed of. The
        // request is thus invalid in this concept, hence the use of a map in
        // the Service to hold sockets. It seems that Curl does this to reuse
        // sockets between requests in some cases.
        auto& service = *reinterpret_cast<Service*>(data);
        ELLE_TRACE_SCOPE("%s: close socket %s", service, fd);
        ELLE_ASSERT_CONTAINS(service._sockets, fd);
        ELLE_ENFORCE(service._sockets.erase(fd));
        return 0;
      }

      /*-------------.
      | StreamBuffer |
      `-------------*/

      elle::WeakBuffer
      Request::Impl::write_buffer()
      {
        ELLE_ASSERT(!this->_output_done);
        if (this->_conf.chunked_transfers())
        {
          this->_output.size(CURL_MAX_WRITE_SIZE);
          return this->_output;
        }
        else
        {
          if (this->_output_available)
            this->_output_consumed.wait();
          this->_output.capacity(this->_output.size() + CURL_MAX_WRITE_SIZE);
          return elle::WeakBuffer(
            this->_output.mutable_contents() + this->_output.size(),
            CURL_MAX_WRITE_SIZE);
        }
      }

      void
      Request::Impl::flush(StreamBuffer::Size size)
      {
        ELLE_ASSERT(!this->_output_done);
        if (this->_conf.chunked_transfers())
        {
          this->_output.size(size);
          ELLE_DEBUG_SCOPE("%s: output: post data: %s",
                           *this->_request, this->_output);
          this->_output_available = true;
          curl_easy_pause(this->_handle, CURLPAUSE_CONT);
        }
        else
        {
          elle::ConstWeakBuffer newdata(
            this->_output.mutable_contents() + this->_output.size(), size);
          ELLE_DEBUG_SCOPE("%s: output: post data: %s",
                           *this->_request, newdata);
          this->_output.size(this->_output.size() + size);
        }
      }

      elle::ConstWeakBuffer
      Request::Impl::read_buffer()
      {
        if (!this->_input_available.opened())
        {
          ELLE_DEBUG_SCOPE("%s: input: wait for more data", *this->_request);
          this->_input_available.wait();
        }
        if (!this->_input.empty())
        {
          this->_input_current = std::move(this->_input.front());
          ELLE_DEBUG_SCOPE("%s: input: fetch data: %f",
                           *this->_request, this->_input_current);
          ELLE_DUMP("%s", this->_input_current);
          this->_input.pop();
          if (this->_input.empty() && !this->_input_done)
            this->_input_available.close();
          return this->_input_current;
        }
        else
        {
          ELLE_DEBUG("%s: input: end of data", *this->_request);
          return elle::WeakBuffer();
        }
      }

      size_t
      Request::Impl::write_callback(char* ptr,
                                    size_t chunk,
                                    size_t count,
                                    void* userdata)
      {
        auto& self = *reinterpret_cast<Request::Impl*>(userdata);
        auto size = chunk * count;
        self.enqueue_data(elle::Buffer(ptr, size));
        return size;
      }

      void
      Request::Impl::enqueue_data(elle::Buffer buffer)
      {
        ELLE_DEBUG_SCOPE("%s: input: got data: %f", *this->_request, buffer);
        this->_input.push(std::move(buffer));
        this->_input_available.open();
      }

      void
      Request::Impl::_complete()
      {
        this->_input_available.open();
        this->_input_done = true;
      }

      /*------.
      | Input |
      `------*/
      size_t
      Request::Impl::read_callback(char* ptr,
                                   size_t chunk,
                                   size_t count,
                                   void* userdata)
      {
        auto& self = *reinterpret_cast<Request::Impl*>(userdata);
        auto size = chunk * count;
        return self.read_data(elle::WeakBuffer(ptr, size));
      }

      size_t
      Request::Impl::read_data(elle::WeakBuffer buffer)
      {
        if (this->_conf.chunked_transfers())
        {
          ELLE_ASSERT_GTE(buffer.size(), this->_output.size());
          if (!this->_output_available)
          {
            if (this->_output_done)
            {
              ELLE_DEBUG("%s: output: end of data", *this->_request);
              return 0;
            }
            ELLE_DEBUG("%s: output: no data available, pause", *this->_request);
            ++this->_pause_count;
            return CURL_READFUNC_PAUSE;
          }
          this->_output_available = false;
          memcpy(buffer.mutable_contents(),
                 this->_output.mutable_contents(), this->_output.size());
          this->_output_consumed.signal();
          ELLE_DEBUG("%s: output: get %s bytes",
                     *this->_request, this->_output.size());
          return this->_output.size();
        }
        else
        {
          ELLE_ASSERT(this->_output_done);
          elle::ConstWeakBuffer source(
            this->_output.contents() + this->_output_offset,
            this->_output.size() - this->_output_offset);
          if (source.size() == 0)
          {
            ELLE_DEBUG("%s: output: end of data", *this->_request);
            return 0;
          }
          auto effective = std::min(source.size(), buffer.size());
          memcpy(buffer.mutable_contents(),
                 source.contents(), effective);
          this->_output_offset += effective;
          ELLE_DEBUG("%s: output: get %s bytes", *this->_request, effective);
          return effective;
        }
      }

      /*---------.
      | Progress |
      `---------*/

      int
      Request::Impl::progress_callback(void* userdata,
                                       curl_off_t dltotal, curl_off_t dlnow,
                                       curl_off_t ultotal, curl_off_t ulnow)
      {
        auto& self = *reinterpret_cast<Request::Impl*>(userdata);
        self.progress_set(dltotal, dlnow, ultotal, ulnow);
        return 0;
      }

      void
      Request::Impl::progress_set(curl_off_t dltotal, curl_off_t dlnow,
                                  curl_off_t ultotal, curl_off_t ulnow)
      {
        this->_progress = Progress {dlnow, dltotal, ulnow, ultotal};
        ELLE_DEBUG("%s: progress set to %s", *this->_request, this->_progress);
        this->_progress_changed(this->_progress);
      }

      std::ostream&
      operator << (std::ostream& os, Request::Progress const& p)
      {
        return elle::print(os, "(DL %s/%s  UL %s/%s)",
                           p.download_current, p.download_total,
                           p.upload_current, p.upload_total);
      }

      bool
      Request::Progress::operator ==(Progress const& b) const
      {
        return std::tie(download_current, download_total, upload_current, upload_total)
          == std::tie(b.download_current, b.download_total, b.upload_current, b.upload_total);
      }

      /*---------.
      | Printing |
      `---------*/

      void
      Request::Impl::print(std::ostream& stream) const
      {
        stream << this->_method << " on " << this->_url
               << " (" << this->_handle << ")";
      }

      /*-------------.
      | Construction |
      `-------------*/

      Request::Request(std::string const& url,
                       Method method,
                       Configuration conf,
                       bool)
        : elle::IOStream(this->_impl = new Impl(*this, url, method,
                                                std::move(conf)))
        , _method(method)
        , _url(url)
        , _query_string()
        , _status(static_cast<StatusCode>(0))
      {}

      Request::Request(std::string const& url,
                       Method method,
                       Configuration conf)
        : Request(url, method, std::move(conf), true)
      {
        this->_impl->header_remove("Transfer-Encoding");
        if (conf.chunked_transfers())
          this->_impl->start();
      }

      Request::Request(std::string const& url,
                       Method method,
                       std::string const& content_type,
                       Configuration conf)
        : Request(url, method, std::move(conf), true)
      {
        this->_impl->header_add("Content-Type", content_type);
        // XXX: HTTP/1.0 expects a Content-Size, preventing streaming. Be safe
        // for now.
        if (conf.chunked_transfers())
        {
          this->_impl->header_add("Transfer-Encoding", "chunked");
          this->_impl->start();
        }
        else
          this->_impl->header_remove("Transfer-Encoding");
      }

      /// Move a Request.
      Request::Request(Request&& source)
        : elle::IOStream(std::move(source))
        , _method(source._method)
        , _url(source._url)
        , _impl(source._impl)
        , _query_string(source._query_string)
        , _status(source._status)
      {
        source._impl = nullptr;
        this->_impl->_request = this;
      }

      Request::~Request()
      {
        // The impl is deleted as the StreamBuffer.
      }

      /*-------------.
      | Query String |
      `-------------*/
      void
      Request::query_string(Request::QueryDict const& query_dict)
      {
        if (query_dict.empty())
          return;
        std::string res = "";
        auto curl = [this](auto const& s)
          {
            char* cp = curl_easy_escape(this->_impl->_handle,
                                        s.c_str(), s.size());
            auto res = std::string{cp};
            curl_free(cp);
            return res;
          };
        for (auto const& pair: query_dict)
          res += elle::print("%s=%s&",
                             curl(pair.first), curl(pair.second));
        this->_query_string = res.substr(0, res.length() - 1);
        this->_impl->_query_string = this->_query_string;
      }

      std::string const&
      Request::query_string() const
      {
        return this->_impl->_query_string;
      }

      /*-----------.
      | Completion |
      `-----------*/

      void
      Request::finalize()
      {
        if (this->_impl->_output_done)
          return;
        ELLE_TRACE_SCOPE("%s: output: finalize", *this);
        this->flush();
        this->_impl->_output_done = true;
        curl_easy_pause(this->_impl->_handle, CURLPAUSE_CONT);
        if (!this->_impl->_conf.chunked_transfers())
        {
          this->_impl->header_add("Content-Length",
                                  std::to_string(this->_impl->_output.size()));
          this->_impl->start();
        }
      }

      void
      Request::_complete(int code)
      {
        this->_impl->_debug2 = 1;
        ELLE_TRACE_SCOPE("%s: complete with code %s", *this, code);
        curl_easy_getinfo(this->_impl->_handle,
                          CURLINFO_RESPONSE_CODE, &this->_status);
        // Distinguishing stall timeout and 'total time limit'
        // timeouts is tricky and requires parsing the error string.
        // Be robust to detection failure.
        bool is_stall = false;
        auto set_exception = [&](std::string const& msg = "")
          {
            ELLE_WARN("%s: done with error: %s", *this, msg);
            if (code == CURLE_GOT_NOTHING)
              this->_raise<EmptyResponse>(this->_url);
            else if (code == CURLE_OPERATION_TIMEDOUT)
            {
              auto const& timeout = this->_impl->_conf.timeout();
              auto const& stall_timeout = this->_impl->_conf.stall_timeout();
              auto const value = is_stall
                ? (stall_timeout ? *stall_timeout : *timeout)
                : (timeout ? *timeout : *stall_timeout);
              this->_raise<Timeout>(this->_url, value);
            }
            else if (code == CURLE_COULDNT_RESOLVE_HOST)
              this->_raise<ResolutionFailure>(this->_url);
            else
              this->_raise<RequestError>(this->_url, msg);
          };
        bool exception = false;
        if (code != CURLE_OK)
        {
          exception = true;
          auto const msg
            = elle::print("%s: %s",
                          curl_easy_strerror(CURLcode(code)),
                          this->_impl->_error);
          is_stall = msg.find("too slow") != msg.npos;
          set_exception(msg);
        }
        else if (this->_impl->_conf.expected_status() &&
                 this->_impl->_conf.expected_status().get() != this->_status)
        {
          exception = true;
          set_exception(elle::print("got unexpected status %s instead of %s",
                                    this->_status,
                                    this->_impl->_conf.expected_status().get()));
        }
        else
          ELLE_TRACE_SCOPE("%s: done with status %s", *this, this->_status);
        if (!exception && this->_status == static_cast<StatusCode>(0))
        {
          exception = true;
          set_exception("server response has no status");
        }
        this->_impl->_debug2 = 2;
        this->_signal();
        // Waitables consume their exception once signaled, restore it.
        if (exception)
        {
          this->_impl->_debug2 = 3;
          set_exception();
        }
        this->_impl->_complete();
      }

      bool
      Request::_wait(Thread* thread, Waker const& waker)
      {
        this->_impl->_debug = 1;
        this->finalize();
        if (this->_impl->_input_done)
        {
          if (std::exception_ptr exn = this->exception())
          {
            this->_impl->_debug = 2;
            std::rethrow_exception(exn);
          }
          this->_impl->_debug = 3;
          if (this->_status == static_cast<StatusCode>(0))
          {
            ELLE_ERR("%s: input done with null status", *this);
            ELLE_ASSERT_NEQ(this->_status, static_cast<StatusCode>(0));
          }
          return false;
        }
        else
        {
          this->_impl->_debug = 4;
          auto impl = this->_impl;
          impl->_bt_waited = elle::Backtrace::current();
          this->_impl->_slot_frozen =
            reactor::scheduler().current()->frozen().connect(
              [impl]
              {
                impl->_bt_frozen = elle::Backtrace::current();
                impl->_slot_frozen.disconnect();
              });
          this->_impl->_slot_unfrozen =
            reactor::scheduler().current()->unfrozen().connect(
              [impl]
              (std::string const& reason)
              {
                impl->_bt_unfrozen_reason = reason;
                impl->_bt_unfrozen = elle::Backtrace::current();
                impl->_slot_unfrozen.disconnect();
              });
          return Waitable::_wait(thread, waker);
        }
      }

      /*-------.
      | Status |
      `-------*/

      StatusCode
      Request::status() const
      {
        ELLE_TRACE_SCOPE("%s: wait status", *this);
        // XXX: We need not wait for the whole request.
        reactor::wait(*const_cast<Request*>(this));
        ELLE_TRACE_SCOPE("%s: waited", *this);
        if (this->_status == static_cast<StatusCode>(0))
        {
          ELLE_ERR("%s: awaken with null status, debug: %s, debug2: %s",
                   *this, this->_impl->_debug, this->_impl->_debug2);
          ELLE_ERR("%s: frozen backtrace: %s",
                   *this, this->_impl->_bt_frozen);
          ELLE_ERR("%s: unfrozen because: %s",
                   *this, this->_impl->_bt_unfrozen_reason);
          ELLE_ERR("%s: unfrozen backtrace: %s",
                   *this, this->_impl->_bt_unfrozen);
          ELLE_ERR("%s: waited backtrace: %s",
                   *this, this->_impl->_bt_waited);
          ELLE_ASSERT_NEQ(this->_status, static_cast<StatusCode>(0));
        }
        return this->_status;
      }

      elle::Buffer
      Request::response()
      {
        this->finalize();
        elle::Buffer res;
        {
          elle::IOStream output(res.ostreambuf());
          using IIterator = std::istreambuf_iterator<char>;
          using OIterator = std::ostreambuf_iterator<char>;
          std::copy(IIterator(*this), IIterator(), OIterator(output));
        }
        // We ran out of data so the request should be finished; this is just
        // for exceptions.
        this->wait();
        return res;
      }

      int
      Request::pause_count() const
      {
        return this->_impl->_pause_count;
      }

      /*--------.
      | Cookies |
      `--------*/

      Request::Configuration::Cookies
      Request::cookies() const
      {
        return this->_impl->cookies();
      }

      /*----------.
      | Printable |
      `----------*/

      void
      Request::print(std::ostream& stream) const
      {
        stream << *this->_impl;
      }

      Request::Progress
      Request::progress() const
      {
        return this->_impl->progress();
      }

      boost::signals2::signal<void (Request::Progress const&)>&
      Request::progress_changed()
      {
        return this->_impl->progress_changed();
      }

      boost::signals2::signal<void (Request::Progress const&)> const&
      Request::progress_changed() const
      {
        return this->_impl->progress_changed();
      }

      /*----------.
      | Shortcuts |
      `----------*/

      elle::Buffer
      get(std::string const& url,
          Request::Configuration conf)
      {
        Request r(url, Method::GET, std::move(conf));
        return r.response();
      }
    }
  }
}

ext: cc

max_stars_repo_name: infinit/elle

max_issues_repo_name: mefyl/elle

max_forks_repo_name: mefyl/elle


text:
/*!
@file
Defines `boost::hana::ext::std::Array`.

@copyright Louis Dionne 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_EXT_STD_ARRAY_HPP
#define BOOST_HANA_EXT_STD_ARRAY_HPP

#include <boost/hana/bool.hpp>
#include <boost/hana/core/datatype.hpp>
#include <boost/hana/core/models.hpp>
#include <boost/hana/detail/std/forward.hpp>
#include <boost/hana/detail/std/integer_sequence.hpp>
#include <boost/hana/detail/std/remove_reference.hpp>
#include <boost/hana/iterable.hpp>
#include <boost/hana/sequence.hpp>

#include <array>
#include <cstddef>

namespace boost { namespace hana {
    namespace ext { namespace std { struct Array; }}

    template <typename T, std::size_t N>
    struct datatype< ::std::array<T, N>> {
        using type = ext::std::Array;
    };

    //////////////////////////////////////////////////////////////////////////
    // Comparable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct equal_impl<ext::std::Array, ext::std::Array>
        : Sequence::equal_impl<ext::std::Array, ext::std::Array>
    { };

    //////////////////////////////////////////////////////////////////////////
    // Orderable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct less_impl<ext::std::Array, ext::std::Array>
        : Sequence::less_impl<ext::std::Array, ext::std::Array>
    { };

    //////////////////////////////////////////////////////////////////////////
    // Foldable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct foldl_impl<ext::std::Array>
        : Iterable::foldl_impl<ext::std::Array>
    { };

    template <>
    struct foldr_impl<ext::std::Array>
        : Iterable::foldr_impl<ext::std::Array>
    { };

    template <>
    struct foldl1_impl<ext::std::Array>
        : Iterable::foldl1_impl<ext::std::Array>
    { };

    template <>
    struct foldr1_impl<ext::std::Array>
        : Iterable::foldr1_impl<ext::std::Array>
    { };

    //////////////////////////////////////////////////////////////////////////
    // Searchable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct find_if_impl<ext::std::Array>
        : Iterable::find_if_impl<ext::std::Array>
    { };

    template <>
    struct any_of_impl<ext::std::Array>
        : Iterable::any_of_impl<ext::std::Array>
    { };

    //////////////////////////////////////////////////////////////////////////
    // Iterable
    //////////////////////////////////////////////////////////////////////////
    template <>
    struct head_impl<ext::std::Array> {
        template <typename Xs>
        static constexpr decltype(auto) apply(Xs&& xs)
        { return detail::std::forward<Xs>(xs)[0]; }
    };

    template <>
    struct tail_impl<ext::std::Array> {
        template <typename T, std::size_t N, typename Xs, std::size_t ...index>
        static constexpr auto tail_helper(Xs&& xs, detail::std::index_sequence<index...>) {
            return ::std::array<T, N - 1>{{
                detail::std::forward<Xs>(xs)[index + 1]...
            }};
        }

        template <typename Xs>
        static constexpr decltype(auto) apply(Xs&& xs) {
            using RawArray = typename detail::std::remove_reference<Xs>::type;
            constexpr auto N = ::std::tuple_size<RawArray>::value;
            using T = typename RawArray::value_type;
            return tail_helper<T, N>(
                detail::std::forward<Xs>(xs),
                detail::std::make_index_sequence<N - 1>{}
            );
        }
    };

    template <>
    struct is_empty_impl<ext::std::Array> {
        template <typename T, std::size_t N>
        static constexpr auto apply(::std::array<T, N> const&)
        { return bool_<N == 0>; }
    };
}} // end namespace boost::hana

#endif // !BOOST_HANA_EXT_STD_ARRAY_HPP

ext: hpp

max_stars_repo_name: josephwinston/hana

max_issues_repo_name: josephwinston/hana

max_forks_repo_name: josephwinston/hana


text:
/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include <com/sun/star/registry/XRegistryKey.hpp>

#include "sddll.hxx"

#include <cppuhelper/factory.hxx>
#include <uno/lbnames.h>
#include <sfx2/sfxmodelfactory.hxx>
#include "osl/diagnose.h"
#include "sal/types.h"

#ifndef INCLUDED_STRING_H
#include <string.h>
#define INCLUDED_STRING_H
#endif
#include <comphelper/stl_types.hxx>
#include <hash_map>
#include <boost/shared_ptr.hpp>

using namespace rtl;
using namespace com::sun::star;

// Forward declarations of the factories.

extern uno::Reference< uno::XInterface > SAL_CALL SdDrawingDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory, const sal_uInt64 _nCreationFlags );
extern OUString SdDrawingDocument_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString > SAL_CALL SdDrawingDocument_getSupportedServiceNames() throw( uno::RuntimeException );

extern uno::Reference< uno::XInterface > SAL_CALL SdPresentationDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory, const sal_uInt64 _nCreationFlags );
extern OUString SdPresentationDocument_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString > SAL_CALL SdPresentationDocument_getSupportedServiceNames() throw( uno::RuntimeException );

extern uno::Reference< uno::XInterface > SAL_CALL SdHtmlOptionsDialog_CreateInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory );
extern OUString SdHtmlOptionsDialog_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString > SAL_CALL SdHtmlOptionsDialog_getSupportedServiceNames() throw( uno::RuntimeException );

extern uno::Reference< uno::XInterface > SAL_CALL SdUnoModule_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory );
extern OUString SdUnoModule_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString > SAL_CALL SdUnoModule_getSupportedServiceNames() throw( uno::RuntimeException );

namespace sd
{
extern uno::Reference< uno::XInterface > SAL_CALL RandomNode_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory );
extern OUString RandomNode__getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString > SAL_CALL RandomNode_getSupportedServiceNames() throw( uno::RuntimeException );

extern uno::Reference< uno::XInterface > SAL_CALL SlideLayoutController_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory );
extern OUString SlideLayoutController_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString >  SlideLayoutController_getSupportedServiceNames() throw( uno::RuntimeException );

extern uno::Reference< uno::XInterface > SAL_CALL InsertSlideController_createInstance( const uno::Reference< lang::XMultiServiceFactory > & _rxFactory );
extern OUString InsertSlideController_getImplementationName() throw( uno::RuntimeException );
extern uno::Sequence< OUString >  InsertSlideController_getSupportedServiceNames() throw( uno::RuntimeException );
}

namespace sd { namespace framework {

extern uno::Reference<uno::XInterface> SAL_CALL Configuration_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString Configuration_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL Configuration_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL ConfigurationController_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString ConfigurationController_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL ConfigurationController_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL ModuleController_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString ModuleController_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL ModuleController_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL BasicPaneFactory_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString BasicPaneFactory_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL BasicPaneFactory_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL BasicToolBarFactory_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString BasicToolBarFactory_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL BasicToolBarFactory_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL BasicViewFactory_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString BasicViewFactory_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL BasicViewFactory_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL ResourceId_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString ResourceId_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL ResourceId_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL PresentationFactoryProvider_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PresentationFactoryProvider_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PresentationFactoryProvider_getSupportedServiceNames (void)
    throw (uno::RuntimeException);
} }

namespace sd { namespace sidebar {

extern uno::Reference<uno::XInterface> SAL_CALL PanelFactory_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PanelFactory_getImplementationName(void) throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PanelFactory_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

} }

namespace sd { namespace presenter {
extern uno::Reference<uno::XInterface> SAL_CALL SlideRenderer_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString SlideRenderer_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL SlideRenderer_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL PresenterCanvas_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PresenterCanvas_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PresenterCanvas_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL PresenterTextViewService_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PresenterTextViewService_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PresenterTextViewService_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL PresenterHelperService_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PresenterHelperService_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PresenterHelperService_getSupportedServiceNames (void)
    throw (uno::RuntimeException);

extern uno::Reference<uno::XInterface> SAL_CALL PresenterPreviewCache_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString PresenterPreviewCache_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL PresenterPreviewCache_getSupportedServiceNames (void)
    throw (uno::RuntimeException);
} }

namespace sd { namespace slidesorter {
extern uno::Reference<uno::XInterface> SAL_CALL SlideSorterService_createInstance(
    const uno::Reference<uno::XComponentContext>& rxContext)
    throw(uno::Exception);
extern OUString SlideSorterService_getImplementationName(void)
    throw (uno::RuntimeException);
extern uno::Sequence<OUString> SAL_CALL SlideSorterService_getSupportedServiceNames (void)
    throw (uno::RuntimeException);
} }

using namespace ::sd;
using namespace ::sd::framework;
using namespace ::sd::presenter;
using namespace ::sd::slidesorter;
using namespace ::sd::sidebar;

// ----------------------------------------------------------------------------
// Declaration and initialization of a map from service names to locally
// unique factory identifiers.

enum FactoryId
{
    SdDrawingDocumentFactoryId,
    SdPresentationDocumentFactoryId,
    SdHtmlOptionsDialogFactoryId,
    SdUnoModuleFactoryId,
    RandomNodeFactoryId,

    ConfigurationFactoryId,
    ConfigurationControllerFactoryId,
    ModuleControllerFactoryId,
    BasicPaneFactoryFactoryId,
    BasicToolBarFactoryFactoryId,
    BasicViewFactoryFactoryId,
    PanelFactoryFactoryId,
    ResourceIdFactoryId,
    PresentationFactoryProviderFactoryId,
    SlideRendererFactoryId,
    PresenterCanvasFactoryId,
    PresenterTextViewServiceFactoryId,
    PresenterHelperServiceFactoryId,
    PresenterPreviewCacheFactoryId,
    SlideSorterServiceFactoryId,
	SlideLayoutControllerFactoryId,
	InsertSlideControllerFactoryId,
};
typedef ::std::hash_map<OUString, FactoryId, comphelper::UStringHash, comphelper::UStringEqual> FactoryMap;

namespace {
static ::boost::shared_ptr<FactoryMap> spFactoryMap;
::boost::shared_ptr<FactoryMap> GetFactoryMap (void)
{
    if (spFactoryMap.get() == NULL)
    {
        spFactoryMap.reset(new FactoryMap);
        (*spFactoryMap)[SdDrawingDocument_getImplementationName()] = SdDrawingDocumentFactoryId;
        (*spFactoryMap)[SdPresentationDocument_getImplementationName()] = SdPresentationDocumentFactoryId;
        (*spFactoryMap)[SdHtmlOptionsDialog_getImplementationName()] = SdHtmlOptionsDialogFactoryId;
        (*spFactoryMap)[SdUnoModule_getImplementationName()] = SdUnoModuleFactoryId;
        (*spFactoryMap)[RandomNode__getImplementationName()] = RandomNodeFactoryId;
        (*spFactoryMap)[Configuration_getImplementationName()] = ConfigurationFactoryId;
        (*spFactoryMap)[ConfigurationController_getImplementationName()] = ConfigurationControllerFactoryId;
        (*spFactoryMap)[ModuleController_getImplementationName()] = ModuleControllerFactoryId;
        (*spFactoryMap)[BasicPaneFactory_getImplementationName()] = BasicPaneFactoryFactoryId;
        (*spFactoryMap)[BasicToolBarFactory_getImplementationName()] = BasicToolBarFactoryFactoryId;
        (*spFactoryMap)[BasicViewFactory_getImplementationName()] = BasicViewFactoryFactoryId;
        (*spFactoryMap)[sidebar::PanelFactory_getImplementationName()] = PanelFactoryFactoryId;
        (*spFactoryMap)[ResourceId_getImplementationName()] = ResourceIdFactoryId;
        (*spFactoryMap)[PresentationFactoryProvider_getImplementationName()] = PresentationFactoryProviderFactoryId;
        (*spFactoryMap)[SlideRenderer_getImplementationName()] = SlideRendererFactoryId;
        (*spFactoryMap)[PresenterCanvas_getImplementationName()] = PresenterCanvasFactoryId;
        (*spFactoryMap)[PresenterTextViewService_getImplementationName()] = PresenterTextViewServiceFactoryId;
        (*spFactoryMap)[PresenterHelperService_getImplementationName()] = PresenterHelperServiceFactoryId;
        (*spFactoryMap)[PresenterPreviewCache_getImplementationName()] = PresenterPreviewCacheFactoryId;
        (*spFactoryMap)[SlideSorterService_getImplementationName()] = SlideSorterServiceFactoryId;
		(*spFactoryMap)[SlideLayoutController_getImplementationName()] = SlideLayoutControllerFactoryId;
		(*spFactoryMap)[InsertSlideController_getImplementationName()] = InsertSlideControllerFactoryId;
    }
    return spFactoryMap;
};
} // end of anonymous namespace

extern "C"
{

SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment(
	const sal_Char  ** ppEnvTypeName,
	uno_Environment **  )
{
	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
	const sal_Char * pImplName,
	void           * pServiceManager,
	void           *  )
{
    void * pRet = 0;

	if( pServiceManager )
	{
		uno::Reference< lang::XMultiServiceFactory > xMSF( reinterpret_cast< lang::XMultiServiceFactory * >( pServiceManager ) );

		uno::Reference<lang::XSingleServiceFactory> xFactory;
        uno::Reference<lang::XSingleComponentFactory> xComponentFactory;

        ::boost::shared_ptr<FactoryMap> pFactoryMap (GetFactoryMap());
        OUString sImplementationName (OUString::createFromAscii(pImplName));
        FactoryMap::const_iterator iFactory (pFactoryMap->find(sImplementationName));
        if (iFactory != pFactoryMap->end())
        {
            switch (iFactory->second)
            {
                case SdHtmlOptionsDialogFactoryId:
                    xFactory = ::cppu::createSingleFactory(
                        xMSF,
                        SdHtmlOptionsDialog_getImplementationName(),
                        SdHtmlOptionsDialog_CreateInstance,
                        SdHtmlOptionsDialog_getSupportedServiceNames());
                    break;

                case SdDrawingDocumentFactoryId:
                    xFactory = ::sfx2::createSfxModelFactory(
                        xMSF,
                        SdDrawingDocument_getImplementationName(),
                        SdDrawingDocument_createInstance,
                        SdDrawingDocument_getSupportedServiceNames());
                    break;

                case SdPresentationDocumentFactoryId:
                    xFactory = ::sfx2::createSfxModelFactory(
                        xMSF,
                        SdPresentationDocument_getImplementationName(),
                        SdPresentationDocument_createInstance,
                        SdPresentationDocument_getSupportedServiceNames());
                    break;

                case SdUnoModuleFactoryId:
                    xFactory = ::cppu::createSingleFactory(
                        xMSF,
                        SdUnoModule_getImplementationName(),
                        SdUnoModule_createInstance,
                        SdUnoModule_getSupportedServiceNames());
                    break;

                case RandomNodeFactoryId:
                    xFactory = ::cppu::createSingleFactory(
                        xMSF,
                        sd::RandomNode__getImplementationName(),
                        sd::RandomNode_createInstance,
                        sd::RandomNode_getSupportedServiceNames());
                    break;

                case ConfigurationFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::Configuration_createInstance,
                        sd::framework::Configuration_getImplementationName(),
                        sd::framework::Configuration_getSupportedServiceNames());
                    break;

                case ConfigurationControllerFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::ConfigurationController_createInstance,
                        sd::framework::ConfigurationController_getImplementationName(),
                        sd::framework::ConfigurationController_getSupportedServiceNames());
                    break;

                case ModuleControllerFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::ModuleController_createInstance,
                        sd::framework::ModuleController_getImplementationName(),
                        sd::framework::ModuleController_getSupportedServiceNames());
                    break;

                case BasicPaneFactoryFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::BasicPaneFactory_createInstance,
                        sd::framework::BasicPaneFactory_getImplementationName(),
                        sd::framework::BasicPaneFactory_getSupportedServiceNames());
                    break;

                case BasicToolBarFactoryFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::BasicToolBarFactory_createInstance,
                        sd::framework::BasicToolBarFactory_getImplementationName(),
                        sd::framework::BasicToolBarFactory_getSupportedServiceNames());
                    break;

                case BasicViewFactoryFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::BasicViewFactory_createInstance,
                        sd::framework::BasicViewFactory_getImplementationName(),
                        sd::framework::BasicViewFactory_getSupportedServiceNames());
                    break;

                case PanelFactoryFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::sidebar::PanelFactory_createInstance,
                        sd::sidebar::PanelFactory_getImplementationName(),
                        sd::sidebar::PanelFactory_getSupportedServiceNames());
                    break;

                case ResourceIdFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::ResourceId_createInstance,
                        sd::framework::ResourceId_getImplementationName(),
                        sd::framework::ResourceId_getSupportedServiceNames());
                    break;

                case PresentationFactoryProviderFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::framework::PresentationFactoryProvider_createInstance,
                        sd::framework::PresentationFactoryProvider_getImplementationName(),
                        sd::framework::PresentationFactoryProvider_getSupportedServiceNames());
                    break;

                case SlideRendererFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::presenter::SlideRenderer_createInstance,
                        sd::presenter::SlideRenderer_getImplementationName(),
                        sd::presenter::SlideRenderer_getSupportedServiceNames());
                    break;

                case PresenterCanvasFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::presenter::PresenterCanvas_createInstance,
                        sd::presenter::PresenterCanvas_getImplementationName(),
                        sd::presenter::PresenterCanvas_getSupportedServiceNames());
                    break;

                case PresenterTextViewServiceFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::presenter::PresenterTextViewService_createInstance,
                        sd::presenter::PresenterTextViewService_getImplementationName(),
                        sd::presenter::PresenterTextViewService_getSupportedServiceNames());
                    break;

                case PresenterHelperServiceFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::presenter::PresenterHelperService_createInstance,
                        sd::presenter::PresenterHelperService_getImplementationName(),
                        sd::presenter::PresenterHelperService_getSupportedServiceNames());
                    break;

                case PresenterPreviewCacheFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::presenter::PresenterPreviewCache_createInstance,
                        sd::presenter::PresenterPreviewCache_getImplementationName(),
                        sd::presenter::PresenterPreviewCache_getSupportedServiceNames());
                    break;

                case SlideSorterServiceFactoryId:
                    xComponentFactory = ::cppu::createSingleComponentFactory(
                        sd::slidesorter::SlideSorterService_createInstance,
                        sd::slidesorter::SlideSorterService_getImplementationName(),
                        sd::slidesorter::SlideSorterService_getSupportedServiceNames());
                    break;

				case SlideLayoutControllerFactoryId:
					xFactory = ::cppu::createSingleFactory(
                        xMSF,
						sd::SlideLayoutController_getImplementationName(),
						sd::SlideLayoutController_createInstance,
						sd::SlideLayoutController_getSupportedServiceNames());
					break;

				case InsertSlideControllerFactoryId:
					xFactory = ::cppu::createSingleFactory(
                        xMSF,
						sd::InsertSlideController_getImplementationName(),
						sd::InsertSlideController_createInstance,
						sd::InsertSlideController_getSupportedServiceNames());
                default:
                    break;
            }
            if (xComponentFactory.is())
            {
                xComponentFactory->acquire();
                pRet = xComponentFactory.get();
            }
            else if (xFactory.is())
            {
                xFactory->acquire();
                pRet = xFactory.get();
            }
        }
    }

    if (pRet != NULL)
        SdDLL::Init();
	return pRet;
}

} // end of extern "C"

ext: cxx

max_stars_repo_name: Grosskopf/openoffice

max_issues_repo_name: Grosskopf/openoffice

max_forks_repo_name: Grosskopf/openoffice


text:
/// yet other file I/O

#include <algorithm>
#include <boost/type_traits/is_complex.hpp>
#include <fstream>
#include <iostream>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <vector>

#include "fhmdot/include/babel_type.hpp"

namespace fhmdot {

namespace yofi {

// printing tuple
template <std::size_t I = 0, typename... Tp>
typename std::enable_if<I == sizeof...(Tp), void>::type
print_tuple(std::tuple<Tp...> &) {}

template <std::size_t I = 0, typename... Tp>
    typename std::enable_if <
    I<sizeof...(Tp), void>::type print_tuple(std::tuple<Tp...> &t) {
  std::cout << std::get<I>(t) << ", ";
  print_tuple<I + 1, Tp...>(t);
}

// writing tuple to a file
template <std::size_t I = 0, typename... Tp>
typename std::enable_if<I == sizeof...(Tp), void>::type
write_tuple(std::ofstream &, std::tuple<Tp...> &) {}

template <std::size_t I = 0, typename... Tp>
    typename std::enable_if <
    I<sizeof...(Tp), void>::type write_tuple(std::ofstream &ofs,
                                             std::tuple<Tp...> &t) {
  ofs.write((char *)&std::get<I>(t),
            sizeof(typename std::tuple_element<I, std::tuple<Tp...>>::type));
  write_tuple<I + 1, Tp...>(ofs, t);
}

// reading tuple from a file
template <std::size_t I = 0, typename... Tp>
typename std::enable_if<I == sizeof...(Tp), void>::type
read_tuple(std::ifstream &, std::tuple<Tp...> &) {}

template <std::size_t I = 0, typename... Tp>
    typename std::enable_if <
    I<sizeof...(Tp), void>::type read_tuple(std::ifstream &ifs,
                                            std::tuple<Tp...> &t) {
  ifs.read((char *)&std::get<I>(t),
           sizeof(typename std::tuple_element<I, std::tuple<Tp...>>::type));
  read_tuple<I + 1, Tp...>(ifs, t);
}

// printing vector
template <typename T> void print_array(std::vector<T> &arr) {
  for (const auto &item : arr) {
    std::cout << item << ",";
  }
}

// writing vector to a file
template <typename T>
void write_array(std::ofstream &ofs, std::vector<T> &arr) {
  std::copy(arr.begin(), arr.end(), std::ostreambuf_iterator<char>(ofs));
}

// reading vector to a file
template <typename T> void read_array(std::ifstream &ifs, std::vector<T> &arr) {
  auto start = std::istreambuf_iterator<char>(ifs);
  auto stop = std::istreambuf_iterator<char>();
  std::copy(start, stop, std::back_inserter(arr));
}

template <typename M> void print_mp(M &smp) {
  auto nb_blocks = smp.size();
  std::cout << "#number of blocks : " << nb_blocks << std::endl;
  std::cout << "#data type : " << nb_blocks << std::endl;

  for (auto &mp : smp.arr_) {
    //  mp.first
    //   write_tuple(ifs, index);
    //   write_tuple(ifs, shape);
    //   write_array(ifs, arr);
  }
}

template <typename M> void write_mp(std::ifstream &ifs, M &smp) {
  // for (index, shape, arr) {
  //   write_tuple(ifs, index);
  //   write_tuple(ifs, shape);
  //   write_array(ifs, arr);
  // }
}

template <typename M> void read_mp(std::ifstream &ifs, M &smp) {
  // for (index, shape, arr) {
  //   write_tuple(ifs, index);
  //   write_tuple(ifs, shape);
  //   write_array(ifs, arr);
  // }
}

} // namespace yofi

} // namespace fhmdot