#include "StdAfx.h"
#include "ExpatXmlParser.h"

CExpatXmlParser::CExpatXmlParser(void)
{
	m_init = FALSE;
}

CExpatXmlParser::~CExpatXmlParser(void)
{
	Close();
}



/////////////////////////////////////////////////////////////////////////////////////
//	開始
/////////////////////////////////////////////////////////////////////////////////////
/*!
	ファイルから取得
*/
CString CExpatXmlParser::LoadXmlFile(CString path)
{
	//	開く
	FILE	*in;
	if(_tfopen_s(&in, path, _T("rb")) != 0)
		throw CXMLTextParserException("ファイルのオープンに失敗しました", 0);
	
	//	サイズ取得
	fseek(in, 0, SEEK_END);
	long	len = ftell(in);
	fseek(in, 0, SEEK_SET);

	//	バッファ用意
	CStringA	ret;
	char	*buf = ret.GetBuffer(len);

	//	読み込み
	fread(buf, len, 1, in);
	ret.ReleaseBufferSetLength(len);
	fclose(in);

	return(ret);
}


/*!
	スキャン
*/
void CExpatXmlParser::StartScan(CStringA xmlUtf8)
{
	//	初期化
	if(Init())
		throw CXMLTextParserException("XMLパーサーの初期化に失敗しました", 0);

	//	解析
	if(XML_Parse(m_parser, xmlUtf8.GetBuffer(0), (int)xmlUtf8.GetLength(), TRUE) != XML_TRUE)
		throw CXMLTextParserException("XMLの解析に失敗しました", 0);
}


/////////////////////////////////////////////////////////////////////////////////////
//	補助
/////////////////////////////////////////////////////////////////////////////////////
/*!
	初期化
*/
int CExpatXmlParser::Init()
{
	if(!m_init)
	{
		//	初期化
		m_parser = XML_ParserCreate(NULL);
		if(m_parser == NULL)
			return(-1);

		//	ユーザーデータセット
		XML_SetUserData(m_parser, this);

		//	ハンドラセット
		XML_SetElementHandler(m_parser, StartElementHandler, EndElementHandler);
		XML_SetCharacterDataHandler(m_parser, CharacterDataHandler);
		m_init = TRUE;
	}
	else
	{
		//	リセット
		if(XML_ParserReset(m_parser, NULL) != XML_TRUE)
			return(-1);
	}
	return(0);
}

/*!
	終了
*/
void CExpatXmlParser::Close()
{
	if(m_init)
	{
		XML_ParserFree(m_parser);
	}
	m_init = FALSE;
}

/*!
	ASCII以外を含むかチェック
*/
int CExpatXmlParser::CheckUTF8(const XML_Char *str, int len)
{
	unsigned char *ptr = (unsigned char *)str;

	//	検索
	if(len == -1)
	{
		for(int i=0;*ptr;i++)
		{
			//	UTF8でASCII以外
			if(*ptr >= 0x80)
				return(1);
			ptr++;
		}
	}
	else
	{
		for(int i=0;i<len;i++)
		{
			//	UTF8でASCII以外
			if(*ptr >= 0x80)
				return(1);
			ptr++;
		}
	}

	return(0);
}


/*!
	Attr数チェック
*/
int CExpatXmlParser::GetAttrCount(LPCSTR *atts)
{
	//	数える
	int i;
	for(i=0;atts[i];i++)
		;
	return(i);
}


/////////////////////////////////////////////////////////////////////////////////////
//	コールバック
/////////////////////////////////////////////////////////////////////////////////////
/*!
	開始タグ
*/
void CExpatXmlParser::StartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts)
{
	CExpatXmlParser *obj = (CExpatXmlParser*)userData;

	//	SJISへ
	name = obj->m_sjis.ConvertToSJIS(name);
	for(int i=0;atts[i];i++)
		atts[i] = obj->m_sjis.ConvertToSJIS(atts[i]);

	//	コール
	obj->OnStartTag(name, atts);

	//	SJIS開放
	obj->m_sjis.Cleanup();
//	TRACE("Start %s\n", name);
}

/*!
	終了タグ
*/
void CExpatXmlParser::EndElementHandler(void *userData, const XML_Char *name)
{
	CExpatXmlParser *obj = (CExpatXmlParser*)userData;

	//	SJISへ
	name = obj->m_sjis.ConvertToSJIS(name);

	//	コール
	obj->OnEndTag(name);

	//	開放
	obj->m_sjis.Cleanup();
//	TRACE("End %s\n", name);
}

