try {
	sc_bit foo('2');
    }
    catch (sc_report) {
	cout << "Caught exception for sc_bit('2')\n";
    }

    sc_bit blc0(sc_logic('0'));
    sc_bit blc1(sc_logic('1'));
    sc_bit blcx(sc_logic('X'));
    sc_bit bcop(bt);
    cout << bdef << bf << bt << b0 << b1 << bc0 << bc1 << blc0 << blc1
	 << blcx << bcop << endl;
    sc_bit b;
    b = bt;
    sc_assert(b);
    b = 0;
    sc_assert(!b);
    b = true;
    sc_assert(b.to_bool());
    b = '0';
    sc_assert(!b.to_bool());
    b = sc_logic('1');
    sc_assert(b.to_char() == '1');
    b = bf;
    sc_assert(~b);
    b |= bt;
    sc_assert(b);
    b &= bf;
    sc_assert(!b);
    b |= 1;
    sc_assert(b);
    b &= 0;
    sc_assert(!b);
    b |= '1';
    sc_assert(b);
    b &= '0';
    sc_assert(!b);
    b |= true;
    sc_assert(b);
    b &= false;
    sc_assert(!b);
    b ^= bt;
    sc_assert(b);
    b ^= 1;
    sc_assert(!b);
    b ^= '1';
    sc_assert(b);
    b ^= true;
    sc_assert(!b);

    sc_assert(b == bf);
    sc_assert(b == 0);
    sc_assert(b == '0');
    sc_assert(b == false);
    b = 1;
    sc_assert(b == bt);
    sc_assert(b == 1);
    sc_assert(b == '1');
    sc_assert(b == true);
    sc_assert(1 == b);
    sc_assert('1' == b);
    sc_assert(true == b);
    sc_assert(equal(b, bt));
    sc_assert(equal(b, 1));
    sc_assert(equal(b, '1'));
    sc_assert(equal(b, true));
    sc_assert(equal(1, b));
    sc_assert(equal('1', b));
    sc_assert(equal(true, b));
    b = 0;
    sc_assert(b != bt);
    sc_assert(b != 1);
    sc_assert(b != '1');
    sc_assert(b != true);
    sc_assert(1 != b);
    sc_assert('1' != b);
    sc_assert(true != b);
    sc_assert(not_equal(b, bt));
    sc_assert(not_equal(b, 1));
    sc_assert(not_equal(b, '1'));
    sc_assert(not_equal(b, true));
    sc_assert(not_equal(1, b));
    sc_assert(not_equal('1', b));
    sc_assert(not_equal(true, b));

    // the following assertion is incorrect, because the b_not() method
    // is destructive, i.e., it implements something like b ~= void.
    b.b_not();
    sc_assert(b);
    sc_bit bx;
    b_not(bx, b0);
    sc_assert(bx);
    b_not(bx, b1);
    sc_assert(!bx);

    cout << (b0|b0) << (b0|b1) << (b1|b0) << (b1|b1) << endl;
    cout << (b0&b0) << (b0&b1) << (b1&b0) << (b1&b1) << endl;
    cout << (b0^b0) << (b0^b1) << (b1^b0) << (b1^b1) << endl;

    cout << (b0|0) << (b0|1) << (b1|0) << (b1|1) << endl;
    cout << (b0&0) << (b0&1) << (b1&0) << (b1&1) << endl;
    cout << (b0^0) << (b0^1) << (b1^0) << (b1^1) << endl;

    cout << (b0|'0') << (b0|'1') << (b1|'0') << (b1|'1') << endl;
    cout << (b0&'0') << (b0&'1') << (b1&'0') << (b1&'1') << endl;
    cout << (b0^'0') << (b0^'1') << (b1^'0') << (b1^'1') << endl;

    cout << (b0|true) << (b0|false) << (b1|true) << (b1|false) << endl;
    cout << (b0&true) << (b0&false) << (b1&true) << (b1&false) << endl;
    cout << (b0^true) << (b0^false) << (b1^true) << (b1^false) << endl;

    cout << (0|b0) << (0|b1) << (1|b0) << (1|b1) << endl;
    cout << (0&b0) << (0&b1) << (1&b0) << (1&b1) << endl;
    cout << (0^b0) << (0^b1) << (1^b0) << (1^b1) << endl;

    cout << ('0'|b0) << ('0'|b1) << ('1'|b0) << ('1'|b1) << endl;
    cout << ('0'&b0) << ('0'&b1) << ('1'&b0) << ('1'&b1) << endl;
    cout << ('0'^b0) << ('0'^b1) << ('1'^b0) << ('1'^b1) << endl;

    cout << (false|b0) << (false|b1) << (true|b0) << (true|b1) << endl;
    cout << (false&b0) << (false&b1) << (true&b0) << (true&b1) << endl;
    cout << (false^b0) << (false^b1) << (true^b0) << (true^b1) << endl;

    cout << b_or(b0,b0) << b_or(b0,b1) << b_or(b1,b0) << b_or(b1,b1) << endl;
    cout << b_and(b0,b0) << b_and(b0,b1) << b_and(b1,b0) << b_and(b1,b1)
         << endl;
    cout << b_xor(b0,b0) << b_xor(b0,b1) << b_xor(b1,b0) << b_xor(b1,b1)
         << endl;

    cout << b_or(b0,0) << b_or(b0,1) << b_or(b1,0) << b_or(b1,1) << endl;
    cout << b_and(b0,0) << b_and(b0,1) << b_and(b1,0) << b_and(b1,1) << endl;
    cout << b_xor(b0,0) << b_xor(b0,1) << b_xor(b1,0) << b_xor(b1,1) << endl;

    cout << b_or(b0,'0') << b_or(b0,'1') << b_or(b1,'0') << b_or(b1,'1')
         << endl;
    cout << b_and(b0,'0') << b_and(b0,'1') << b_and(b1,'0') << b_and(b1,'1')
         << endl;
    cout << b_xor(b0,'0') << b_xor(b0,'1') << b_xor(b1,'0') << b_xor(b1,'1')
         << endl;

    cout << b_or(b0,false) << b_or(b0,true) << b_or(b1,false) << b_or(b1,true)
         << endl;
    cout << b_and(b0,false) << b_and(b0,true) << b_and(b1,false)
         << b_and(b1,true) << endl;
    cout << b_xor(b0,false) << b_xor(b0,true) << b_xor(b1,false)
         << b_xor(b1,true) << endl;

    cout << b_or(0,b0) << b_or(0,b1) << b_or(1,b0) << b_or(1,b1) << endl;
    cout << b_and(0,b0) << b_and(0,b1) << b_and(1,b0) << b_and(1,b1) << endl;
    cout << b_xor(0,b0) << b_xor(0,b1) << b_xor(1,b0) << b_xor(1,b1) << endl;

    cout << b_or('0',b0) << b_or('0',b1) << b_or('1',b0) << b_or('1',b1)
         << endl;
    cout << b_and('0',b0) << b_and('0',b1) << b_and('1',b0) << b_and('1',b1)
         << endl;
    cout << b_xor('0',b0) << b_xor('0',b1) << b_xor('1',b0) << b_xor('1',b1)
         << endl;

    cout << b_or(false,b0) << b_or(false,b1) << b_or(true,b0) << b_or(true,b1)
         << endl;
    cout << b_and(false,b0) << b_and(false,b1) << b_and(true,b0)
         << b_and(true,b1) << endl;
    cout << b_xor(false,b0) << b_xor(false,b1) << b_xor(true,b0)
         << b_xor(true,b1) << endl;

    b_or(b, b0, b1);
    sc_assert(b);
    b_and(b, b0, b1);
    sc_assert(!b);
    b_xor(b, b0, b1);
    sc_assert(b);
}

int
sc_main(int, char*[])
{
    cover_sc_bit();
    return 0;
}


try {
    level_ptr = nullptr;
    value_of(level_ptr);
  } catch(const std::exception& e) {
    printf("Exception: %s\n", e.what());
  }

#include <cstdio>
#include <stdexcept>
#include <type_traits>

template <typename T>
auto value_of(T x) {
  if constexpr(std::is_pointer<T>::value) {
    if(!x)
      throw std::runtime_error{ "Null pointer dereference." };
    return *x;
  } else {
    return x;
  }
}

int main() {
  unsigned long level{ 8998 };
  auto level_ptr = &level;
  auto& level_ref = level;
  printf("Power level = %lu\n", value_of(level_ptr));
  ++*level_ptr;
  printf("Power level = %lu\n", value_of(level_ref));
  ++level_ref;
  printf("It's over %lu!\n", value_of(level++));


try
                {
                    sk_ = new seal::SecretKey();
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }

#include "sealnet/SecretKeyWrapper.h"
#include "sealnet/Common.h"

using namespace std;
using namespace System;
using namespace System::IO;
using namespace System::Collections::Generic;

namespace seal
{
    /**
    <summary>Enables access to private members of seal::SecretKey.</summary>
    */
    struct SecretKey::SecretKeyPrivateHelper
    {
        static seal::BigPoly &data(seal::SecretKey *sk)
        {
            return sk->mutable_data();
        }

        static seal::EncryptionParameters::hash_block_type &hash_block(seal::SecretKey *sk)
        {
            return sk->mutable_hash_block();
        }
    };
}

namespace Microsoft
{
    namespace Research
    {
        namespace SEAL
        {
            SecretKey::SecretKey()
            {

            }

            SecretKey::SecretKey(SecretKey ^copy)
            {
                if (copy == nullptr)
                {
                    throw gcnew ArgumentNullException("copy cannot be null");
                }
                try
                {
                    sk_ = new seal::SecretKey(copy->GetKey());
                    GC::KeepAlive(copy);
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }
            }

            void SecretKey::Set(SecretKey ^assign)
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                if (assign == nullptr)
                {
                    throw gcnew ArgumentNullException("assign cannot be null");
                }
                try
                {
                    *sk_ = *assign->sk_;
                    GC::KeepAlive(assign);
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }
            }

            BigPoly ^SecretKey::Data::get()
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                return gcnew BigPoly(seal::SecretKey::SecretKeyPrivateHelper::data(sk_));
            }

            void SecretKey::Save(Stream ^stream)
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                if (stream == nullptr)
                {
                    throw gcnew ArgumentNullException("stream cannot be null");
                }
                try
                {
                    Write(stream, reinterpret_cast<const char*>(&seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)),
                        sizeof(seal::EncryptionParameters::hash_block_type));
                    auto poly = gcnew BigPoly(&seal::SecretKey::SecretKeyPrivateHelper::data(sk_));
                    poly->Save(stream);
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }
            }

            void SecretKey::Load(Stream ^stream)
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                if (stream == nullptr)
                {
                    throw gcnew ArgumentNullException("stream cannot be null");
                }
                try
                {
                    Read(stream, reinterpret_cast<char*>(&seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)),
                        sizeof(seal::EncryptionParameters::hash_block_type));
                    auto poly = gcnew BigPoly(&seal::SecretKey::SecretKeyPrivateHelper::data(sk_));
                    poly->Load(stream);
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }
            }

            SecretKey::~SecretKey()
            {
                this->!SecretKey();
            }

            SecretKey::!SecretKey()
            {
                if (sk_ != nullptr)
                {
                    delete sk_;
                    sk_ = nullptr;
                }
            }

            Tuple<UInt64, UInt64, UInt64, UInt64> ^SecretKey::HashBlock::get()
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                return gcnew Tuple<UInt64, UInt64, UInt64, UInt64>(
                    seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)[0],
                    seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)[1],
                    seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)[2],
                    seal::SecretKey::SecretKeyPrivateHelper::hash_block(sk_)[3]);
            }

            SecretKey::SecretKey(const seal::SecretKey &ciphertext) : sk_(nullptr)
            {
                try
                {
                    sk_ = new seal::SecretKey(ciphertext);
                }
                catch (const exception &e)
                {
                    HandleException(&e);
                }
                catch (...)
                {
                    HandleException(nullptr);
                }
            }

            seal::SecretKey &SecretKey::GetKey()
            {
                if (sk_ == nullptr)
                {
                    throw gcnew ObjectDisposedException("SecretKey is disposed");
                }
                return *sk_;
            }
        }
    }
}


try
			{
				bSuccess=OnEventCenterSocketRead(pCenterSocketRead->Command,pCenterSocketRead->cbReadBuffer,pCenterSocketRead->wDataSize);
			}
			catch (...)	{ }

#include "StdAfx.h"
#include "AttemperEngineSink.h"

//宏定义
#define TIME_RECONNECT						15000L						//重连时间
#define TIME_UPDATE_LIST					30000L						//更新时间

//定时器 ID
#define IDI_CONNECT_CENTER_SERVER			1							//连接服务器
#define IDI_UPDATE_SERVER_LIST				2							//更新列表