/*!
	データ
*/
void CExpatXmlParser::CharacterDataHandler(void *userData, const XML_Char *s, int len)
{
	CExpatXmlParser *obj = (CExpatXmlParser*)userData;

	//	SJISへ
	s = obj->m_sjis.ConvertToSJIS(s, len);

	//	コール
	obj->OnData(s, len);

	//	SJIS開放
	obj->m_sjis.Cleanup();
}


/////////////////////////////////////////////////////////////////////////////////////
//	CExpatXmlParserUTF8Convert
/////////////////////////////////////////////////////////////////////////////////////
/*!
	コンストラクタ
*/
CExpatXmlParserUTF8Convert::CExpatXmlParserUTF8Convert() : 
	m_extUtf16Buf(0)
{
	m_sjisBufUsing = 0;
}

/*!
	デストラクタ
*/
CExpatXmlParserUTF8Convert::~CExpatXmlParserUTF8Convert()
{
	Cleanup();
}

/*!
	取得
*/
LPCSTR CExpatXmlParserUTF8Convert::ConvertToSJIS(LPCSTR utf8, int &len)
{
	//	変換の必要はあるか？
	if(!CheckUTF8(utf8, len))
		return(utf8);
	
	//	長さ取得
	if(len == -1)
		len = strlen(utf8);

	//	UTF16の長さ取得
	int wbLen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);

	//	UTF16へ変換
	wchar_t *utf16 = AllocUTF16Buf(wbLen + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, wbLen);

	//	SJISの長さ取得
	len = WideCharToMultiByte(CP_ACP, 0, utf16, wbLen, NULL, 0, NULL, NULL);

	//	SJISへ
	CHAR *sjis = AllocString(len + 1);
	WideCharToMultiByte(CP_ACP, 0, utf16, wbLen, sjis, len + 1, NULL, NULL);
	sjis[len] = 0;

	return(sjis);
}

/*!
	掃除
*/
void CExpatXmlParserUTF8Convert::Cleanup()
{
	m_sjisBufUsing = 0;

	//	拡張バッファ削除
	if(m_extSjisBuf.GetSize() > 0)
	{
		for(int i=0;i<m_extSjisBuf.GetSize();i++)
			delete m_extSjisBuf[i];
		m_extSjisBuf.RemoveAll();
	}
}


/*!
	C文字列へ
*/
LPCSTR CExpatXmlParserUTF8Convert::ToCString(const CHAR *buf, int len)
{
	CHAR *ret = AllocString(len + 1);
	memmove(ret, buf, len);
	ret[len] = 0;

	return(ret);
}

/////////////////////////////////////////////////////////////////////////////////////
//	補助
/////////////////////////////////////////////////////////////////////////////////////
/*!
	ASCII以外を含むかチェック
*/
int CExpatXmlParserUTF8Convert::CheckUTF8(LPCSTR str, int len)
{
	unsigned char *ptr = (unsigned char *)str;

	//	検索
	if(len == -1)
	{
		for(int i=0;*ptr;i++)
		{
			//	UTF8でASCII以外
			if(*ptr >= 0x80)
				return(1);
			ptr++;
		}
	}
	else
	{
		for(int i=0;i<len;i++)
		{
			//	UTF8でASCII以外
			if(*ptr >= 0x80)
				return(1);
			ptr++;
		}
	}

	return(0);
}

/*!
	確保
*/
LPSTR CExpatXmlParserUTF8Convert::AllocString(int len)
{
	//	拡張に確保の必要有り
	if(len >= EXPAT_SJIS_STRING_BUF_LEN || m_sjisBufUsing >= EXPAT_SJIS_STRING_BUF_COUNT)
		return(AllocExtString(len));

	return(m_sjisBuf[m_sjisBufUsing++]);
}

/*!
	拡張バッファ確保
*/
LPSTR CExpatXmlParserUTF8Convert::AllocExtString(int len)
{
	//	バッファ確保
	CHAR *buf = new CHAR[len];
	m_extSjisBuf.Add(buf);

	return(buf);
}

//!	UTF16バッファ取得
wchar_t *CExpatXmlParserUTF8Convert::AllocUTF16Buf(int count)
{
	//	確保の必要なし？
	if(count < EXPAT_UTF16_STRING_BUF_COUNT)
		return(m_utf16Buf);

	//	確保
	m_extUtf16Buf.Alloc(count);
	return(m_extUtf16Buf);
}