void WriteLog(CString strFileName, CString strText)
{
	try
	{
        CTime tm = CTime::GetCurrentTime();
        CString strTime = tm.Format(_T("%Y-%m-%d %H:%M:%S"));
		//BOOL bFull = FALSE;
		CStdioFile file;
		if( file.Open(strFileName, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite) != 0)
		{
			file.SeekToEnd();
			file.WriteString(strTime);
			file.WriteString(strText);
			file.WriteString(_T("\n\n"));
			file.Close();
		}
		/*
		if(!bFull) return;
		if( file.Open(strFileName, CFile::modeCreate|CFile::modeReadWrite) != 0)
		{
		file.SeekToEnd();
		file.WriteString(strTime);
		file.WriteString(strText);
		file.WriteString(_T("\n"));
		file.Close();
		}
		*/
	}
	catch(...)
	{
	}
}

//构造函数
CAttemperEngineSink::CAttemperEngineSink()
{
	//设置变量
	m_pInitParamter=NULL;
	m_pConnectItemInfo=NULL;

	//中心服务器
	m_pCenterSocket=NULL;
	m_SocketState=SocketState_NoConnect;

	//接口变量
	m_pITimerEngine=NULL;
	m_pIEventService=NULL;
	m_pITCPSocketEngine=NULL;

	return;
}

//析构函数
CAttemperEngineSink::~CAttemperEngineSink()
{
}

//接口查询
void * __cdecl CAttemperEngineSink::QueryInterface(const IID & Guid, DWORD dwQueryVer)
{
	QUERYINTERFACE(IAttemperEngineSink,Guid,dwQueryVer);
	QUERYINTERFACE_IUNKNOWNEX(IAttemperEngineSink,Guid,dwQueryVer);
	return NULL;
}

//调度模块启动
bool __cdecl CAttemperEngineSink::StartService(IUnknownEx * pIUnknownEx)
{
	//效验参数
	ASSERT(pIUnknownEx!=NULL);
	ASSERT(m_pInitParamter!=NULL);
	ASSERT(m_pIEventService!=NULL);

	//创建辅助变量
	m_pConnectItemInfo=new tagConnectItemInfo [m_pInitParamter->m_wMaxConnect];
	if (m_pConnectItemInfo==NULL) return false;
	memset(m_pConnectItemInfo,0,sizeof(tagConnectItemInfo)*m_pInitParamter->m_wMaxConnect);

	//连接中心服务器
	DWORD dwServerIP=inet_addr(m_pInitParamter->m_szCenterServerAddr);
	m_pCenterSocket->Connect(dwServerIP,PORT_CENTER_SERVER);

	return true;
}

//调度模块关闭
bool __cdecl CAttemperEngineSink::StopService(IUnknownEx * pIUnknownEx)
{
	//删除数据
	SafeDeleteArray(m_pConnectItemInfo);

	return true;
}

//事件处理接口
bool __cdecl CAttemperEngineSink::OnAttemperEvent(WORD wIdentifier, void * pDataBuffer, WORD wDataSize, DWORD dwInsertTime)
{
	switch (wIdentifier)
	{
	case EVENT_CENTER_CONNECT:	//中心连接事件
		{
			//效验大小
			ASSERT(wDataSize==sizeof(NTY_CenterConnect));
			if (wDataSize!=sizeof(NTY_CenterConnect)) return false;

			//消息处理
			NTY_CenterConnect * pCenterSocketConnect=(NTY_CenterConnect *)pDataBuffer;

			return OnEventCenterSocketConnect(pCenterSocketConnect->iErrorCode);
		}
	case EVENT_CENTER_READ:		//中心读取事件
		{
			//效验大小
			NTY_CenterRead * pCenterSocketRead=(NTY_CenterRead *)pDataBuffer;
			ASSERT(wDataSize>=((sizeof(NTY_CenterRead)-sizeof(pCenterSocketRead->cbReadBuffer))));
			ASSERT(wDataSize==(sizeof(NTY_CenterRead)-sizeof(pCenterSocketRead->cbReadBuffer)+pCenterSocketRead->wDataSize));
			if (wDataSize<(sizeof(NTY_CenterRead)-sizeof(pCenterSocketRead->cbReadBuffer))) return false;
			if (wDataSize!=sizeof(NTY_CenterRead)-sizeof(pCenterSocketRead->cbReadBuffer)+pCenterSocketRead->wDataSize) return false;

			//处理消息
			bool bSuccess=false;

			if (bSuccess==false) m_pCenterSocket->CloseSocket(true);

			return true;
		}
	case EVENT_CENTER_CLOSE:		//中心关闭事件
		{
			//效验大小
			ASSERT(wDataSize==sizeof(NTY_CenterClose));
			if (wDataSize!=sizeof(NTY_CenterClose)) return false;

			//消息处理
			NTY_CenterClose * pCenterSocketClose=(NTY_CenterClose *)pDataBuffer;
			OnEventCenterSocketClose(pCenterSocketClose->bCloseByServer);

			return true;
		}
	}

	return false;
}

//设置事件
bool CAttemperEngineSink::SetEventService(IUnknownEx * pIUnknownEx)
{
	//查询接口
	ASSERT(pIUnknownEx!=NULL);
	m_pIEventService=GET_OBJECTPTR_INTERFACE(pIUnknownEx,IEventService);
	ASSERT(m_pIEventService!=NULL);

	//设置接口
	m_ServerList.SetEventService(m_pIEventService);

	return (m_pIEventService!=NULL);
}

//配置函数
bool CAttemperEngineSink::InitAttemperSink(CInitParamter * pInitParamter, CCenterSocket * pCenterSocket, IUnknownEx * pIUnknownEx)
{
	//效验参数
	ASSERT(pIUnknownEx!=NULL);
	ASSERT(pInitParamter!=NULL);
	ASSERT(pCenterSocket!=NULL);

	//设置变量
	m_pInitParamter=pInitParamter;
	m_pCenterSocket=pCenterSocket;

	//服务引擎
	IServiceEngine * pIServiceEngine=(IServiceEngine *)pIUnknownEx->QueryInterface(IID_IServiceEngine,VER_IServiceEngine);
	if (pIServiceEngine==NULL)
	{
		m_pIEventService->ShowEventNotify(TEXT("获取服务引擎服务失败"),Level_Exception);
		return false;
	}

	//定时器引擎
	m_pITimerEngine=(ITimerEngine *)pIServiceEngine->GetTimerEngine(IID_ITimerEngine,VER_ITimerEngine);
	if (m_pITimerEngine==NULL)
	{
		m_pIEventService->ShowEventNotify(TEXT("获取定时器引擎服务失败"),Level_Exception);
		return false;
	}

	//网络引擎
	m_pITCPSocketEngine=(ITCPSocketEngine *)pIServiceEngine->GetTCPSocketEngine(IID_ITCPSocketEngine,VER_ITCPSocketEngine);
	if (m_pITCPSocketEngine==NULL)
	{
		m_pIEventService->ShowEventNotify(TEXT("获取网络引擎服务失败"),Level_Exception);
		return false;
	}

	//数据库引擎
	IDataBaseEngine * pIDataBaseEngine=(IDataBaseEngine *)pIServiceEngine->GetDataBaseEngine(IID_IDataBaseEngine,VER_IDataBaseEngine);
	if (pIDataBaseEngine==NULL)
	{
		m_pIEventService->ShowEventNotify(TEXT("获取数据库引擎服务失败"),Level_Exception);
		return false;
	}

	//数据库触发
	IUnknownEx * pIQueueService=(IUnknownEx *)pIDataBaseEngine->GetQueueService(IID_IUnknownEx,VER_IUnknownEx);
	if (m_DataBaseEvent.SetQueueService(pIQueueService)==false)
	{
		m_pIEventService->ShowEventNotify(TEXT("获取数据库触发服务失败"),Level_Exception);
		return false;
	}

	//列表组件
	if (m_ServerList.SetSocketEngine(m_pITCPSocketEngine)==false)
	{
		m_pIEventService->ShowEventNotify(TEXT("列表组件与网络引擎绑定失败"),Level_Exception);
		return false;
	}

	return true;
}

//定时器事件
bool CAttemperEngineSink::OnEventTimer(WORD wTimerID, WPARAM wBindParam)
{
	switch (wTimerID)
	{
	case IDI_CONNECT_CENTER_SERVER:		//连接中心服务器
		{
			DWORD dwServerIP=inet_addr(m_pInitParamter->m_szCenterServerAddr);
			m_pCenterSocket->Connect(dwServerIP,PORT_CENTER_SERVER);
			return true;
		}
	case IDI_UPDATE_SERVER_LIST:		//更新服务器列表
		{
			if (m_SocketState==SocketState_Connected)
			{
				m_pCenterSocket->SendData(MDM_CS_SERVER_LIST,SUB_CS_GET_SERVER_LIST,NULL,0);
			}
			return true;
		}
	}
	return false;
}

//数据库事件
bool CAttemperEngineSink::OnEventDataBase(void * pDataBuffer, WORD wDataSize, NTY_DataBaseEvent * pDataBaseEvent)
{
	switch (pDataBaseEvent->wRequestID)
	{
	case DBR_GP_LOGON_SUCCESS:		//登录成功
		{
			return OnDBLogonSuccess(pDataBuffer,wDataSize,pDataBaseEvent);
		}
	case DBR_GP_LOGON_ERROR:		//登录失败
		{
			return OnDBLogonError(pDataBuffer,wDataSize,pDataBaseEvent);
		}
	}

	return false;
}

//用户登录成功
bool CAttemperEngineSink::OnDBLogonSuccess(void * pDataBuffer, WORD wDataSize, NTY_DataBaseEvent * pDataBaseEvent)
{
	//效验参数
	ASSERT(pDataBaseEvent->wRequestID==DBR_GP_LOGON_SUCCESS);
	ASSERT(wDataSize==sizeof(DBR_GP_LogonSuccess));
	if (wDataSize!=sizeof(DBR_GP_LogonSuccess)) return false;

	//判断在线
	ASSERT(pDataBaseEvent->wIndex<m_pInitParamter->m_wMaxConnect);
	tagConnectItemInfo * pConnectItemInfo=(m_pConnectItemInfo+pDataBaseEvent->wIndex);
	if (pConnectItemInfo->bConnect==FALSE) return true;
	if (pConnectItemInfo->wRoundID!=pDataBaseEvent->wRoundID) return true;

	//构造数据
	BYTE cbBuffer[SOCKET_PACKAGE];
	CMD_GP_LogonSuccess * pCMDLogonSuccess=(CMD_GP_LogonSuccess *)cbBuffer;
	DBR_GP_LogonSuccess * pDBRLogonSuccess=(DBR_GP_LogonSuccess *)pDataBuffer;
	pCMDLogonSuccess->cbGender=pDBRLogonSuccess->cbGender;
	pCMDLogonSuccess->cbMember=pDBRLogonSuccess->cbMember;
	pCMDLogonSuccess->wFaceID=pDBRLogonSuccess->wFaceID;
	pCMDLogonSuccess->dwUserID=pDBRLogonSuccess->dwUserID;
	pCMDLogonSuccess->dwGroupID=pDBRLogonSuccess->dwGroupID;
	pCMDLogonSuccess->dwExperience=pDBRLogonSuccess->dwExperience;
	pCMDLogonSuccess->dwUserRight=pDBRLogonSuccess->dwUserRight;
	pCMDLogonSuccess->dwMasterRight=pDBRLogonSuccess->dwMasterRight;

	//叠加数据
	CSendPacketHelper SendPacket(cbBuffer+sizeof(CMD_GP_LogonSuccess),sizeof(cbBuffer)-sizeof(CMD_GP_LogonSuccess));
	SendPacket.AddPacket(pDBRLogonSuccess->szAccounts,CountString(pDBRLogonSuccess->szAccounts),DTP_USER_ACCOUNTS);
	SendPacket.AddPacket(pDBRLogonSuccess->szPassWord,CountString(pDBRLogonSuccess->szPassWord),DTP_USER_PASS);

	//社团信息
	if (pDBRLogonSuccess->dwGroupID!=0L)
	{
		ASSERT(pDBRLogonSuccess->szGroupName[0]!=0);
		SendPacket.AddPacket(pDBRLogonSuccess->szGroupName,CountString(pDBRLogonSuccess->szGroupName),DTP_USER_GROUP_NAME);
	}

	//站点主页
	if (m_pInitParamter->m_szMainPage[0]!=0)
	{
		SendPacket.AddPacket(m_pInitParamter->m_szMainPage,CountString(m_pInitParamter->m_szMainPage),DTP_STATION_PAGE);
	}

	//发送登录结果
	WORD wIndex=pDataBaseEvent->wIndex;
	WORD wRoundID=pDataBaseEvent->wRoundID;
	WORD wSendSize=sizeof(CMD_GP_LogonSuccess)+SendPacket.GetDataSize();
	m_pITCPSocketEngine->SendData(wIndex,wRoundID,MDM_GP_LOGON,SUB_GP_LOGON_SUCCESS,cbBuffer,wSendSize);

	//列表配置
	CMD_GP_ListConfig ListConfig;
	ListConfig.bShowOnLineCount=TRUE;
	m_pITCPSocketEngine->SendData(wIndex,wRoundID,MDM_GP_SERVER_LIST,SUB_GP_LIST_CONFIG,&ListConfig,sizeof(ListConfig));

	//发送游戏列表
	m_ServerList.SendGameTypeList(wIndex,wRoundID);
	m_ServerList.SendGameKindList(wIndex,wRoundID);
	m_ServerList.SendGameStationList(wIndex,wRoundID);
	m_ServerList.SendGameServerList(wIndex,wRoundID);

	//发送登录完成
	m_pITCPSocketEngine->SendData(wIndex,wRoundID,MDM_GP_LOGON,SUB_GP_LOGON_FINISH);

	//关闭连接
	m_pITCPSocketEngine->ShutDownSocket(wIndex,wRoundID);

	return true;
}

//用户登录失败
bool CAttemperEngineSink::OnDBLogonError(void * pDataBuffer, WORD wDataSize, NTY_DataBaseEvent * pDataBaseEvent)
{
	//效验参数
	ASSERT(pDataBaseEvent->wRequestID==DBR_GP_LOGON_ERROR);
	ASSERT(wDataSize==sizeof(DBR_GP_LogonError));

	//判断在线
	ASSERT(pDataBaseEvent->wIndex<m_pInitParamter->m_wMaxConnect);
	tagConnectItemInfo * pConnectItemInfo=(m_pConnectItemInfo+pDataBaseEvent->wIndex);
	if (pConnectItemInfo->bConnect==FALSE) return true;
	if (pConnectItemInfo->wRoundID!=pDataBaseEvent->wRoundID) return true;

	//变量定义
	CMD_GP_LogonError LogonError;
	DBR_GP_LogonError * pLogonError=(DBR_GP_LogonError *)pDataBuffer;
	pLogonError->szErrorDescribe[CountString(pLogonError->szErrorDescribe)-1]=0;

	//构造数据
	LogonError.lErrorCode=pLogonError->lErrorCode;
	lstrcpyn(LogonError.szErrorDescribe,pLogonError->szErrorDescribe,sizeof(LogonError.szErrorDescribe));
	WORD wDescribeSize=CountString(LogonError.szErrorDescribe);

	//发送数据
	WORD wSendSize=sizeof(LogonError)-sizeof(LogonError.szErrorDescribe)+wDescribeSize;
	m_pITCPSocketEngine->SendData(pDataBaseEvent->wIndex,pDataBaseEvent->wRoundID,MDM_GP_LOGON,
		SUB_GP_LOGON_ERROR,&LogonError,wSendSize);

	//关闭连接
	m_pITCPSocketEngine->ShutDownSocket(pDataBaseEvent->wIndex,pDataBaseEvent->wRoundID);

	return true;
}

//网络应答事件
bool __cdecl CAttemperEngineSink::OnEventSocketAccept(NTY_SocketAcceptEvent * pSocketAcceptEvent)
{
	//效验参数
	ASSERT(pSocketAcceptEvent->wIndex<m_pInitParamter->m_wMaxConnect);

	//设置数据
	tagConnectItemInfo * pConnectItemInfo=m_pConnectItemInfo+pSocketAcceptEvent->wIndex;
	pConnectItemInfo->bConnect=TRUE;
	pConnectItemInfo->wRoundID=pSocketAcceptEvent->wRoundID;
	pConnectItemInfo->dwClientIP=pSocketAcceptEvent->dwClientIP;

	return true;
}

//网络读取事件
bool __cdecl CAttemperEngineSink::OnEventSocketRead(CMD_Command Command,
													void * pDataBuffer,
													WORD wDataSize,
													NTY_SocketReadEvent * pSocketReadEvent)
{
	switch (Command.wMainCmdID)
	{
	//登录消息
	case MDM_GP_LOGON:
		{
			return OnSocketMainLogon(Command,pDataBuffer,wDataSize,pSocketReadEvent);
		}
	}

	return false;
}

//网络关闭事件
bool __cdecl CAttemperEngineSink::OnEventSocketClose(NTY_SocketCloseEvent * pSocketCloseEvent)
{
	//效验参数
	ASSERT(pSocketCloseEvent->wIndex<m_pInitParamter->m_wMaxConnect);

	//设置数据
	tagConnectItemInfo * pConnectItemInfo=m_pConnectItemInfo+pSocketCloseEvent->wIndex;
	pConnectItemInfo->wRoundID++;
	pConnectItemInfo->dwClientIP=0;
	pConnectItemInfo->bConnect=FALSE;

	return true;
}

//中心连接事件
bool __cdecl CAttemperEngineSink::OnEventCenterSocketConnect(int iErrorCode)
{
	//错误判断
	if (iErrorCode!=0)
	{
		m_SocketState=SocketState_NoConnect;
		m_pITimerEngine->SetTimer(IDI_CONNECT_CENTER_SERVER,TIME_RECONNECT,1,NULL);
		return true;
	}

	//设置变量
	m_SocketState=SocketState_Connected;

	//获取列表
	m_pCenterSocket->SendData(MDM_CS_SERVER_LIST,SUB_CS_GET_SERVER_LIST,NULL,0);

	//设置定时器
	m_pITimerEngine->SetTimer(IDI_UPDATE_SERVER_LIST,TIME_UPDATE_LIST,TIMER_REPEAT_TIMER,NULL);

	return true;
}

//中心读取事件
bool __cdecl CAttemperEngineSink::OnEventCenterSocketRead(CMD_Command Command, void * pDataBuffer, WORD wDataSize)
{
	switch (Command.wMainCmdID)
	{
	case MDM_CS_SERVER_LIST:	//列表消息
		{
			return OnCenterMainServerList(Command,pDataBuffer,wDataSize);
		}
	}
	return true;
}

//中心关闭事件
bool __cdecl CAttemperEngineSink::OnEventCenterSocketClose(bool bCloseByServer)
{
	//设置变量
	m_SocketState=SocketState_NoConnect;
	m_pITimerEngine->KillTimer(IDI_UPDATE_SERVER_LIST);

	//重新连接
	if (bCloseByServer==true) m_pITimerEngine->SetTimer(IDI_CONNECT_CENTER_SERVER,TIME_RECONNECT,1,NULL);

	return true;
}

//登录消息处理
bool CAttemperEngineSink::OnSocketMainLogon(CMD_Command Command, void * pDataBuffer, WORD wDataSize, NTY_SocketReadEvent * pSocketReadEvent)
{
	CString strFile,strTemp;
	CTime tmCur = CTime::GetCurrentTime();
	CString strTime = tmCur.Format("%m%d");
	strFile.Format("log\\%sOnSocketMainLogon.log",strTime);

	strTemp.Format("into OnSocketMainLogon");
	WriteLog(strFile, strTemp);

	ASSERT(Command.wMainCmdID==MDM_GP_LOGON);
	switch (Command.wSubCmdID)
	{
	case SUB_GP_LOGON_ACCOUNTS:		//帐号登录
		{

	strTemp.Format("into 帐号登录");
	WriteLog(strFile, strTemp);

			//效验参数
			ASSERT(wDataSize>=sizeof(CMD_GP_LogonByAccounts));
			if (wDataSize<sizeof(CMD_GP_LogonByAccounts)) return false;

			//处理消息
			CMD_GP_LogonByAccounts * pLogonByAccounts=(CMD_GP_LogonByAccounts *)pDataBuffer;
			pLogonByAccounts->szAccounts[CountArray(pLogonByAccounts->szAccounts)-1]=0;
			pLogonByAccounts->szPassWord[CountArray(pLogonByAccounts->szPassWord)-1]=0;
			pLogonByAccounts->szRealityPass[CountArray(pLogonByAccounts->szRealityPass)-1]=0;

			//连接信息
			ASSERT(pSocketReadEvent->wIndex<m_pInitParamter->m_wMaxConnect);
			DWORD dwClientAddr=(m_pConnectItemInfo+pSocketReadEvent->wIndex)->dwClientIP;

	strTemp.Format("dwPlazaVersion=%d,%d", pLogonByAccounts->dwPlazaVersion, VER_PLAZA_FRAME);
	WriteLog(strFile, strTemp);

			//效验版本
			if (pLogonByAccounts->dwPlazaVersion!=VER_PLAZA_FRAME)
			{
				//获取版本
				WORD wLow=LOWORD(pLogonByAccounts->dwPlazaVersion);
				WORD wHigh=HIWORD(pLogonByAccounts->dwPlazaVersion);

				//构造数据
				CMD_GP_Version Version;
				Version.bNewVersion=TRUE;
				Version.bAllowConnect=(wHigh==VER_PLAZA_HIGH)?TRUE:FALSE;

				//发送数据
				WORD wIndex=pSocketReadEvent->wIndex;
				WORD wRountID=pSocketReadEvent->wRoundID;
				m_pITCPSocketEngine->SendData(wIndex,wRountID,MDM_GP_SYSTEM,SUB_GP_VERSION,&Version,sizeof(Version));

				//判断关闭
				if (Version.bAllowConnect==FALSE)
				{
					return true;
				}
			}

			//构造数据
			DBR_GP_LogonByAccounts LogonByAccounts;
			memset(&LogonByAccounts,0,sizeof(LogonByAccounts));
			LogonByAccounts.dwClientIP=dwClientAddr;
			lstrcpyn(LogonByAccounts.szAccounts,pLogonByAccounts->szAccounts,sizeof(LogonByAccounts.szAccounts));
			lstrcpyn(LogonByAccounts.szPassWord,pLogonByAccounts->szPassWord,sizeof(LogonByAccounts.szPassWord));
			lstrcpyn(LogonByAccounts.szRealityPass,pLogonByAccounts->szRealityPass,sizeof(LogonByAccounts.szRealityPass));

			//投递数据库
			m_DataBaseEvent.PostDataBaseEvent(DBR_GP_LOGON_BY_ACCOUNTS,pSocketReadEvent->wIndex,
				pSocketReadEvent->wRoundID,&LogonByAccounts,sizeof(LogonByAccounts));

			return true;
		}
	case SUB_GP_LOGON_USERID:		//ID 登录
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(CMD_GP_LogonByUserID));
			if (wDataSize<sizeof(CMD_GP_LogonByUserID)) return false;

			//处理消息
			CMD_GP_LogonByUserID * pLogonByUserID=(CMD_GP_LogonByUserID *)pDataBuffer;
			pLogonByUserID->szPassWord[CountArray(pLogonByUserID->szPassWord)-1]=0;

			//连接信息
			ASSERT(pSocketReadEvent->wIndex<m_pInitParamter->m_wMaxConnect);
			DWORD dwClientAddr=(m_pConnectItemInfo+pSocketReadEvent->wIndex)->dwClientIP;

	strTemp.Format("2 dwPlazaVersion=%d,%d", pLogonByUserID->dwPlazaVersion, VER_PLAZA_FRAME);
	WriteLog(strFile, strTemp);

			//效验版本
			if (pLogonByUserID->dwPlazaVersion!=VER_PLAZA_FRAME)
			{
				//获取版本
				WORD wLow=LOWORD(pLogonByUserID->dwPlazaVersion);
				WORD wHigh=HIWORD(pLogonByUserID->dwPlazaVersion);

				//构造数据
				CMD_GP_Version Version;
				Version.bNewVersion=TRUE;
				Version.bAllowConnect=(wHigh==VER_PLAZA_HIGH)?TRUE:FALSE;

				//发送数据
				WORD wIndex=pSocketReadEvent->wIndex;
				WORD wRountID=pSocketReadEvent->wRoundID;
				m_pITCPSocketEngine->SendData(wIndex,wRountID,MDM_GP_SYSTEM,SUB_GP_VERSION,&Version,sizeof(Version));

				//判断关闭
				if (Version.bAllowConnect==FALSE)
				{
					return true;
				}
			}

			//构造数据
			DBR_GP_LogonByUserID LogonByUserID;
			memset(&LogonByUserID,0,sizeof(LogonByUserID));
			LogonByUserID.dwClientIP=dwClientAddr;
			LogonByUserID.dwUserID=pLogonByUserID->dwUserID;
			lstrcpyn(LogonByUserID.szPassWord,pLogonByUserID->szPassWord,sizeof(LogonByUserID.szPassWord));

			//投递数据库
			m_DataBaseEvent.PostDataBaseEvent(DBR_GP_LOGON_BY_USERID,pSocketReadEvent->wIndex,
				pSocketReadEvent->wRoundID,&LogonByUserID,sizeof(LogonByUserID));

			return true;
		}
	case SUB_GP_REGISTER_ACCOUNTS:		//注册帐号
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(CMD_GP_RegisterAccounts));
			if (wDataSize<sizeof(CMD_GP_RegisterAccounts)) return false;

			//处理消息
			CMD_GP_RegisterAccounts * pRegisterAccounts=(CMD_GP_RegisterAccounts *)pDataBuffer;
			pRegisterAccounts->szAccounts[CountArray(pRegisterAccounts->szAccounts)-1]=0;
			pRegisterAccounts->szPassWord[CountArray(pRegisterAccounts->szPassWord)-1]=0;

			//连接信息
			ASSERT(pSocketReadEvent->wIndex<m_pInitParamter->m_wMaxConnect);
			DWORD dwClientAddr=(m_pConnectItemInfo+pSocketReadEvent->wIndex)->dwClientIP;

			//效验版本
			if (pRegisterAccounts->dwPlazaVersion!=VER_PLAZA_FRAME)
			{
				//获取版本
				WORD wLow=LOWORD(pRegisterAccounts->dwPlazaVersion);
				WORD wHigh=HIWORD(pRegisterAccounts->dwPlazaVersion);

				//构造数据
				CMD_GP_Version Version;
				Version.bNewVersion=TRUE;
				Version.bAllowConnect=(wHigh==VER_PLAZA_HIGH)?TRUE:FALSE;

				//发送数据
				WORD wIndex=pSocketReadEvent->wIndex;
				WORD wRountID=pSocketReadEvent->wRoundID;
				m_pITCPSocketEngine->SendData(wIndex,wRountID,MDM_GP_SYSTEM,SUB_GP_VERSION,&Version,sizeof(Version));

				//判断关闭
				if (Version.bAllowConnect==FALSE)
				{
					m_pITCPSocketEngine->ShutDownSocket(wIndex,wRountID);
					return true;
				}
			}

			//构造数据
			DBR_GP_RegisterAccounts RegisterAccounts;
			memset(&RegisterAccounts,0,sizeof(RegisterAccounts));
			RegisterAccounts.dwClientIP=dwClientAddr;
			RegisterAccounts.wFaceID=pRegisterAccounts->wFaceID;
			lstrcpyn(RegisterAccounts.szAccounts,pRegisterAccounts->szAccounts,sizeof(RegisterAccounts.szAccounts));
			lstrcpyn(RegisterAccounts.szPassWord,pRegisterAccounts->szPassWord,sizeof(RegisterAccounts.szPassWord));

			//投递数据库
			m_DataBaseEvent.PostDataBaseEvent(DBR_GP_REGISTER_ACCOUNTS,pSocketReadEvent->wIndex,
				pSocketReadEvent->wRoundID,&RegisterAccounts,sizeof(RegisterAccounts));

			return true;
		}
	}
	return false;
}

//列表消息处理
bool CAttemperEngineSink::OnCenterMainServerList(CMD_Command Command, void * pDataBuffer, WORD wDataSize)
{
	ASSERT(Command.wMainCmdID==MDM_CS_SERVER_LIST);
	switch (Command.wSubCmdID)
	{
	case SUB_CS_LIST_INFO:		//列表信息
		{
			//效验参数
			ASSERT(wDataSize==sizeof(CMD_CS_ListInfo));
			if (wDataSize!=sizeof(CMD_CS_ListInfo)) return false;

			//消息处理
			m_ServerList.ResetServerListBuffer();

			return true;
		}
	case SUB_CS_LIST_TYPE:		//种类信息
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(tagGameType));
			ASSERT(wDataSize%sizeof(tagGameType)==0);

			//消息处理
			DWORD dwCount=wDataSize/sizeof(tagGameType);
			tagGameType * pGameType=(tagGameType *)pDataBuffer;
			m_ServerList.AppendGameTypeBuffer(pGameType,dwCount);

			return true;
		}
	case SUB_CS_LIST_KIND:		//类型信息
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(tagGameKind));
			ASSERT(wDataSize%sizeof(tagGameKind)==0);

			//消息处理
			DWORD dwCount=wDataSize/sizeof(tagGameKind);
			tagGameKind * pGameKind=(tagGameKind *)pDataBuffer;
			m_ServerList.AppendGameKindBuffer(pGameKind,dwCount);

			return true;
		}
	case SUB_CS_LIST_STATION:	//站点信息
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(tagGameStation));
			ASSERT(wDataSize%sizeof(tagGameStation)==0);

			//消息处理
			DWORD dwCount=wDataSize/sizeof(tagGameStation);
			tagGameStation * pGameStation=(tagGameStation *)pDataBuffer;
			m_ServerList.AppendGameStationBuffer(pGameStation,dwCount);

			return true;
		}
	case SUB_CS_LIST_SERVER:	//房间信息
		{
			//效验参数
			ASSERT(wDataSize>=sizeof(tagGameServer));
			ASSERT(wDataSize%sizeof(tagGameServer)==0);

			//消息处理
			DWORD dwCount=wDataSize/sizeof(tagGameServer);
			tagGameServer * pGameServer=(tagGameServer *)pDataBuffer;
			m_ServerList.AppendGameServerBuffer(pGameServer,dwCount);

			return true;
		}
	case SUB_CS_LIST_FINISH:	//更新完成
		{
			//消息处理
			m_ServerList.ActiveServerListBuffer();

			return true;
		}
	}

	return true;
}


try{
            while (1)
            {
                // This will throw if we've run out of frames
                auto fi = NextFrame();
                PacketStreamSource& s = _sources[fi.src];
                PANGO_ENSURE(s.index.size() == fi.sequence_num);
                s.index.push_back({fi.frame_streampos, fi.time});
            }
        }catch(...){
        }

/* This file is part of the Pangolin Project.
 * http://example.com
 *
 */

#include <pangolin/log/packetstream_reader.h>
#include <pangolin/log/packetstream_writer.h>

using std::string;
using std::istream;
using std::ios;
using std::lock_guard;
using std::runtime_error;
using std::ios_base;
using std::streampos;
using std::streamoff;

#include <thread>

#ifndef _WIN_
#  include <unistd.h>
#endif

namespace pangolin
{

PacketStreamReader::PacketStreamReader()
    : _pipe_fd(-1)
{
}

PacketStreamReader::PacketStreamReader(const std::string& filename)
    : _pipe_fd(-1)
{
    Open(filename);
}

PacketStreamReader::~PacketStreamReader()
{
    Close();
}

void PacketStreamReader::Open(const std::string& filename)
{
    std::lock_guard<std::recursive_mutex> lg(_mutex);

    Close();

    _filename = filename;
    _is_pipe = IsPipe(filename);
    _stream.open(filename);

    if (!_stream.is_open())
        throw runtime_error("Cannot open stream.");

    for (auto i : PANGO_MAGIC)
    {
        if (_stream.get() != i)
            throw runtime_error("Unrecognised file header.");
        if (!_stream.good())
            throw runtime_error("Bad stream");
    }

    ParseHeader();

    while (_stream.peekTag() == TAG_ADD_SOURCE) {
        ParseNewSource();
    }

    if(!SetupIndex()) {
        FixFileIndex();
    }
}

void PacketStreamReader::Close() {
    std::lock_guard<std::recursive_mutex> lg(_mutex);

    _stream.close();
    _sources.clear();

#ifndef _WIN_
    if (_pipe_fd != -1) {
        close(_pipe_fd);
    }
#endif
}

void PacketStreamReader::ParseHeader()
{
    _stream.readTag(TAG_PANGO_HDR);

    picojson::value json_header;
    picojson::parse(json_header, _stream);

    // File timestamp
    const int64_t start_us = json_header["time_us"].get<int64_t>();
    packet_stream_start = SyncTime::TimePoint() + std::chrono::microseconds(start_us);

    _stream.get(); // consume newline
}

void PacketStreamReader::ParseNewSource()
{
    _stream.readTag(TAG_ADD_SOURCE);
    picojson::value json;
    picojson::parse(json, _stream);
    _stream.get(); // consume newline

    const size_t src_id = json[pss_src_id].get<int64_t>();

    if(_sources.size() <= src_id) {
        _sources.resize(src_id+1);
    }

    PacketStreamSource& pss = _sources[src_id];
    pss.id = src_id;
    pss.driver = json[pss_src_driver].get<string>();
    pss.uri = json[pss_src_uri].get<string>();
    pss.info = json[pss_src_info];
    pss.version = json[pss_src_version].get<int64_t>();
    pss.data_alignment_bytes = json[pss_src_packet][pss_pkt_alignment_bytes].get<int64_t>();
    pss.data_definitions = json[pss_src_packet][pss_pkt_definitions].get<string>();
    pss.data_size_bytes = json[pss_src_packet][pss_pkt_size_bytes].get<int64_t>();
}

bool PacketStreamReader::SetupIndex()
{
    bool index_good = false;

    if (_stream.seekable())
    {
        // Save current position
        std::streampos pos = _stream.tellg();

        // Look for footer at end of file (TAG_PANGO_FOOTER + index position).
        _stream.seekg(-(static_cast<istream::off_type>(sizeof(uint64_t)) + TAG_LENGTH), ios_base::end);
        if (_stream.peekTag() == TAG_PANGO_FOOTER)
        {
            //parsing the footer returns the index position
            _stream.seekg(ParseFooter());
            if (_stream.peekTag() == TAG_PANGO_STATS) {
                // Read the pre-build index from the file
                index_good = ParseIndex();
            }
        }

        // Restore previous location
        _stream.clear();
        _stream.seekg(pos);
    }

    return index_good;
}

streampos PacketStreamReader::ParseFooter() //returns position of index.
{
    _stream.readTag(TAG_PANGO_FOOTER);
    uint64_t index=0;
    size_t bytes_read = _stream.read(reinterpret_cast<char*>(&index), sizeof(index));
    PANGO_ENSURE(bytes_read == sizeof(index));
    return index;
}

bool PacketStreamReader::ParseIndex()
{
    _stream.readTag(TAG_PANGO_STATS);
    picojson::value json;
    picojson::parse(json, _stream);

    const bool index_good = json.contains("src_packet_index") && json.contains("src_packet_times");

    if (index_good)
    {
        // This is a two-dimensional serialized array, [source id][sequence number] ---> packet position in stream
        const auto& json_index = json["src_packet_index"].get<picojson::array>();
        const auto& json_times = json["src_packet_times"].get<picojson::array>();

        // We shouldn't have seen more sources than exist in the index
        PANGO_ENSURE(_sources.size() <= json_index.size());
        PANGO_ENSURE(json_index.size() == json_times.size());

        _sources.resize(json_index.size());

        // Populate index
        for(size_t i=0; i < _sources.size(); ++i) {
            PANGO_ENSURE(json_index[i].size() == json_times[i].size());
            _sources[i].index.resize(json_index[i].size());
            for(size_t f=0; f < json_index[i].size(); ++f) {
                _sources[i].index[f].pos = json_index[i][f].get<int64_t>();
                _sources[i].index[f].capture_time = json_times[i][f].get<int64_t>();
            }
        }
    }

    return index_good;
}

bool PacketStreamReader::GoodToRead()
{
    if(!_stream.good()) {
#ifndef _WIN_
        if (_is_pipe)
        {
            if (_pipe_fd == -1) {
                _pipe_fd = ReadablePipeFileDescriptor(_filename);
            }

            if (_pipe_fd != -1) {
                // Test whether the pipe has data to be read. If so, open the
                // file stream and start reading. After this point, the file
                // descriptor is owned by the reader.
                if (PipeHasDataToRead(_pipe_fd))
                {
                    close(_pipe_fd);
                    _pipe_fd = -1;
                    Open(_filename);
                    return _stream.good();
                }
            }
        }
#endif

        return false;
    }

    return true;

}

Packet PacketStreamReader::NextFrame()
{
    std::unique_lock<std::recursive_mutex> lock(_mutex);

    while (GoodToRead())
    {
        const pangoTagType t = _stream.peekTag();

        switch (t)
        {
        case TAG_PANGO_SYNC:
            SkipSync();
            break;
        case TAG_ADD_SOURCE:
            ParseNewSource();
            break;
        case TAG_SRC_JSON: //frames are sometimes preceded by metadata, but metadata must ALWAYS be followed by a frame from the same source.
        case TAG_SRC_PACKET:
            return Packet(_stream, std::move(lock), _sources);
        case TAG_PANGO_STATS:
            ParseIndex();
            break;
        case TAG_PANGO_FOOTER: //end of frames
        case TAG_END:
            throw std::runtime_error("PacketStreamReader: end of stream");
        case TAG_PANGO_HDR: //shoudln't encounter this
            ParseHeader();
            break;
        case TAG_PANGO_MAGIC: //or this
            SkipSync();
            break;
        default: //or anything else
            pango_print_warn("Unexpected packet type: \"%s\". Resyncing()\n", tagName(t).c_str());
            ReSync();
            break;
        }
    }

    // No frame
    throw std::runtime_error("PacketStreamReader: no frame");
}

Packet PacketStreamReader::NextFrame(PacketStreamSourceId src)
{
    while (1)
    {
        // This will throw if nothing is left.
        auto fi = NextFrame();
        if (fi.src == src) {
            return fi;
        }
    }
}

void PacketStreamReader::RebuildIndex()
{
    lock_guard<decltype(_mutex)> lg(_mutex);

    if(_stream.seekable()) {
        pango_print_warn("Index for '%s' bad / outdated. Rebuilding.\n", _filename.c_str());

        // Save current position
        std::streampos pos = _stream.tellg();

        // Clear existing index
        for(PacketStreamSource& s : _sources) {
            s.index.clear();
            s.next_packet_id = 0;
        }

        // Read through entire file, updating index

        // Reset Packet id's
        for(PacketStreamSource& s : _sources) {
            s.next_packet_id = 0;
        }

        // Restore previous location
        _stream.clear();
        _stream.seekg(pos);
    }
}

void PacketStreamReader::AppendIndex()
{
    lock_guard<decltype(_mutex)> lg(_mutex);

    if(_stream.seekable()) {
        // Open file again for append
        std::ofstream of(_filename, std::ios::app | std::ios::binary);
        if(of.is_open()) {
            pango_print_warn("Appending new index to '%s'.\n", _filename.c_str());
            uint64_t indexpos = (uint64_t)of.tellp();
            writeTag(of, TAG_PANGO_STATS);
            SourceStats(_sources).serialize(std::ostream_iterator<char>(of), false);
            writeTag(of, TAG_PANGO_FOOTER);
            of.write(reinterpret_cast<char*>(&indexpos), sizeof(uint64_t));
        }
    }
}

void PacketStreamReader::FixFileIndex()
{
    if(_stream.seekable())
    {
        RebuildIndex();
        AppendIndex();
    }
}

size_t PacketStreamReader::Seek(PacketStreamSourceId src, size_t framenum)
{
    lock_guard<decltype(_mutex)> lg(_mutex);

    PANGO_ASSERT(_stream.seekable());
    PANGO_ASSERT(src < _sources.size());
    PacketStreamSource& source = _sources[src];
    PANGO_ASSERT(framenum < source.index.size());

    if(source.index[framenum].pos > 0) {
        _stream.clear();
        _stream.seekg(source.index[framenum].pos);
        source.next_packet_id = framenum;
    }
    return source.next_packet_id;
}

// Jumps to the first packet with time >= time
size_t PacketStreamReader::Seek(PacketStreamSourceId src, SyncTime::TimePoint time)
{
    PacketStreamSource& source = _sources[src];

    PacketStreamSource::PacketInfo v = {
        0, std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count()
    };

    // Find time in indextime
    auto lb = std::lower_bound(
        source.index.begin(), source.index.end(), v,
        [](const PacketStreamSource::PacketInfo& a, const PacketStreamSource::PacketInfo& b){
            return a.capture_time < b.capture_time;
        }
    );

    if(lb != source.index.end()) {
        const size_t frame_num = lb - source.index.begin();
        return Seek(src, frame_num);
    }else{
        return source.next_packet_id;
    }
}

void PacketStreamReader::SkipSync()
{
    //Assume we have just read PAN, read GO
    if (_stream.get() != 'G' && _stream.get() != 'O')
        throw std::runtime_error("Unknown packet type.");

    while (_stream.peekTag() != TAG_SRC_PACKET && _stream.peekTag() != TAG_END)
        _stream.readTag();
}

}


try
    {
        ASSERT_FALSE(struct_test.charUnion().case_zero() == 111);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }

#include <fastrtps/types/TypesBase.h>
#include <gtest/gtest.h>
#include <fastrtps/types/DynamicTypeBuilderFactory.h>
#include <fastrtps/types/DynamicTypeBuilder.h>
#include <fastrtps/types/DynamicTypeBuilderPtr.h>
#include <fastrtps/types/DynamicDataFactory.h>
#include <fastrtps/types/TypeDescriptor.h>
#include <fastrtps/types/MemberDescriptor.h>
#include <fastrtps/types/DynamicType.h>
#include <fastrtps/types/DynamicPubSubType.h>
#include <fastrtps/types/DynamicTypePtr.h>
#include <fastrtps/types/DynamicData.h>
#include <fastrtps/types/DynamicDataPtr.h>
#include <fastrtps/types/TypeObjectFactory.h>
#include <fastdds/dds/log/Log.hpp>
#include <fastcdr/exceptions/BadParamException.h>
#include "idl/new_features_4_2PubSubTypes.h"
#include "idl/new_features_4_2TypeObject.h"

using namespace eprosima::fastrtps;
using namespace eprosima::fastrtps::rtps;
using namespace eprosima::fastrtps::types;
using namespace eprosima::fastcdr::exception;

class DynamicTypes_4_2_Tests: public ::testing::Test
{
    const std::string config_file_ = "types.xml";

    public:
        DynamicTypes_4_2_Tests()
        {
        }

        ~DynamicTypes_4_2_Tests()
        {
            eprosima::fastdds::dds::Log::KillThread();
        }

        virtual void TearDown() override
        {
            TypeObjectFactory::delete_instance();
            DynamicDataFactory::delete_instance();
            DynamicTypeBuilderFactory::delete_instance();
        }
};

TEST_F(DynamicTypes_4_2_Tests, Inheritance_And_Default_Value)
{
    StructTest struct_test;
    ASSERT_TRUE(struct_test.uint64_() == 555);
    ASSERT_TRUE(struct_test.int64_() == 0);
}

TEST_F(DynamicTypes_4_2_Tests, Bitmask)
{
    using namespace bitmodule;
    MyBitMask bitmask(static_cast<MyBitMask>(0));

    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(0));
    bitmask = MyBitMask::flag0;
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(1));
    bitmask = MyBitMask::flag1;
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(2));
    bitmask = MyBitMask::flag4;
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(16));
    bitmask = MyBitMask::flag6;
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(64));
    bitmask = MyBitMask::flag7;
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(128));

    bitmask = static_cast<MyBitMask>(MyBitMask::flag0 | MyBitMask::flag4);
    ASSERT_TRUE(bitmask == static_cast<MyBitMask>(17));

    bitmask = static_cast<MyBitMask>(9);
    ASSERT_TRUE(bitmask & MyBitMask::flag0);
    ASSERT_FALSE(bitmask & MyBitMask::flag1);
    ASSERT_FALSE(bitmask & MyBitMask::flag4);
}

TEST_F(DynamicTypes_4_2_Tests, Bitset)
{
    using namespace bitmodule;
    MyBitset mybitset;

    ASSERT_TRUE(mybitset.a() == 0);
    ASSERT_TRUE(mybitset.b() == 0);
    ASSERT_TRUE(mybitset.c() == 0);
    ASSERT_TRUE(mybitset.d() == 0);
    ASSERT_TRUE(mybitset.e() == 0);
    ASSERT_TRUE(mybitset.f() == 0);
    ASSERT_TRUE(mybitset.parent_bitfield() == 0);

    mybitset.a(static_cast<char>(15));    // 00001111
    ASSERT_TRUE(mybitset.a() == 7);       // 00000111
    ASSERT_TRUE(mybitset.b() == 0);       // b unaffected
    ASSERT_FALSE(mybitset.b());
    mybitset.b(true);
    ASSERT_TRUE(mybitset.b());
    mybitset.c(static_cast<uint16_t>(-1));// 1111111111111111
    ASSERT_TRUE(mybitset.c() == 1023);    // 0000001111111111 (2^10 - 1)
    mybitset.d(-1);                       // 1111111111111111
    mybitset.e(5555);                     // 0001010110110011 (The most significant bit is not stored)
    mybitset.f(3851);
    ASSERT_TRUE(mybitset.d() == 4095);    // 0000111111111111 (2^12 - 1)
    ASSERT_TRUE(mybitset.e() == 1459);    // 0000010110110011 (The most significant bit is not stored)
    ASSERT_TRUE(mybitset.f() == 3851);
    mybitset.parent_bitfield(static_cast<uint32_t>(-1));// 11111111111111111111111111111111
    ASSERT_TRUE(mybitset.parent_bitfield() == 131071);  // 00000000000000111111111111111111 (2^17 - 1)
}

TEST_F(DynamicTypes_4_2_Tests, Non_Serialized_Annotation)
{
    NewAliases struct_test;
    struct_test.int8_(-8);
    struct_test.uint8_(8);
    struct_test.int16_(-16);
    struct_test.uint16_(16);
    struct_test.int32_(-32);
    struct_test.uint32_(32);
    struct_test.int64_(-64);
    struct_test.uint64_(64);
    struct_test.local_string("DON'T_SERIALIZE");

    NewAliasesPubSubType pst;
    NewAliases destination;
    uint32_t payloadSize = static_cast<uint32_t>(pst.getSerializedSizeProvider(&struct_test)());
    SerializedPayload_t payload(payloadSize);

    pst.serialize(&struct_test, &payload);
    pst.deserialize(&payload, &destination);

    ASSERT_TRUE(destination.int8_() == -8);
    ASSERT_TRUE(destination.uint8_() == 8);
    ASSERT_TRUE(destination.int16_() == -16);
    ASSERT_TRUE(destination.uint16_() == 16);
    ASSERT_TRUE(destination.int32_() == -32);
    ASSERT_TRUE(destination.uint32_() == 32);
    ASSERT_TRUE(destination.int64_() == -64);
    ASSERT_TRUE(destination.uint64_() == 64);
    ASSERT_FALSE(destination.local_string() == "DON'T_SERIALIZE"); // Is non_serialized annotated
}

TEST_F(DynamicTypes_4_2_Tests, New_Union_Discriminators)
{
    StructTest struct_test;

    ASSERT_TRUE(sizeof(struct_test.int8Union()._d()) == 1);
    ASSERT_TRUE(sizeof(struct_test.octetUnion()._d()) == 1);
    ASSERT_TRUE(sizeof(struct_test.charUnion()._d()) == sizeof(wchar_t));

    struct_test.int8Union().case_three(333);
    struct_test.int8Union().case_six(666);

    struct_test.int8Union()._d() = 3;
    ASSERT_TRUE(struct_test.int8Union().case_three() == 333);
    try
    {
        ASSERT_FALSE(struct_test.int8Union().case_six() == 666);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }

    struct_test.int8Union()._d() = 6;
    try
    {
        ASSERT_FALSE(struct_test.int8Union().case_three() == 333);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }
    ASSERT_TRUE(struct_test.int8Union().case_six() == 666);

    // octetUnion
    struct_test.octetUnion().case_five(555);
    struct_test.octetUnion().case_seven(777);

    struct_test.octetUnion()._d() = 5;
    ASSERT_TRUE(struct_test.octetUnion().case_five() == 555);
    try
    {
        ASSERT_FALSE(struct_test.octetUnion().case_seven() == 777);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }

    struct_test.octetUnion()._d() = 7;
    try
    {
        ASSERT_FALSE(struct_test.octetUnion().case_five() == 555);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }
    ASSERT_TRUE(struct_test.octetUnion().case_seven() == 777);

    struct_test.charUnion().case_zero(111);
    struct_test.charUnion().case_one(222);

    struct_test.charUnion()._d() = L'a';
    ASSERT_TRUE(struct_test.charUnion().case_zero() == 111);
    try
    {
        ASSERT_FALSE(struct_test.charUnion().case_one() == 222);
        ASSERT_TRUE(false);
    }
    catch(const BadParamException&)
    {
    }

    struct_test.charUnion()._d() = L'b';

    ASSERT_TRUE(struct_test.charUnion().case_one() == 222);
}

TEST_F(DynamicTypes_4_2_Tests, TypeObject_DynamicType_Conversion)
{
    registernew_features_4_2Types();

    // TODO Bitset serialization isn't compatible.
    const TypeIdentifier* identifier = GetStructTestIdentifier(true);
    const TypeObject* object = GetCompleteStructTestObject();

    DynamicType_ptr dyn_type =
        TypeObjectFactory::get_instance()->build_dynamic_type("StructTest", identifier, object);

    TypeIdentifier conv_identifier;
    TypeObject conv_object;
    DynamicTypeBuilderFactory::get_instance()->build_type_object(dyn_type, conv_object, true, true); // Avoid factory
    DynamicTypeBuilderFactory::get_instance()->build_type_identifier(dyn_type, conv_identifier, true);

    ASSERT_TRUE(*identifier == conv_identifier);
    ASSERT_TRUE(*object == conv_object);

    StructTest struct_test;
    DynamicData_ptr dyn_data(DynamicDataFactory::get_instance()->create_data(dyn_type));

    DynamicPubSubType pst_dynamic(dyn_type);
    uint32_t payload_dyn_size = static_cast<uint32_t>(pst_dynamic.getSerializedSizeProvider(dyn_data.get())());
    SerializedPayload_t payload(payload_dyn_size);
    ASSERT_TRUE(pst_dynamic.serialize(dyn_data.get(), &payload));
    ASSERT_TRUE(payload.length == payload_dyn_size);

    StructTestPubSubType pst_static;
    uint32_t payload_size = static_cast<uint32_t>(pst_static.getSerializedSizeProvider(&struct_test)());
    SerializedPayload_t st_payload(payload_size);
    ASSERT_TRUE(pst_static.serialize(&struct_test, &st_payload));
    ASSERT_TRUE(st_payload.length == payload_size);

    DynamicData_ptr dyn_data_from_dynamic(DynamicDataFactory::get_instance()->create_data(dyn_type));
    ASSERT_TRUE(pst_dynamic.deserialize(&payload, dyn_data_from_dynamic.get()));

    types::DynamicData_ptr dyn_data_from_static(DynamicDataFactory::get_instance()->create_data(dyn_type));
    ASSERT_TRUE(pst_dynamic.deserialize(&st_payload, dyn_data_from_static.get()));

    // DEBUG Printing payloads
    /*
    std::cout << "Payload: " << std::endl;
    for (int i = 0; i < payload_size; ++i)
    {
        std::cout << std::hex << (uint32_t)(payload.data[i]) << " ";
    }
    std::cout << std::endl;
    std::cout << "ST_Payload: " << std::endl;
    for (int i = 0; i < st_payload.length; ++i)
    {
        std::cout << std::hex << (uint32_t)(st_payload.data[i]) << " ";
    }
    std::cout << "--------------------------" << std::endl;
    */
    ASSERT_TRUE(dyn_data_from_static->equals(dyn_data_from_dynamic.get()));
}

TEST_F(DynamicTypes_4_2_Tests, Static_Dynamic_Values)
{
    registernew_features_4_2Types();

    const TypeIdentifier* identifier = GetStructTestIdentifier(true);
    const TypeObject* object = GetCompleteStructTestObject();

    DynamicType_ptr dyn_type =
        TypeObjectFactory::get_instance()->build_dynamic_type("StructTest", identifier, object);

    // Serialize static initialization with values
    StructTest struct_test;
    StructTestPubSubType pst_static;

    struct_test.int8_(-8);
    struct_test.uint8_(8);
    struct_test.int16_(-16);
    struct_test.uint16_(16);
    struct_test.int32_(-32);
    struct_test.uint32_(32);
    struct_test.int64_(-64);
    struct_test.uint64_(64);
    struct_test.local_string("DON'T_SERIALIZE");
    struct_test.charUnion().case_one(11111);
    struct_test.octetUnion().case_seven(77777);
    struct_test.int8Union().case_three(33333);
    struct_test.myStructBits().mybitset().parent_bitfield(2121);
    struct_test.myStructBits().mybitset().a(5);
    struct_test.myStructBits().mybitset().b(true);
    struct_test.myStructBits().mybitset().c(333);
    struct_test.myStructBits().mybitset().d(4000);
    struct_test.myStructBits().mybitset().e(4001);
    struct_test.myStructBits().mybitset().f(3001);
    struct_test.myStructBits().mybitmask(
        static_cast<bitmodule::MyBitMask>(bitmodule::MyBitMask::flag0 | bitmodule::MyBitMask::flag4));
    struct_test.myStructBits().two(
        static_cast<bitmodule::MyBitMask>(bitmodule::MyBitMask::flag1 | bitmodule::MyBitMask::flag6));
    struct_test.myStructBits().mylong(static_cast<uint32_t>(struct_test.myStructBits().two()));

    // Static serialization
    uint32_t payload_size = static_cast<uint32_t>(pst_static.getSerializedSizeProvider(&struct_test)());
    SerializedPayload_t st_payload(payload_size);
    ASSERT_TRUE(pst_static.serialize(&struct_test, &st_payload));
    ASSERT_TRUE(st_payload.length == payload_size);

    // Dynamic deserialization from static
    DynamicPubSubType pst_dynamic(dyn_type);
    DynamicData_ptr dyn_data(DynamicDataFactory::get_instance()->create_data(dyn_type));
    ASSERT_TRUE(pst_dynamic.deserialize(&st_payload, dyn_data.get()));

    // Dynamic serialization
    uint32_t payload_dyn_size = static_cast<uint32_t>(pst_dynamic.getSerializedSizeProvider(dyn_data.get())());
    SerializedPayload_t dyn_payload(payload_dyn_size);
    ASSERT_TRUE(pst_dynamic.serialize(dyn_data.get(), &dyn_payload));
    ASSERT_TRUE(dyn_payload.length == payload_dyn_size);

    // Static deserialization from dynamic
    StructTest struct_test_from_dynamic;
    ASSERT_TRUE(pst_static.deserialize(&dyn_payload, &struct_test_from_dynamic));

    // Check values
    ASSERT_TRUE(struct_test_from_dynamic.int8_() == struct_test.int8_());
    ASSERT_TRUE(struct_test_from_dynamic.uint8_() == struct_test.uint8_());
    ASSERT_TRUE(struct_test_from_dynamic.int16_() == struct_test.int16_());
    ASSERT_TRUE(struct_test_from_dynamic.uint16_() == struct_test.uint16_());
    ASSERT_TRUE(struct_test_from_dynamic.int32_() == struct_test.int32_());
    ASSERT_TRUE(struct_test_from_dynamic.uint32_() == struct_test.uint32_());
    ASSERT_TRUE(struct_test_from_dynamic.int64_() == struct_test.int64_());
    ASSERT_TRUE(struct_test_from_dynamic.uint64_() == struct_test.uint64_());
    ASSERT_FALSE(struct_test_from_dynamic.local_string() == struct_test.local_string()); // Non serialized
    ASSERT_TRUE(struct_test_from_dynamic.charUnion().case_one() == struct_test.charUnion().case_one());
    ASSERT_TRUE(struct_test_from_dynamic.octetUnion().case_seven() == struct_test.octetUnion().case_seven());
    ASSERT_TRUE(struct_test_from_dynamic.int8Union().case_three() == struct_test.int8Union().case_three());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().parent_bitfield() == struct_test.myStructBits().mybitset().parent_bitfield());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().a() == struct_test.myStructBits().mybitset().a());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().b() == struct_test.myStructBits().mybitset().b());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().c() == struct_test.myStructBits().mybitset().c());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().d() == struct_test.myStructBits().mybitset().d());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().e() == struct_test.myStructBits().mybitset().e());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitset().f() == struct_test.myStructBits().mybitset().f());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mybitmask() == struct_test.myStructBits().mybitmask());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().two() == struct_test.myStructBits().two());
    ASSERT_TRUE(struct_test_from_dynamic.myStructBits().mylong() == struct_test.myStructBits().mylong());

    ASSERT_TRUE(dyn_data->get_int8_value(dyn_data->get_member_id_by_name("int8_")) == struct_test.int8_());
    ASSERT_TRUE(dyn_data->get_uint8_value(dyn_data->get_member_id_by_name("uint8_")) == struct_test.uint8_());
    ASSERT_TRUE(dyn_data->get_int16_value(dyn_data->get_member_id_by_name("int16_")) == struct_test.int16_());
    ASSERT_TRUE(dyn_data->get_uint16_value(dyn_data->get_member_id_by_name("uint16_")) == struct_test.uint16_());
    ASSERT_TRUE(dyn_data->get_int32_value(dyn_data->get_member_id_by_name("int32_")) == struct_test.int32_());
    ASSERT_TRUE(dyn_data->get_uint32_value(dyn_data->get_member_id_by_name("uint32_")) == struct_test.uint32_());
    ASSERT_TRUE(dyn_data->get_int64_value(dyn_data->get_member_id_by_name("int64_")) == struct_test.int64_());
    ASSERT_TRUE(dyn_data->get_uint64_value(dyn_data->get_member_id_by_name("uint64_")) == struct_test.uint64_());
    ASSERT_FALSE(dyn_data->get_string_value(dyn_data->get_member_id_by_name("local_string")) ==
        struct_test.local_string()); // Non serialized

    DynamicData* charUnion = dyn_data->loan_value(dyn_data->get_member_id_by_name("charUnion"));
    ASSERT_TRUE(charUnion->get_int32_value(charUnion->get_member_id_by_name("case_one")) ==
        struct_test.charUnion().case_one());
    dyn_data->return_loaned_value(charUnion);

    DynamicData* octetUnion = dyn_data->loan_value(dyn_data->get_member_id_by_name("octetUnion"));
    ASSERT_TRUE(octetUnion->get_int32_value(octetUnion->get_member_id_by_name("case_seven")) ==
        struct_test.octetUnion().case_seven());
    dyn_data->return_loaned_value(octetUnion);

    DynamicData* int8Union = dyn_data->loan_value(dyn_data->get_member_id_by_name("int8Union"));
    ASSERT_TRUE(int8Union->get_int32_value(int8Union->get_member_id_by_name("case_three")) ==
        struct_test.int8Union().case_three());
    dyn_data->return_loaned_value(int8Union);

    DynamicData* myStructBits = dyn_data->loan_value(dyn_data->get_member_id_by_name("myStructBits"));
    DynamicData* mybitset = myStructBits->loan_value(myStructBits->get_member_id_by_name("mybitset"));

    ASSERT_TRUE(mybitset->get_uint32_value(mybitset->get_member_id_by_name("parent_bitfield"))
        == struct_test.myStructBits().mybitset().parent_bitfield());
    ASSERT_TRUE(mybitset->get_char8_value(mybitset->get_member_id_by_name("a"))
        == struct_test.myStructBits().mybitset().a());
    ASSERT_TRUE(mybitset->get_bool_value(mybitset->get_member_id_by_name("b"))
        == struct_test.myStructBits().mybitset().b());
    ASSERT_TRUE(mybitset->get_uint16_value(mybitset->get_member_id_by_name("c"))
        == struct_test.myStructBits().mybitset().c());
    ASSERT_TRUE(mybitset->get_int16_value(mybitset->get_member_id_by_name("d"))
        == struct_test.myStructBits().mybitset().d());
    ASSERT_TRUE(mybitset->get_int16_value(mybitset->get_member_id_by_name("e"))
        == struct_test.myStructBits().mybitset().e());
    ASSERT_TRUE(mybitset->get_int16_value(mybitset->get_member_id_by_name("f"))
        == struct_test.myStructBits().mybitset().f());

    myStructBits->return_loaned_value(mybitset);
    ASSERT_TRUE(myStructBits->get_uint64_value(myStructBits->get_member_id_by_name("mybitmask")) ==
        struct_test.myStructBits().mybitmask());
    ASSERT_TRUE(myStructBits->get_uint64_value(myStructBits->get_member_id_by_name("two")) ==
        struct_test.myStructBits().two());
    ASSERT_TRUE(myStructBits->get_int32_value(myStructBits->get_member_id_by_name("mylong")) ==
        struct_test.myStructBits().mylong());
    dyn_data->return_loaned_value(myStructBits);
}

int main(int argc, char **argv)
{
    eprosima::fastdds::dds::Log::SetVerbosity(eprosima::fastdds::dds::Log::Info);

    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


try
      {
         if ( replyObj.getBoolField( ES_ERROR_FIELD_NAME ) )
         {
            rc = SDB_SYS ;
            PD_LOG( PDERROR, "Operation on remote failed. Reply: %s", reply ) ;
            goto error ;
         }
      }
      catch ( std::exception &e )
      {
         rc = SDB_SYS ;
         PD_LOG( PDERROR, "Unexpected exception happened: %s", e.what() ) ;
         goto error ;
      }

/*******************************************************************************

   Source File Name = utilESClt.cpp

   Descriptive Name = Elasticsearch client.

   When/how to use: this program may be used on binary and text-formatted
   versions of data management component. This file contains structure for
   DMS storage unit and its methods.

   Dependencies: N/A

   Restrictions: N/A

   Change Activity:
   defect Date        Who Description
   ====== =========== === ==============================================
          14/04/2017  YSD Initial Draft

   Last Changed =

*******************************************************************************/
#include "utilESClt.hpp"

#include <iostream>
#include <sstream>
#include <cstring>
#include <vector>

#include "pd.hpp"
#include "ossUtil.hpp"
#include "../bson/bson.hpp"

using namespace bson ;

#define ES_HITS_KEY              "_hits"
#define ES_TOTAL_KEY             "total"
#define ES_SCROLL_ID_KEY         "_scroll_id"
#define ES_SOURCE_KEY            "_source"
#define ES_ERROR_FIELD_NAME      "errors"

#define ES_CLT_ARG_CHK1( index )                         \
do                                                       \
{                                                        \
   if ( !(index) )                                       \
   {                                                     \
      PD_LOG( PDERROR, "Index name is NULL" ) ;          \
      rc = SDB_INVALIDARG ;                              \
      goto error ;                                       \
   }                                                     \
}                                                        \
while ( 0 ) ;

#define ES_CLT_ARG_CHK2( index, type )                   \
do                                                       \
{                                                        \
   ES_CLT_ARG_CHK1( index ) ;                            \
   if ( !(type) )                                        \
   {                                                     \
      PD_LOG( PDERROR, "Type name is NULL" ) ;           \
      rc = SDB_INVALIDARG ;                              \
      goto error ;                                       \
   }                                                     \
}                                                        \
while ( 0 ) ;

#define ES_CLT_ARG_CHK3( index, type, id )               \
do                                                       \
{                                                        \
   ES_CLT_ARG_CHK2( index, type ) ;                      \
   if ( !(id) )                                          \
   {                                                     \
      PD_LOG( PDERROR, "Id is NULL" ) ;                  \
      rc = SDB_INVALIDARG ;                              \
      goto error ;                                       \
   }                                                     \
}                                                        \
while ( 0 ) ;

#define ES_CLT_ARG_CHK4( index, type, id, data )         \
do                                                       \
{                                                        \
   ES_CLT_ARG_CHK3( index, type, id ) ;                  \
   if ( !(id) )                                          \
   {                                                     \
      PD_LOG( PDERROR, "Data is NULL" ) ;                \
      rc = SDB_INVALIDARG ;                              \
      goto error ;                                       \
   }                                                     \
}                                                        \
while ( 0 ) ;

namespace seadapter
{
   _utilESClt::_utilESClt()
   : _readOnly( FALSE ),
     _errMsg( NULL )
   {
   }

   _utilESClt::~_utilESClt()
   {
   }

   INT32 _utilESClt::init( const string &uri, BOOLEAN readOnly, INT32 timeout )
   {
      INT32 rc = SDB_OK ;
      if ( 0 == uri.size() )
      {
         rc = SDB_INVALIDARG ;
         PD_LOG( PDERROR, "Search engine service address should not be empty, "
                 "rc: %d", rc ) ;
         goto error ;
      }

      rc = _http.init( uri, TRUE, timeout ) ;
      if ( rc )
      {
         PD_LOG( PDERROR, "Failed to init http connection with node: %s, "
                 "rc: %d", uri.c_str(), rc ) ;
         goto error ;
      }
      _readOnly = readOnly ;

   done:
      return rc  ;
   error:
      goto done ;
   }

   BOOLEAN _utilESClt::isActive()
   {
      return ( SDB_OK == _http.get( NULL, NULL ) ) ? TRUE : FALSE ;
   }

   INT32 _utilESClt::active()
   {
      INT32 rc = SDB_OK ;

      rc = _http.reconnect() ;
      PD_RC_CHECK( rc, PDERROR, "Activate client failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::getSEInfo( BSONObj &infoObj )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;

      rc = _http.get( NULL, NULL, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, infoObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::indexExist( const CHAR *index, BOOLEAN &exist )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      BSONObj replyInfo ;

      ES_CLT_ARG_CHK1( index ) ;

      rc = _http.head( index, NULL, &status, &reply, &replyLen ) ;
      if ( SDB_OK == rc )
      {
         exist = TRUE ;
         goto done ;
      }
      else if ( HTTP_NOT_FOUND == status )
      {
         exist = FALSE ;
         rc = SDB_OK ;
         goto done ;
      }

      rc = _processReply( rc, reply, replyLen, replyInfo ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::createIndex( const CHAR *index, const CHAR *data )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      BSONObj replyInfo ;

      ES_CLT_ARG_CHK1( index ) ;

      rc = _http.put( index, data, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, replyInfo ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::dropIndex( const CHAR *index )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      BSONObj replyInfo ;

      ES_CLT_ARG_CHK1( index ) ;

      rc = _http.remove( index, NULL, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, replyInfo ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::indexDocument( const CHAR *index, const CHAR *type,
                                    const CHAR *id, const CHAR *jsonData )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj bsonObj ;
      HTTP_STATUS_CODE status = 0 ;
      CHAR url[ UTIL_SE_MAX_URL_SIZE ] = { 0 } ;

      ES_CLT_ARG_CHK4( index, type, id, jsonData ) ;

      if ( strlen( index ) + strlen( type ) + strlen( id ) + 2
           > UTIL_SE_MAX_URL_SIZE )
      {
         rc = SDB_INVALIDARG ;
         PD_LOG( PDERROR, "Url length is too long, max: %d, actual: %d",
                 UTIL_SE_MAX_URL_SIZE,
                 strlen( index ) + strlen( type ) + strlen( id ) + 2 ) ;
         goto error ;
      }

      ossSnprintf( url, UTIL_SE_MAX_URL_SIZE, "%s/%s/%s", index, type, id ) ;
      rc = _http.put( url, jsonData, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, bsonObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::updateDocument( const CHAR *index, const CHAR *type,
                                     const CHAR *id, const CHAR *newData )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj bsonObj ;
      HTTP_STATUS_CODE status = 0 ;
      CHAR url[ UTIL_SE_MAX_URL_SIZE ] = { 0 } ;

      ES_CLT_ARG_CHK4( index, type, id, newData ) ;

      if ( strlen( index ) + strlen( type ) + strlen( id ) + 2
           > UTIL_SE_MAX_URL_SIZE )
      {
         rc = SDB_INVALIDARG ;
         PD_LOG( PDERROR, "Url length is too long, max: %d, actual: %d",
                 UTIL_SE_MAX_URL_SIZE,
                 strlen( index ) + strlen( type ) + strlen( id ) + 2 ) ;
         goto error ;
      }

      ossSnprintf( url, UTIL_SE_MAX_URL_SIZE, "%s/%s/%s", index, type, id ) ;
      rc = _http.put( url, newData, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, bsonObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::deleteDocument( const CHAR *index, const CHAR *type,
                                     const CHAR *id )
   {
      INT32 rc = SDB_OK ;
      std::string result ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      BSONObj resultObj ;
      std::ostringstream oss ;

      ES_CLT_ARG_CHK3( index, type, id ) ;

      SDB_ASSERT( index && type && id, "Invalid arguments for deleteDocument" ) ;

      oss << index << "/" << type << "/" << id ;

      rc = _http.remove( oss.str().c_str(), NULL, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, resultObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::getDocument( const CHAR *index, const CHAR *type,
                                  const CHAR *id, BSONObj &result,
                                  BOOLEAN withMeta )
   {
      INT32 rc = SDB_OK ;
      BSONObj fullObj ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      std::ostringstream oss ;
      utilCommObjBuff objBuff ;

      ES_CLT_ARG_CHK3( index, type, id ) ;

      oss << index << "/" << type << "/" << id ;
      rc = _http.get( oss.str().c_str(), NULL, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, fullObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

      if ( withMeta )
      {
         result = fullObj ;
      }
      else
      {
         rc = _removeDocMeta( fullObj, result ) ;
         PD_RC_CHECK( rc, PDERROR, "Remove document meta failed[ %d ]", rc ) ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::getDocument( const CHAR *index, const CHAR *type,
                                  const CHAR *key, const CHAR *value,
                                  utilCommObjBuff &objBuff, BOOLEAN withMeta )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      std::ostringstream endUrl ;
      std::ostringstream query ;
      BSONObj fullObj ;

      ES_CLT_ARG_CHK4( index, type, key, value ) ;

      endUrl << index << "/" << type << "/_search" ;
      query << "{\"query\":{\"match\":{\"" << key << "\":\""
            << value << "\"}}}" ;

      rc = objBuff.reset() ;
      PD_RC_CHECK( rc, PDERROR, "Reset object buffer failed[ %d ]", rc ) ;

      rc = _http.get( endUrl.str().c_str(), query.str().c_str(),
                      &status, &reply, &replyLen ) ;
      if ( withMeta )
      {
         rc = _processReply( rc, reply, replyLen, fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;
         rc = objBuff.appendObj( fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Append object to buffer failed[ %d ]", rc ) ;
      }
      else
      {
         rc = _processReply( rc, reply,replyLen, fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

         rc = _getResultObjs( fullObj, objBuff ) ;
         PD_RC_CHECK( rc, PDERROR, "Get result objects failed[ %d ]" ) ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::getDocument( const CHAR *index, const CHAR *type,
                                  const CHAR *query, utilCommObjBuff &objBuff,
                                  BOOLEAN withMeta )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      HTTP_STATUS_CODE status = 0 ;
      std::ostringstream endUrl ;
      BSONObj fullObj ;

      ES_CLT_ARG_CHK2( index, type ) ;

      if ( !query )
      {
         rc = SDB_INVALIDARG ;
         PD_LOG( PDERROR, "Query condition is NULL" ) ;
         goto error ;
      }

      endUrl << index << "/" << type << "/_search" ;

      rc = objBuff.reset() ;
      PD_RC_CHECK( rc, PDERROR, "Reset object buffer failed[ %d ]", rc ) ;

      rc = _http.get( endUrl.str().c_str(), query, &status, &reply, &replyLen ) ;
      if ( withMeta )
      {
         rc = _processReply( rc, reply, replyLen, fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;
         rc = objBuff.appendObj( fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Append object to buffer failed[ %d ]", rc ) ;
      }
      else
      {
         rc = _processReply( rc, reply,replyLen, fullObj ) ;
         PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

         rc = _getResultObjs( fullObj, objBuff ) ;
         PD_RC_CHECK( rc, PDERROR, "Get result objects failed[ %d ]" ) ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::getDocCount( const CHAR *index, const CHAR *type,
                                  UINT64 &count )
   {
      INT32 rc = SDB_OK ;
      std::ostringstream oss ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj bsonObj ;
      HTTP_STATUS_CODE status = 0 ;

      ES_CLT_ARG_CHK2( index, type ) ;

      oss << index << "/" << type << "/_count" ;

      rc = _http.get( oss.str().c_str(), NULL, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, bsonObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

      count = bsonObj.getIntField( "count" ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::documentExist( const CHAR *index, const CHAR *type,
                                    const CHAR *id, BOOLEAN &exist )
   {
      INT32 rc = SDB_OK ;
      HTTP_STATUS_CODE status = 0 ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      std::ostringstream oss ;
      BSONObj result ;

      ES_CLT_ARG_CHK3( index, type, id ) ;

      oss << index << "/" << type << "/" << id ;
      rc = _http.head( oss.str().c_str(), NULL, &status, &reply, &replyLen ) ;
      if ( SDB_OK == rc )
      {
         exist = ( HTTP_OK == status ) ;
      }
      else if ( SDB_INVALIDARG == rc )
      {
         exist = FALSE ;
         rc = SDB_OK ;
         goto done ;
      }
      else
      {
         PD_LOG( PDERROR, "HEAD request[ %s ] failed[ %d ]", oss.str().c_str(),
                 rc ) ;
         goto error ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::documentExist( const CHAR *index, const CHAR *type,
                                    const CHAR *key, const CHAR *value,
                                    BOOLEAN &exist )
   {
      INT32 rc = SDB_OK ;
      std::ostringstream url ;
      std::ostringstream query ;
      HTTP_STATUS_CODE status = 0 ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj result ;
      INT64 hitNum = 0 ;

      ES_CLT_ARG_CHK4( index, type, key, val ) ;

      url << index << "/" << type ;
      query << "{\"query\":{\"match\":{\"" << key << "\":\""
            << value << "\"}}}" ;

      rc = _http.get( url.str().c_str(), query.str().c_str(), &status,
                      &reply, &replyLen ) ;
      if ( rc )
      {
         exist = FALSE ;
      }
      else
      {
         rc = _processReply( rc, reply, replyLen, result ) ;
         PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;
         _getHitNum( result, hitNum ) ;
         exist = ( hitNum >= 1 ) ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::deleteAllByType( const CHAR *index, const CHAR *type )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj resultObj ;
      HTTP_STATUS_CODE status = 0 ;
      std::ostringstream uri, data ;

      ES_CLT_ARG_CHK2( index, type ) ;

      uri << index << "/" << type << "/_delete_by_query" ;
      data << "{\"query\":{\"match_all\":{}}}" ;

      rc = _http.post( uri.str().c_str(), data.str().c_str(),
                       &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, resultObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::refresh( const CHAR *index )
   {
      INT32 rc = SDB_OK ;
      BSONObj bsonObj ;
      std::string result ;
      std::ostringstream oss ;

      ES_CLT_ARG_CHK1( index ) ;

      oss << index << "/_refresh" ;
      rc = _http.get( oss.str().c_str(), NULL ) ;
      PD_RC_CHECK( rc, PDERROR, "Process refresh request failed[ %d ]" ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::initScroll( std::string& scrollId,
                                 const CHAR* index,
                                 const CHAR* type,
                                 const std::string& query,
                                 utilCommObjBuff &result,
                                 int scrollSize,
                                 const CHAR *filterPath )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj replyObj ;
      HTTP_STATUS_CODE status = 0 ;
      std::ostringstream oss;

      ES_CLT_ARG_CHK2( index, type ) ;

      oss << index << "/" << type << "/_search?scroll=1m&size="
         << scrollSize;
      if ( filterPath )
      {
         oss << "&" << filterPath ;
      }

      rc = result.reset() ;
      PD_RC_CHECK( rc, PDERROR, "Reset object buffer failed[ %d ]", rc ) ;

      rc = _http.post( oss.str().c_str(), query.c_str(), &status,
                       &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, replyObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;
      PD_LOG( PDDEBUG, "Reply for init scroll: %s",
              replyObj.toString().c_str() ) ;

      rc = _getResultObjs( replyObj, result ) ;
      PD_RC_CHECK( rc, PDERROR, "Get result objects from reply failed[ %d ]",
                   rc ) ;

      scrollId = string( replyObj.getStringField( ES_SCROLL_ID_KEY ) ) ;
      PD_LOG( PDDEBUG, "scroll id returned: %s", scrollId.c_str() ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   INT32 _utilESClt::scrollNext( std::string& scrollId, utilCommObjBuff &result,
                                 const CHAR *filterPath )
   {
      INT32 rc = SDB_OK ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj replyObj ;
      HTTP_STATUS_CODE status = 0 ;
      string endUrl = "_search/scroll?scroll=1m" ;
      string scrollIdStr = "{ \"scroll_id\" : \"" + scrollId + "\" }" ;

      if ( filterPath )
      {
         endUrl = endUrl + "&" + filterPath ;
      }

      rc = _http.post( endUrl.c_str(), scrollIdStr.c_str(),
                       &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, replyObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

      rc = _getResultObjs( replyObj, result ) ;
      PD_RC_CHECK( rc, PDERROR, "Get objects from reply failed[ %d ]", rc ) ;

      scrollId = string( replyObj.getStringField( ES_SCROLL_ID_KEY ) ) ;
      PD_LOG( PDDEBUG, "scroll id returned: %s", scrollId.c_str() ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   void _utilESClt::clearScroll( const std::string& scrollId )
   {
      string endUrl = "_search/scroll/" + scrollId ;
      _http.remove( endUrl.c_str(), NULL, NULL, NULL, NULL );
   }

   INT32 _utilESClt::bulk( const CHAR *index, const CHAR *type,
                           const CHAR *data, const CHAR *filterPath )
   {
      INT32 rc = SDB_OK ;
      string endUrl ;
      const CHAR *reply = NULL ;
      INT32 replyLen = 0 ;
      BSONObj replyObj ;
      HTTP_STATUS_CODE status = 0 ;

      if ( !data )
      {
         rc = SDB_INVALIDARG ;
         PD_LOG( PDERROR, "No valid data for _bulk operation" ) ;
         goto error ;
      }

      if ( index )
      {
         endUrl = string( index ) ;
         if ( type )
         {
            endUrl += string( "/" ) + type ;
         }
      }
      endUrl += "/_bulk" ;
      if ( filterPath )
      {
         endUrl = endUrl + "?" + filterPath ;
      }

      rc = _http.post( endUrl.c_str(), data, &status, &reply, &replyLen ) ;
      rc = _processReply( rc, reply, replyLen, replyObj ) ;
      PD_RC_CHECK( rc, PDERROR, "Process request reply failed[ %d ]", rc ) ;

   done:
      return rc ;
   error:
      goto done ;
   }

   const CHAR* _utilESClt::getLastErrMsg() const
   {
      return _errMsg ;
   }

   INT32 _utilESClt::_getResultObjs( const BSONObj &replyObj,
                                     utilCommObjBuff &resultObjs )
   {
      INT32 rc = SDB_OK ;
      BSONElement sourceObj ;

      PD_RC_CHECK( rc, PDERROR, "Initialize result buffer failed[ %d ]", rc ) ;

      try
      {
         PD_LOG( PDDEBUG, "Result object: %s", replyObj.toString( FALSE, TRUE ).c_str() ) ;
         {
            BSONElement hitsObj = replyObj.getField( "hits" ) ;
            if ( Object == hitsObj.type() )
            {
               BSONObj hitsObj2 = hitsObj.embeddedObject() ;
               BSONElement hitsEle2 = hitsObj2.getField( "hits" ) ;
               if ( Array == hitsEle2.type() )
               {
                  vector<BSONElement> hitObjs = hitsEle2.Array() ;
                  for ( vector<BSONElement>::iterator itr = hitObjs.begin();
                        itr != hitObjs.end(); ++itr )
                  {
                     BSONObj sourceObj = itr->embeddedObject() ;
                     rc = resultObjs.appendObj( sourceObj ) ;
                     PD_RC_CHECK( rc, PDERROR, "Append object failed[ %d ]",
                                  rc ) ;
                  }
               }
            }
         }
      }
      catch ( std::exception &e )
      {
         PD_LOG( PDERROR, "Exception occurred: %s", e.what() ) ;
         rc = SDB_SYS ;
         goto error ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }

   void _utilESClt::_getHitNum( const BSONObj &fullResult, INT64 &hitNum )
   {
      BSONObj hitsObj = fullResult.getObjectField( ES_HITS_KEY ) ;
      BSONElement totalEle = hitsObj.getField( ES_TOTAL_KEY ) ;
      if ( NumberInt == totalEle.type() ||
           NumberLong == totalEle.type() )
      {
         hitNum = totalEle.numberLong() ;
      }
      else
      {
         hitNum = 0 ;
      }
   }

   INT32 _utilESClt::_removeDocMeta( const BSONObj &fullObj, BSONObj &newObj )
   {
      INT32 rc = SDB_OK ;

      try
      {
         BSONElement ele = fullObj.getField( ES_SOURCE_KEY ) ;
         newObj = ele.Obj() ;
      }
      catch ( std::exception &e )
      {
         rc = SDB_SYS ;
         PD_LOG( PDERROR, "Exception occurred: %s", e.what() ) ;
         goto error ;
      }

   done:
      return rc ;
   error:
      goto done ;
   }
}


try
				{
					while (text.length())
					{
						if (coords.size() == 1)
						{
							// Don't apply an offset to text box size.
							offset.commit();
							MapCoord::boundsOffset().reset(false);
						}
						coords.emplace_back(text);
					}
				}
				catch (std::exception& e)
				{
					Q_UNUSED(e)
					qDebug("Could not parse the coordinates: %s", e.what());
					throw FileFormatException(::OpenOrienteering::ImportExport::tr("Could not parse the coordinates."));
				}

/*
 *
 *    This file is part of OpenOrienteering.
 *
 */

#include "xml_stream_util.h"

#include <algorithm>
#include <array>
#include <exception>
#include <limits>
#include <stdexcept>

#include <QtGlobal>
#include <QBuffer>
#include <QByteArray>
#include <QChar>
#include <QIODevice>
#include <QLatin1Char>
#include <QScopedValueRollback>
#include <QTextCodec>
// IWYU pragma: no_include <qxmlstream.h>

#include "core/map_coord.h"
#include "fileformats/file_format.h"
#include "fileformats/file_import_export.h"
#include "fileformats/xml_file_format.h"
#include "util/key_value_container.h"

namespace OpenOrienteering {

void writeLineBreak(QXmlStreamWriter& xml)
{
	if (!xml.autoFormatting())
	{
		static const QString linebreak = QLatin1String{"\n"};
		xml.writeCharacters(linebreak);
	}
}

QString numberToString(double value, int precision)
{
	auto number = QString::number(value, 'f', precision);
	auto i = number.length() - 1;
	if (number.contains(QLatin1Char('.')))
	{
		// Cut off trailing zeros
		while (i > 0 && number.at(i) == QLatin1Char('0'))
			--i;
		if (number.at(i) == QLatin1Char('.'))
			--i;
	}
	number.resize(++i);
	return number;
}

bool XmlRecoveryHelper::operator() ()
{
	auto offending_index_64 = xml.characterOffset();
	auto offending_message = xml.errorString();
	auto stream = xml.device();

	if (xml.hasError()
	    && offending_index_64 <= std::numeric_limits<int>::max()
	    && offending_index_64 > recovery_start
	    && stream
	    && stream->seek(0))
	{
		// Get the whole input
		auto raw_data = stream->readAll();

		// Determine the encoding
		QTextCodec* codec = nullptr;
		for (QXmlStreamReader probe(raw_data); !probe.atEnd(); probe.readNext())
		{
			if (probe.tokenType() == QXmlStreamReader::StartDocument)
			{
				codec = QTextCodec::codecForName(probe.documentEncoding().toLatin1());
				break;
			}
		}
		if (Q_UNLIKELY(!codec))
		{
			return false;
		}

		// Convert to QString, and release the raw data
		auto data = codec->toUnicode(raw_data);
		raw_data = {};

		// Loop until the current element is fixed
		for (auto index = int(offending_index_64 - 1); xml.hasError(); index = int(xml.characterOffset() - 1))
		{
			auto offending_char = static_cast<unsigned int>(data.at(index).unicode());
			if (xml.error() != QXmlStreamReader::NotWellFormedError
			    || offending_char == 0x9     // horizontal tab
			    || offending_char == 0xa  // line feed
			    || offending_char == 0xd  // carriage return
			    || (offending_char >= 0x20 && offending_char <= 0xfffd)
			    || offending_char > QChar::LastValidCodePoint)
			{
				// Another error than an invalid character
				break;
			}

			// Remove the offending character
			data.remove(index, 1);

			// Read again to the element start
			xml.clear();
			xml.addData(data);
			while (!xml.hasError() && xml.characterOffset() < recovery_start)
			{
				xml.readNext();
			}
			Q_ASSERT(!xml.hasError());

			// Read the current element completely
			xml.skipCurrentElement();
		}

		// Restore the XML stream state with the modified data.
		// We must use a QIODevice again, for later recovery attempts.
		auto buffer = new QBuffer(stream); // buffer will live as long as the original stream
		buffer->setData(codec->fromUnicode(data));
		buffer->open(QIODevice::ReadOnly);

		xml.clear();
		xml.setDevice(buffer);
		while (!xml.atEnd() && xml.characterOffset() < recovery_start)
		{
			xml.readNext();
		}

		if (xml.characterOffset() == recovery_start)
		{
			return true;
		}
		else if (!xml.hasError())
		{
			xml.raiseError(offending_message);
		}
	}
	return false;
}

void XmlElementWriter::write(const MapCoordVector& coords)
{
	namespace literal = XmlStreamLiteral;

	writeAttribute(literal::count, coords.size());

	if (XMLFileFormat::active_version < 6 || xml.autoFormatting())
	{
		// XMAP files and old format: syntactically rich output
		for (auto& coord : coords)
			coord.save(xml);
	}
	else if (auto* device = xml.device())
	{
		// Default: efficient plain text format
		// Direct UTF-8 writing without unnecessary allocations, escaping or
		// conversions, but also without handling of device errors.
		xml.writeCharacters({});  // Finish the start element
		MapCoord::StringBuffer<char> buffer;
		for (auto& coord : coords)
			device->write(coord.toUtf8(buffer));
	}
	else
	{
		// Default: efficient plain text format
		MapCoord::StringBuffer<QChar> buffer;
		for (auto& coord : coords)
			xml.writeCharacters(coord.toString(buffer));
	}
}

void OpenOrienteering::XmlElementWriter::write(const KeyValueContainer& tags)
{
	namespace literal = XmlStreamLiteral;

	for (auto const& tag : tags)
	{
		XmlElementWriter tag_element(xml, literal::t);
		tag_element.writeAttribute(literal::k, tag.key);
		xml.writeCharacters(tag.value);
	}
}

void XmlElementReader::read(MapCoordVector& coords)
{
	namespace literal = XmlStreamLiteral;

	coords.clear();

	const auto num_coords = attribute<unsigned int>(literal::count);
	coords.reserve(std::min(num_coords, 500000u));

	try
	{
		for( xml.readNext(); xml.tokenType() != QXmlStreamReader::EndElement; xml.readNext() )
		{
			const QXmlStreamReader::TokenType token = xml.tokenType();
			if (xml.error() || token == QXmlStreamReader::EndDocument)
			{
				throw FileFormatException(::OpenOrienteering::ImportExport::tr("Could not parse the coordinates."));
			}
			else if (token == QXmlStreamReader::Characters && !xml.isWhitespace())
			{
				QStringRef text = xml.text();
				try
				{
					while (text.length())
					{
						coords.emplace_back(text);
					}
				}
				catch (std::exception& e)
				{
					Q_UNUSED(e)
					qDebug("Could not parse the coordinates: %s", e.what());
					throw FileFormatException(::OpenOrienteering::ImportExport::tr("Could not parse the coordinates."));
				}
			}
			else if (token == QXmlStreamReader::StartElement)
			{
				if (xml.name() == literal::coord)
				{
					coords.emplace_back(MapCoord::load(xml));
				}
				else
				{
					xml.skipCurrentElement();
				}
			}
			// otherwise: ignore element
		}
	}
	catch (std::range_error &e)
	{
		throw FileFormatException(::OpenOrienteering::MapCoord::tr(e.what()));
	}

	if (coords.size() != num_coords)
	{
		throw FileFormatException(::OpenOrienteering::ImportExport::tr("Expected %1 coordinates, found %2."));
	}
}

void XmlElementReader::readForText(MapCoordVector& coords)
{
	namespace literal = XmlStreamLiteral;

	coords.clear();
	coords.reserve(2);

	const auto num_coords = attribute<unsigned int>(literal::count);

	QScopedValueRollback<MapCoord::BoundsOffset> offset{MapCoord::boundsOffset()};

	try
	{
		for( xml.readNext(); xml.tokenType() != QXmlStreamReader::EndElement; xml.readNext() )
		{
			const QXmlStreamReader::TokenType token = xml.tokenType();
			if (xml.error() || token == QXmlStreamReader::EndDocument)
			{
				throw FileFormatException(::OpenOrienteering::ImportExport::tr("Could not parse the coordinates."));
			}
			else if (token == QXmlStreamReader::Characters && !xml.isWhitespace())
			{
				QStringRef text = xml.text();

			}
			else if (token == QXmlStreamReader::StartElement)
			{
				if (xml.name() == literal::coord)
				{
					if (coords.size() == 1)
					{
						// Don't apply an offset to text box size.
						offset.commit();
						MapCoord::boundsOffset().reset(false);
					}
					coords.emplace_back(MapCoord::load(xml));
				}
				else
				{
					xml.skipCurrentElement();
				}
			}
			// otherwise: ignore element
		}
	}
	catch (std::range_error &e)
	{
		throw FileFormatException(::OpenOrienteering::MapCoord::tr(e.what()));
	}

	if (coords.size() != num_coords)
	{
		throw FileFormatException(::OpenOrienteering::ImportExport::tr("Expected %1 coordinates, found %2."));
	}
}

void OpenOrienteering::XmlElementReader::read(KeyValueContainer& tags)
{
	namespace literal = XmlStreamLiteral;

	tags.clear();
	while (xml.readNextStartElement())
	{
		if (xml.name() == literal::t)
		{
			const QString key(xml.attributes().value(literal::k).toString());
			tags.insert_or_assign(key, xml.readElementText());
		}
		else
		{
			xml.skipCurrentElement();
		}
	}
}

}  // namespace OpenOrienteering