/*	
 *	tixml.c
 *
 *	XML DOM parser
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2006 Naoyuki Sawa
 *
 *	* Sat Nov 25 20:20:00 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	- TinyXml version 1.2.4 を参考にして、作成しました。
 *	  以下に、オリジナルの TinyXml version 1.2.4 から Copyright 文をを引用します。
 *	  ------------------------------------------------------------------------
 *	  Copyright (c) 2000 Lee Thomason (www.grinninglizard.com)
 *	  
 *	  This software is provided 'as-is', without any express or implied 
 *	  warranty. In no event will the authors be held liable for any 
 *	  damages arising from the use of this software.
 *	  
 *	  Permission is granted to anyone to use this software for any 
 *	  purpose, including commercial applications, and to alter it and 
 *	  redistribute it freely, subject to the following restrictions:
 *	  
 *	  1. The origin of this software must not be misrepresented; you must 
 *	  not claim that you wrote the original software. If you use this 
 *	  software in a product, an acknowledgment in the product documentation 
 *	  would be appreciated but is not required.
 *	  
 *	  2. Altered source versions must be plainly marked as such, and 
 *	  must not be misrepresented as being the original software.
 *	  
 *	  3. This notice may not be removed or altered from any source 
 *	  distribution.
 *	  ------------------------------------------------------------------------
 *	- 基本的には、TinyXml の設計そのままで、C++→C言語に移植しただけです。
 *	  ただし、エラー処理を削除して強制終了に変更する等、大幅に簡略化しました。
 *	- TinyXml version 1.2.4 はかなり旧いバージョンなので、いくつか誤りが有ります。
 *	  新しい、TinyXml version 2.5.2 のソースも参考し、気付いた誤りは修正しました。
 */
#include "clip.h"

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

/* 空白をスキップします。
 * [in]
 *	p		走査開始位置のポインタ。
 * [out]
 *	戻り値		空白以外の文字、または、終端のnulへのポインタ。
 */
static const char*
SkipWhiteSpace(const char* p)
{
	while(isspace(*p)) {
		p++;
	}

	return p;
}

/* タグ名、または、属性名を読み取ります。
 * [in]
 *	p		名称の一文字目へのポインタ。
 *	name		名称を格納する文字列へのポインタ。
 * [out]
 *	戻り値		名称の直後へのポインタ。
 *	name		名称が格納されています。
 * [note]
 *	* この関数が呼ばれた時、nameは空文字列の状態であることが前提です。
 *	  空文字列でないnameを指定して呼び出すと、正しい結果となりません。
 */
static const char*
ReadName(const char* p, /*[out]*/ StdString* name)
{
	int c;

	/* 名称が、アルファベットまたはアンダースコアで始まっていることを確認します。 */
	c = *p;
	if(isalpha(c) || c == '_') {
		do {
			/* 名称に、一文字追加します。 */
			StdString_append(name, (char*)&c);

			/* ポインタを次の文字の位置へ進め、一文字取得します。 */
			c = *++p;

		/* 二文字目以降は、アルファベット、数値、アンダースコア、ハイフン、コロンです。
		 * (TinyXMLは、名前空間のプレフィクスも名称に含めて扱うため、コロンを含めます。)
		 */
		} while(isalnum(c) || c == '_' || c == '-' || c == ':');

		/* 名称以外の文字に出会ったら、完了し、その位置のポインタを返します。 */
		return p;
	}

	/* アルファベットまたはアンダースコアを指した状態で呼ばれなければなりません。 */
	DIE();
}

/* ドキュメント直下のノード{宣言,要素,コメント,不明}を識別して作成し、パースします。
 * [in]
 *	where		ノード先頭の「<」へのポインタへのポインタ。
 * [out]
 *	where		ノード末尾の「>」の直後へのポインタで更新。
 */
static TiXmlNode*
IdentifyAndParse(const char** where)
{
	TiXmlNode* node;

	/* ポインタを取り出します。 */
	const char* p = *where;

	/* 「<」を指した状態で呼ばれなければなりません。 */
	if(*p != '<') {
		DIE();
	}

	/* 「<」の後の空白をスキップします。 */
	p = SkipWhiteSpace(p + 1);

	/* 「?xml」ならば、宣言ノードを作成します。 */
	if(tolower(p[0]) == '?' &&
	   tolower(p[1]) == 'x' &&
	   tolower(p[2]) == 'm' &&
	   tolower(p[3]) == 'l') {
		node = TiXmlDeclaration_super(TiXmlDeclaration_new(NULL, NULL, NULL));

	/* アルファベットまたはアンダースコアで始まるタグ名ならば、要素ノードを作成します。 */
	} else if(isalpha(*p) || *p == '_') {
		node = TiXmlElement_super(TiXmlElement_new(NULL));

	/* 「!--」ならば、コメントを作成します。 */
	} else if(p[0] == '!' &&
	          p[1] == '-' &&
	          p[2] == '-') {
		node = TiXmlComment_super(TiXmlComment_new());

	/* それ以外は、不明ノードを作成します。 */
	} else {
		node = TiXmlUnknown_super(TiXmlUnknown_new());
	}

	/* ノードの内容をパースします。 */
	p = node->vptr->Parse(node, p);

	/* ポインタを書き戻します。 */
	*where = p;

	/* 作成、パースしたノードを返します。 */
	return node;
}

/* インデントを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
static void
Indent(FILE* fp, int depth)
{
	int i;

	for(i = 0; i < depth; i++) {
		fprintf(fp, "\t");
	}
}

/****************************************************************************
 *	StdString
 ****************************************************************************/

/* * Tue Dec 05 00:37:14 JST 2006 Naoyuki Sawa
 * - StdString.bufのメモリ割り当て単位を定義します。
 *   この値を大きくするほどメモリ割り当て回数は減り、高速化しますが、メモリ使用効率が悪くなります。
 * - 任意の(2^N)の値に調整可能ですが、4未満には設定しないでください。
 *   P/ECEカーネル内部のメモリ割り当ては4バイト単位に切り上げられるので、4未満にしてもメモリ使用効率は改善されません。
 * - 実際に格納する文字列の平均的な長さに近いほど、速度とメモリ使用効率のバランスが良くなります。
 *   8または16程度が適切かと思いますが、まずは、最低限の4で試してみることにします。(2006/12/05現在)
 */
#define StdString_BufUnit	(1<<2)

/* 文字列を作成します。
 * [in]
 *	p		文字列の初期値へのポインタ。
 *			NULLを指定すると、空文字列を作成します。
 */
StdString*
StdString_new(const char* p/*=NULL*/)
{
	StdString* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_StdString_construct(This, p);
	return This;
}

/* 文字列を削除します。
 */
void
StdString_delete(StdString* This)
{
	if(This) {
		/** no virtual destructor **/
		_StdString_destruct(This);
		free(This);
	}
}

/* 文字列のコンストラクタです。
 * [in]
 *	p		文字列の初期値へのポインタ。
 *			NULLを指定すると、空文字列に初期化します。
 */
void
_StdString_construct(StdString* This, const char* p/*=NULL*/)
{
	/** no base class **/
	/** no vptr **/

	StdString_assign(This, p);
}

/* 文字列のデストラクタです。
 */
/*virtual*/ void
_StdString_destruct(StdString* This)
{
	free(This->buf/*NULLOK*/);

	/** no base class **/
}

/* ヌル終端文字列へのポインタを取得します。
 * [out]
 *	戻り値		ヌル終端文字列へのポインタ。
 */
const char*
StdString_c_str(StdString* This)
{
	return This->buf ? This->buf : "";
}

/* 文字列を設定します。
 * [in]
 *	p		文字列の設定値へのポインタ。
 *			NULLを指定すると、空文字列に設定します。
 */
void
StdString_assign(StdString* This, const char* p/*=NULL*/)
{
	int len1;
	int cap1;
	int len2;
	int cap2;

	/* 空文字列の代入ならば、バッファを開放します。 */
	if(!p || !*p) {
		free(This->buf/*NULLOK*/);
		This->buf = NULL;
		return; /* ここまで */
	}

	/* 現在の文字数と、現在のバッファサイズを求めます。 */
	if(This->buf) {
		len1 = strlen(This->buf);
		cap1 = ((len1 + 1/*nul*/) + (StdString_BufUnit - 1)) & ~(StdString_BufUnit - 1);
	} else {
		len1 = 0;
		cap1 = 0;
	}

	/* 代入する文字数と、代入に必要なバッファサイズを求めます。 */
	len2 = strlen(p);
	cap2 = ((len2 + 1/*nul*/) + (StdString_BufUnit - 1)) & ~(StdString_BufUnit - 1);

	/* バッファサイズが変化したら、再割り当てします。 */
	if(cap1 != cap2) {
		This->buf = realloc(This->buf/*NULLOK*/, cap2);
		if(!This->buf) {
			DIE();
		}
	}

	/* 代入する文字列をコピーします。 */
	memcpy(This->buf, p, len2 + 1/*nul*/);
}

/* 文字列を追加します。
 * [in]
 *	p		追加する文字列へのポインタ。
 *			NULLを指定すると、何も行いません。
 */
void
StdString_append(StdString* This, const char* p/*=NULL*/)
{
	int len1;
	int cap1;
	int len2;
	int cap2;

	/* 空文字列の連結ならば、何もしません。 */
	if(!p || !*p) {
		return; /* ここまで */
	}

	/* 現在の文字数と、現在のバッファサイズを求めます。 */
	if(This->buf) {
		len1 = strlen(This->buf);
		cap1 = ((len1 + 1/*nul*/) + (StdString_BufUnit - 1)) & ~(StdString_BufUnit - 1);
	} else {
		len1 = 0;
		cap1 = 0;
	}

	/* 連結する文字数と、連結に必要なバッファサイズを求めます。 */
	len2 = strlen(p);
	cap2 = ((len1 + len2 + 1/*nul*/) + (StdString_BufUnit - 1)) & ~(StdString_BufUnit - 1);

	/* バッファサイズが変化したら、再割り当てします。 */
	if(cap1 != cap2) {
		This->buf = realloc(This->buf/*NULLOK*/, cap2);
		if(!This->buf) {
			DIE();
		}
	}

	/* 代入する文字列をコピーします。 */
	memcpy(This->buf + len1, p, len2 + 1/*nul*/);
}

/****************************************************************************
 *	TiXmlBase
 ****************************************************************************/

static const TiXmlBase_vtbl _TiXmlBase_vtbl = {
	_TiXmlBase_destruct,	/*destruct*/
	NULL,			/*Print*/
	/*↑TiXmlBase_vtbl↑*/
};

/* XML DOMオブジェクトを削除します。
 */
void
TiXmlBase_delete(TiXmlBase* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* XML DOMオブジェクトのコンストラクタです。
 */
void
_TiXmlBase_construct(TiXmlBase* This)
{
	/** no base class **/
	This->vptr = &_TiXmlBase_vtbl;
}

/* XML DOMオブジェクトのデストラクタです。
 */
/*virtual*/ void
_TiXmlBase_destruct(TiXmlBase* This)
{
	/** no base class **/
}

/****************************************************************************
 *	TiXmlNode
 ****************************************************************************/

static const TiXmlNode_vtbl _TiXmlNode_vtbl = {
	_TiXmlNode_destruct,	/*destruct*/
	NULL,			/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	NULL,			/*Clone*/
	NULL,			/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
};

/* XMLノードを削除します。
 */
void
TiXmlNode_delete(TiXmlNode* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* XMLノードのコンストラクタです。
 */
void
_TiXmlNode_construct(TiXmlNode* This)
{
	_TiXmlBase_construct(TiXmlNode_super(This));
	This->vptr = &_TiXmlNode_vtbl;

	/* 値を作成します。 */
	This->value = StdString_new(NULL);
}

/* XMLノードのデストラクタです。
 * [note]
 *	- オリジナルの TinyXml version 1.2.4 と違い、本ライブラリは子ノード追加時にコピーを作成しない仕様です。
 *	  (TiXmlNode_InsertEndChild()のコメントを参照してください。)
 *	  ただしデストラクタにおいては、オリジナルの TinyXml version 1.2.4 と同じく、子ノードを全て削除します。
 *	  追加時(コピーを作成しない)との対称性に欠けますが、利便性を優先してこのような仕様としました。
 *	- 子ノードの追加時に、その子ノードの所有権が親ノードに移る(親ノードが削除する)、と考えてください。
 *	  TiXmlNode_ReplaceChild()、または、TiXmlNode_RemoveChild()で取り外すと、親ノードから所有権が戻ります。
 */
/*virtual*/ void
_TiXmlNode_destruct(TiXmlNode* This)
{
	/* 子ノードを全て削除します。 */
	TiXmlNode_Clear(This);

	/* 値を削除します。 */
	StdString_delete(This->value);

	_TiXmlBase_destruct(TiXmlNode_super(This));
}

/* 値を取得します。
 * [out]
 *	戻り値		値。
 * [note]
 *	* 値の用途は、派生クラス毎に異なります。
 */
const char*
TiXmlNode_Value(TiXmlNode* This)
{
	return StdString_c_str(This->value);
}

/* 値を設定します。
 * [in]
 *	value		値。
 * [note]
 *	* 値の用途は、派生クラス毎に異なります。
 */
void
TiXmlNode_SetValue(TiXmlNode* This, const char* value)
{
	StdString_assign(This->value, value);
}

/* 子ノードを全て削除します。
 */
void
TiXmlNode_Clear(TiXmlNode* This)
{
	TiXmlNode* node = This->firstChild;

	while(node) {
		TiXmlNode* next = node->next;
		TiXmlNode_delete(node);
		node = next;
	}

	This->firstChild = NULL;
	This->lastChild = NULL;
}

/* 先頭の子ノードを取得します。
 * [in]
 *	value		この値に一致する子ノードのうち、先頭の子ノードを取得します。
 *			NULLを指定した場合、単純に、先頭の子ノードを取得します。
 * [out]
 *	戻り値		条件に一致する子ノードが有れば、そのポインタを返します。
 *			条件に一致する子ノードが無ければ、NULLを返します。
 */
TiXmlNode*
TiXmlNode_FirstChild(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = This->firstChild;
	    node;
	    node = node->next) {
		if(!value ||
		   !strcmp(TiXmlNode_Value(node), value)) {
			return node;
		}
	}

	return NULL;
}

/* 末尾の子ノードを取得します。
 * [in]
 *	value		この値に一致する子ノードのうち、末尾の子ノードを取得します。
 *			NULLを指定した場合、単純に、末尾の子ノードを取得します。
 * [out]
 *	戻り値		条件に一致する子ノードが有れば、そのポインタを返します。
 *			条件に一致する子ノードが無ければ、NULLを返します。
 */
TiXmlNode*
TiXmlNode_LastChild(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = This->lastChild;
	    node;
	    node = node->prev) {
		if(!value ||
		   !strcmp(TiXmlNode_Value(node), value)) {
			return node;
		}
	}

	return NULL;
}

/* 子ノードを走査します。
 * [in]
 *	value		この値に一致する子ノードを走査します。
 *			NULLを指定した場合、全ての子ノードを走査します。
 *	previous	初回は、NULLを指定してください。
 *			二回目以降は、前回の戻り値を指定してください。
 * [out]
 *	戻り値		条件に一致する子ノードがまだ有れば、そのポインタを返します。
 *			条件に一致する子ノードがもう無くなったら、NULLを返します。
 * [note]
 *	- 以下の例のように利用してください。
 *		TiXmlNode* child = NULL;
 *		while((child = TiXmlNode_IterateChildren(parent, value, child) != NULL) {
 *			// childを使って処理を行う //
 *		}
 */
TiXmlNode*
TiXmlNode_IterateChildren(TiXmlNode* This, const char* value/*=NULL*/, TiXmlNode* previous)
{
	if(!previous) {
		return TiXmlNode_FirstChild(This, value);
	} else {
		return TiXmlNode_NextSibling(previous, value);
	}
}

/* 末尾に子ノードを追加します。
 * [in]
 *	addThis		追加する子ノード。
 * [note]
 *	- オリジナルのTinyXml version 1.2.4は、指定された子ノード自身でなく、コピーを作成して追加する仕様でした。
 *	  本ライブラリでは、コピーでなく、指定された子ノード自身を追加するよう、仕様を変更しました。
 *	  コピー元のオブジェクトをスタック上の値オブジェクトとして作成できるC++言語版と違って、
 *	  C言語版では常にヒープ上の参照オブジェクトとして作成するので、コピーする意味が少ないと判断したためです。
 */
void
TiXmlNode_InsertEndChild(TiXmlNode* This, TiXmlNode* addThis)
{
	addThis->prev = This->lastChild;
	addThis->next = NULL;

	if(This->lastChild) {
		This->lastChild->next = addThis;
	} else {
		This->firstChild = addThis;
	}
	This->lastChild = addThis;
}

/* 指定位置の直前に、子ノードを追加します。
 * [in]
 *	beforeThis	位置を指定する子ノード。
 *	addThis		追加する子ノード。
 * [note]
 *	- コピーではなく、指定された子ノード自身を追加します。
 *	  TiXmlNode_InsertEndChild()のコメントを参照してください。
 */
void
TiXmlNode_InsertBeforeChild(TiXmlNode* This, TiXmlNode* beforeThis, TiXmlNode* addThis)
{
	addThis->next = beforeThis;
	addThis->prev = beforeThis->prev;

	if(beforeThis->prev) {
		beforeThis->prev->next = addThis;
	} else {
		This->firstChild = addThis;
	}
	beforeThis->prev = addThis;
}

/* 指定位置の直後に、子ノードを追加します。
 * [in]
 *	afterThis	位置を指定する子ノード。
 *	addThis		追加する子ノード。
 * [note]
 *	- コピーではなく、指定された子ノード自身を追加します。
 *	  TiXmlNode_InsertEndChild()のコメントを参照してください。
 */
void
TiXmlNode_InsertAfterChild(TiXmlNode* This, TiXmlNode* afterThis, TiXmlNode* addThis)
{
	addThis->prev = afterThis;
	addThis->next = afterThis->next;

	if(afterThis->next) {
		afterThis->next->prev = addThis;
	} else {
		This->lastChild = addThis;
	}
	afterThis->next = addThis;
}

/* 指定した子ノードをリンクから取り外し、同じ位置に、代わりに別の子ノードをリンクします。
 * [in]
 *	replaceThis	リンクから取り外す子ノード。
 *	withThis	代わりにリンクする子ノード。
 * [note]
 *	- コピーではなく、指定された子ノード自身を追加します。
 *	  TiXmlNode_InsertEndChild()のコメントを参照してください。
 *	- オリジナルのTinyXml version 1.2.4は、取り外した子ノード(replaceThis)は自動的に削除される仕様でした。
 *	  本ライブラリでは、取り外した子ノードを自動的に削除しない仕様に変更しました。
 *	  追加時(コピーを作成しない)との対称性を維持するための仕様変更で、利便性が理由ではありません。
 *	  取り外した子ノードは、不要ならば明示的に削除するよう、注意してください。
 */
void
TiXmlNode_ReplaceChild(TiXmlNode* This, TiXmlNode* replaceThis, TiXmlNode* withThis)
{
	withThis->next = replaceThis->next;
	withThis->prev = replaceThis->prev;

	if(replaceThis->next) {
		replaceThis->next->prev = withThis;
	} else {
		This->lastChild = withThis;
	}
	if(replaceThis->prev) {
		replaceThis->prev->next = withThis;
	} else {
		This->firstChild = withThis;
	}

	replaceThis->next = NULL;
	replaceThis->prev = NULL;
}

/* 子ノードをリンクから取り外します。
 * [in]
 *	removeThis	リンクから取り外す子ノード。
 * [note]
 *	- オリジナルのTinyXml version 1.2.4は、取り外した子ノード(removeThis)は自動的に削除される仕様でした。
 *	  本ライブラリでは、取り外した子ノードを自動的に削除しない仕様に変更しました。
 *	  追加時(コピーを作成しない)との対称性を維持するための仕様変更で、利便性が理由ではありません。
 *	  取り外した子ノードは、不要ならば明示的に削除するよう、注意してください。
 */
void
TiXmlNode_RemoveChild(TiXmlNode* This, TiXmlNode* removeThis)
{
	if(removeThis->next) {
		removeThis->next->prev = removeThis->prev;
	} else {
		This->lastChild = removeThis->prev;
	}
	if(removeThis->prev) {
		removeThis->prev->next = removeThis->next;
	} else {
		This->firstChild = removeThis->next;
	}

	removeThis->next = NULL;
	removeThis->prev = NULL;
}

/* 次の兄弟ノードを取得します。
 * [in]
 *	value		この値に一致する兄弟ノードのうち、次の兄弟ノードを取得します。
 *			NULLを指定した場合、単純に、次の兄弟ノードを取得します。
 * [out]
 *	戻り値		条件に一致する兄弟ノードが有れば、そのポインタを返します。
 *			条件に一致する兄弟ノードが無ければ、NULLを返します。
 */
TiXmlNode*
TiXmlNode_NextSibling(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = This->next;
	    node;
	    node = node->next) {
		if(!value ||
		   !strcmp(TiXmlNode_Value(node), value)) {
			return node;
		}
	}

	return NULL;
}

/* 前の兄弟ノードを取得します。
 * [in]
 *	value		この値に一致する兄弟ノードのうち、前の兄弟ノードを取得します。
 *			NULLを指定した場合、単純に、前の兄弟ノードを取得します。
 * [out]
 *	戻り値		条件に一致する兄弟ノードが有れば、そのポインタを返します。
 *			条件に一致する兄弟ノードが無ければ、NULLを返します。
 */
TiXmlNode*
TiXmlNode_PreviousSibling(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = This->prev;
	    node;
	    node = node->prev) {
		if(!value ||
		   !strcmp(TiXmlNode_Value(node), value)) {
			return node;
		}
	}

	return NULL;
}

/* 要素ノードに限定して、次の兄弟ノードを取得します。
 * [in]
 *	value		この値に一致する兄弟ノードのうち、次の兄弟ノードを取得します。
 *			NULLを指定した場合、単純に、次の兄弟ノードを取得します。
 * [out]
 *	戻り値		条件に一致する兄弟ノードが有れば、そのポインタを返します。
 *			条件に一致する兄弟ノードが無ければ、NULLを返します。
 */
TiXmlElement*
TiXmlNode_NextSiblingElement(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = TiXmlNode_NextSibling(This, value);
	    node;
	    node = TiXmlNode_NextSibling(node, value)) {
		if(TiXmlNode_ToElement(node)) {
			return TiXmlNode_ToElement(node);
		}
	}

	return NULL;
}

/* 要素ノードに限定して、先頭の子ノードを取得します。
 * [in]
 *	value		この値に一致する子ノードのうち、先頭の子ノードを取得します。
 *			NULLを指定した場合、単純に、先頭の子ノードを取得します。
 * [out]
 *	戻り値		条件に一致する子ノードが有れば、そのポインタを返します。
 *			条件に一致する子ノードが無ければ、NULLを返します。
 */
TiXmlElement*
TiXmlNode_FirstChildElement(TiXmlNode* This, const char* value/*=NULL*/)
{
	TiXmlNode* node;

	for(node = TiXmlNode_FirstChild(This, value);
	    node;
	    node = TiXmlNode_NextSibling(node, value)) {
		if(TiXmlNode_ToElement(node)) {
			return TiXmlNode_ToElement(node);
		}
	}

	return NULL;
}

/****************************************************************************
 *	TiXmlElement
 ****************************************************************************/

static const TiXmlElement_vtbl _TiXmlElement_vtbl = {
	_TiXmlElement_destruct,	/*destruct*/
	_TiXmlElement_Print,	/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlElement_Clone,	/*Clone*/
	_TiXmlElement_Parse,	/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlElement_vtbl↑*/
};

/* 要素ノードを作成します。
 * [in]
 *	value		要素名。
 *			NULLを指定すると、空文字列と見なします。
 */
TiXmlElement*
TiXmlElement_new(const char* value/*=NULL*/)
{
	TiXmlElement* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlElement_construct(This, value);
	return This;
}

/* 要素ノードを削除します。
 */
void
TiXmlElement_delete(TiXmlElement* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* 要素ノードのコンストラクタです。
 * [in]
 *	value		要素名。
 *			NULLを指定すると、空文字列と見なします。
 */
void
_TiXmlElement_construct(TiXmlElement* This, const char* value/*=NULL*/)
{
	_TiXmlNode_construct(TiXmlElement_super(This));
	This->vptr = &_TiXmlElement_vtbl;

	/* 属性セットを作成します。 */
	This->attributeSet = TiXmlAttributeSet_new();

	/* 要素名お設定します。 */
	StdString_assign(This->value, value);
}

/* 要素ノードのデストラクタです。
 */
/*virtual*/ void
_TiXmlElement_destruct(TiXmlElement* This)
{
	/* 属性セットを削除します。 */
	TiXmlAttributeSet_delete(This->attributeSet);

	_TiXmlNode_destruct(TiXmlElement_super(This));
}

/* 属性値を取得します。
 * [in]
 *	name		属性名。
 * [out]
 *	戻り値		属性値。
 *			指定された属性名に一致する属性が無い場合は、NULLを返します。
 */
const char*
TiXmlElement_Attribute(TiXmlElement* This, const char* name)
{
	TiXmlAttribute* attribute = TiXmlAttributeSet_Find(This->attributeSet, name);

	if(attribute) {
		return TiXmlAttribute_Value(attribute);
	}

	return NULL;
}

/* 属性を設定します。
 * [in]
 *	name		属性名。
 *	value		属性値。
 * [note]
 *	- 既に同じ属性名の属性が設定されていた場合は、属性値を置き換えます。
 */
void
TiXmlElement_SetAttribute(TiXmlElement* This, const char* name, const char* value)
{
	TiXmlAttribute* attribute = TiXmlAttributeSet_Find(This->attributeSet, name);

	if(attribute) {
		TiXmlAttribute_SetValue(attribute, value);
		return;
	}

	attribute = TiXmlAttribute_new(name, value);
	TiXmlAttributeSet_Add(This->attributeSet, attribute);
}

/* 属性を削除します。
 * [in]
 *	name		属性名。
 * [note]
 *	- 指定された属性名に一致する属性が無い場合は、何も行いません。
 */
void
TiXmlElement_RemoveAttribute(TiXmlElement* This, const char* name)
{
	TiXmlAttribute* attribute = TiXmlAttributeSet_Find(This->attributeSet, name);

	if(attribute) {
		TiXmlAttributeSet_Remove(This->attributeSet, attribute);
		TiXmlAttribute_delete(attribute);
	}
}

/* 先頭の属性を取得します。
 * [out]
 *	戻り値		属性のポインタ。
 *			属性が無い場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlElement_FirstAttribute(TiXmlElement* This)
{
	return TiXmlAttributeSet_First(This->attributeSet);
}

/* 末尾の属性を取得します。
 * [out]
 *	戻り値		属性のポインタ。
 *			属性が無い場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlElement_LastAttribute(TiXmlElement* This)
{
	return TiXmlAttributeSet_Last(This->attributeSet);
}

/* 要素ノードを複製します。
 * [out]
 *	戻り値		複製した要素ノード。
 */
/*virtual*/ TiXmlNode*
_TiXmlElement_Clone(TiXmlElement* This)
{
	TiXmlElement* clone = TiXmlElement_new(StdString_c_str(This->value));	/* 要素名を複製 */
	TiXmlAttribute* attribute;
	TiXmlNode* node;

	/* 属性セットを複製 */
	for(attribute = TiXmlAttributeSet_First(This->attributeSet);
	    attribute;
	    attribute = TiXmlAttribute_Next(attribute)) {
		TiXmlElement_SetAttribute(clone, TiXmlAttribute_Name(attribute), TiXmlAttribute_Value(attribute));
	}

	/* 子ノードを複製 */
	for(node = This->firstChild;
	    node;
	    node = TiXmlNode_NextSibling(node, NULL)) {
		TiXmlNode_InsertEndChild(TiXmlElement_super(clone), node->vptr->Clone(node));
	}

	return TiXmlElement_super(clone);
}

/* 要素ノードを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
/*virtual*/ void
_TiXmlElement_Print(TiXmlElement* This, FILE* fp, int depth)
{
	TiXmlAttribute* attribute;
	TiXmlNode* node;

	Indent(fp, depth);
	fprintf(fp, "<%s", StdString_c_str(This->value));

	for(attribute = TiXmlAttributeSet_First(This->attributeSet);
	    attribute;
	    attribute = TiXmlAttribute_Next(attribute)) {
		fprintf(fp, " ");
		attribute->vptr->Print(attribute, fp, 0);
	}

	if(This->firstChild) {
		fprintf(fp, ">");
		for(node = This->firstChild;
		    node;
		    node = TiXmlNode_NextSibling(node, NULL)) {
			if(!TiXmlNode_ToText(node)) {
				fprintf(fp, "\n");
			}
			node->vptr->Print(node, fp, depth + 1);
		}
		fprintf(fp, "\n");
		Indent(fp, depth);
		fprintf(fp, "</%s>", StdString_c_str(This->value));
	} else {
		fprintf(fp, " />");
	}
}

/* 要素ノードをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- 要素ノード作成直後に呼ばれることが前提です。
 *	  既に要素名が設定されていたり、属性や子ノードが追加された状態でパースすると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlElement_Parse(TiXmlElement* This, const char* p)
{
	TiXmlAttribute* attribute;
	int len;

	/* 要素名を取得します。 */
	p = ReadName(p, This->value);

	for(;;) {
		/* 空白をスキップします。 */
		p = SkipWhiteSpace(p);

		/* 「/>」を見つけたら、空要素タグです。 */
		if(*p == '/') {
			if(p[1] != '>') {
				DIE();
			}

			/* 「/>」の直後へのポインタを返します。 */
			return p + 2;

		/* 「>」を見つけたら、開始タグです。 */
		} else if(*p == '>') {
			/* 要素の内容を取得します。 */
			p = TiXmlElement_ReadValue(This, p + 1);

			/* 終了タグを確認します。 */
			len = strlen(StdString_c_str(This->value));
			if(p[0] != '<' ||
			   p[1] != '/' ||
			   strncmp(p + 2, StdString_c_str(This->value), len) ||
			   p[2 + len] != '>') {
				DIE();
			}

			/* 終了タグの直後へのポインタを返します。 */
			return p + 2/*「</」*/ + len/*value*/ + 1/*「>」*/;

		/* それ以外ならば、属性と見なして取得してみます。 */
		} else {
			attribute = TiXmlAttribute_new(NULL, NULL);
			p = TiXmlAttribute_Parse(attribute, p);
			TiXmlElement_SetAttribute(This, TiXmlAttribute_Name(attribute), TiXmlAttribute_Value(attribute));
			TiXmlAttribute_delete(attribute);
		}
	}
}

/* 開始タグと終了タグの間をパースします。
 * [in]
 *	p		開始タグ直後の位置へのポインタ。
 * [out]
 *	戻り値		終了タグの先頭位置へのポインタ。
 */
const char*
TiXmlElement_ReadValue(TiXmlElement* This, const char* p)
{
	TiXmlText* text;
	TiXmlNode* node;

	for(;;) {
		/* テキストが有れば、子ノードとして追加します。 */
		text = TiXmlText_new();
		p = text->vptr->Parse(text, p);
		if(*TiXmlNode_Value(TiXmlText_super(text))) {
			TiXmlNode_InsertEndChild(TiXmlElement_super(This), TiXmlText_super(text));
		} else {
			TiXmlText_delete(text);
		}

		/* テキスト以外ならば子要素の開始タグ、または、自身の終了タグです。 */
		if(p[0] != '<') {
			DIE();
		}
		if(p[1] != '/') {
			/* 子要素をパースし、子ノードとして追加します。 */
			node = IdentifyAndParse(&p);
			TiXmlNode_InsertEndChild(TiXmlElement_super(This), node);
		} else {
			/* 自身の終了タグの先頭位置へのポインタを返します。 */
			return p;
		}
	}
}

/****************************************************************************
 *	TiXmlComment
 ****************************************************************************/

static const TiXmlComment_vtbl _TiXmlComment_vtbl = {
	_TiXmlComment_destruct,	/*destruct*/
	_TiXmlComment_Print,	/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlComment_Clone,	/*Clone*/
	_TiXmlComment_Parse,	/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlComment_vtbl↑*/
};

/* コメントノードを作成します。
 */
TiXmlComment*
TiXmlComment_new()
{
	TiXmlComment* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlComment_construct(This);
	return This;
}

/* コメントノードを削除します。
 */
void
TiXmlComment_delete(TiXmlComment* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* コメントノードのコンストラクタです。
 */
void
_TiXmlComment_construct(TiXmlComment* This)
{
	_TiXmlNode_construct(TiXmlComment_super(This));
	This->vptr = &_TiXmlComment_vtbl;
}

/* コメントノードのデストラクタです。
 */
/*virtual*/ void
_TiXmlComment_destruct(TiXmlComment* This)
{
	_TiXmlNode_destruct(TiXmlComment_super(This));
}

/* コメントノードを複製します。
 * [out]
 *	戻り値		複製したコメントノード。
 */
/*virtual*/ TiXmlNode*
_TiXmlComment_Clone(TiXmlComment* This)
{
	TiXmlComment* clone = TiXmlComment_new();

	/* 内容を複製 */
	StdString_assign(clone->value, StdString_c_str(This->value));

	return TiXmlComment_super(clone);
}

/* コメントノードを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
/*virtual*/ void
_TiXmlComment_Print(TiXmlComment* This, FILE* fp, int depth)
{
	Indent(fp, depth);
	fprintf(fp, "<!--%s-->", StdString_c_str(This->value));
}

/* コメントノードをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- コメントノード作成直後に呼ばれることが前提です。
 *	  既に内容が設定されていると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlComment_Parse(TiXmlComment* This, const char* p)
{
	const char* end;
	int c;

	/* 「!--」を指した状態で呼ばれなければなりません。 */
	if(p[0] != '!' ||
	   p[1] != '-' ||
	   p[2] != '-') {
		DIE();
	}

	/* ポインタを「!--」の直後へ進めます。 */
	p += 3;

	/* 「-->」を探し、無ければエラーとします。 */
	end = strstr(p, "-->");
	if(!end) {
		DIE();
	}

	/* 「!--」の直後から「-->」の直前までの文字列を、そのまま取得します。
	 * - オリジナルのTinyXML1.2.4は、テキストと同様に連続する空白を一文字にまとめていますが、
	 *   IE6でXMLを表示してみると、コメント中の文字列は連続する空白もそのまま表示しています。
	 *   また、コメント先行の空白もコメント後続の空白も、まとめずそのまま表示されるようです。
	 *   今回は、IE6の仕様に従うことにしました。(※どちらが正しいのか、要確認)
	 */
	while(p < end) {
		c = *p++;
		StdString_append(This->value, (char*)&c);
	}

	/* 「-->」の直後へのポインタを返します。 */
	return end + 3;
}

/****************************************************************************
 *	TiXmlText
 ****************************************************************************/

static const TiXmlText_vtbl _TiXmlText_vtbl = {
	_TiXmlText_destruct,	/*destruct*/
	_TiXmlText_Print,	/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlText_Clone,	/*Clone*/
	_TiXmlText_Parse,	/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlText_vtbl↑*/
};

/* テキストノードを作成します。
 */
TiXmlText*
TiXmlText_new()
{
	TiXmlText* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlText_construct(This);
	return This;
}

/* テキストノードを削除します。
 */
void
TiXmlText_delete(TiXmlText* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* テキストノードのコンストラクタです。
 */
void
_TiXmlText_construct(TiXmlText* This)
{
	_TiXmlNode_construct(TiXmlText_super(This));
	This->vptr = &_TiXmlText_vtbl;
}

/* テキストノードのデストラクタです。
 */
/*virtual*/ void
_TiXmlText_destruct(TiXmlText* This)
{
	_TiXmlNode_destruct(TiXmlText_super(This));
}

/* テキストノードを複製します。
 * [out]
 *	戻り値		複製したテキストノード。
 */
/*virtual*/ TiXmlNode*
_TiXmlText_Clone(TiXmlText* This)
{
	TiXmlText* clone = TiXmlText_new();

	/* 内容を複製 */
	StdString_assign(clone->value, StdString_c_str(This->value));

	return TiXmlText_super(clone);
}

/* テキストノードを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		使いません。
 *			テキストは開始タグの直後に表示します。
 */
/*virtual*/ void
_TiXmlText_Print(TiXmlText* This, FILE* fp, int depth)
{
	fprintf(fp, "%s", StdString_c_str(This->value));
}

/* テキストノードをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- テキストノード作成直後に呼ばれることが前提です。
 *	  既に内容が設定されていると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlText_Parse(TiXmlText* This, const char* p)
{
	int whiteSpace;
	int c;

	/* テキスト先行の空白は格納しません。 */
	p = SkipWhiteSpace(p);

	whiteSpace = 0;
	for(;;) {
		/* 一文字取得します。 */
		c = *p;

		/* 終端または「<」に達したら、その位置へのポインタを返します。
		 * テキスト後続の空白は格納しません。(もしwhiteSpace=1であっても無視する)
		 * - オリジナルのTinyXML1.2.4は、テキスト後続の空白を保存するようですが、
		 *   IE6でXMLを表示してみると、テキスト後続の空白を保持しないようなので、
		 *   IE6の仕様に従うことにしました。(※どちらが正しいのか、要確認)
		 */
		if(!c || c == '<') {
			return p;
		}

		/* 一文字追加します。
		 * ただし、テキスト途中の連続する空白は、一文字に置き換えて格納します。
		 */
		if(isspace(c)) {
			whiteSpace = 1;
		} else {
			if(whiteSpace) {
				StdString_append(This->value, " ");
				whiteSpace = 0;
			}
			StdString_append(This->value, (char*)&c);
		}

		/* ポインタを次へ進めます。 */
		p++;
	}
}

/****************************************************************************
 *	TiXmlDeclaration
 ****************************************************************************/

static const TiXmlDeclaration_vtbl _TiXmlDeclaration_vtbl = {
	_TiXmlDeclaration_destruct,	/*destruct*/
	_TiXmlDeclaration_Print,	/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlDeclaration_Clone,	/*Clone*/
	_TiXmlDeclaration_Parse,	/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlDeclaration_vtbl↑*/
};

/* 宣言ノードを作成します。
 * [in]
 *	version		バージョン。
 *			NULLを指定すると、空文字列と見なします。
 *	encoding	エンコーディング。
 *			NULLを指定すると、空文字列と見なします。
 *	standalone	スタンドアローン。
 *			NULLを指定すると、空文字列と見なします。
 */
TiXmlDeclaration*
TiXmlDeclaration_new(const char* version/*=NULL*/, const char* encoding/*=NULL*/, const char* standalone/*=NULL*/)
{
	TiXmlDeclaration* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlDeclaration_construct(This, version, encoding, standalone);
	return This;
}

/* 宣言ノードを削除します。
 */
void
TiXmlDeclaration_delete(TiXmlDeclaration* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* 宣言ノードのコンストラクタです。
 * [in]
 *	version		バージョン。
 *			NULLを指定すると、空文字列と見なします。
 *	encoding	エンコーディング。
 *			NULLを指定すると、空文字列と見なします。
 *	standalone	スタンドアローン。
 *			NULLを指定すると、空文字列と見なします。
 */
void
_TiXmlDeclaration_construct(TiXmlDeclaration* This, const char* version/*=NULL*/, const char* encoding/*=NULL*/, const char* standalone/*=NULL*/)
{
	_TiXmlNode_construct(TiXmlDeclaration_super(This));
	This->vptr = &_TiXmlDeclaration_vtbl;

	This->version = StdString_new(version);
	This->encoding = StdString_new(encoding);
	This->standalone = StdString_new(standalone);
}

/* 宣言ノードのデストラクタです。
 */
/*virtual*/ void
_TiXmlDeclaration_destruct(TiXmlDeclaration* This)
{
	StdString_delete(This->version);
	StdString_delete(This->encoding);
	StdString_delete(This->standalone);

	_TiXmlNode_destruct(TiXmlDeclaration_super(This));
}

/* バージョンを取得します。
 * [out]
 *	戻り値		バージョン。
 */
const char*
TiXmlDeclaration_Version(TiXmlDeclaration* This)
{
	return StdString_c_str(This->version);
}

/* エンコーディングを取得します。
 * [out]
 *	戻り値		エンコーディング。
 */
const char*
TiXmlDeclaration_Encoding(TiXmlDeclaration* This)
{
	return StdString_c_str(This->encoding);
}

/* スタンドアローンを取得します。
 * [out]
 *	戻り値		スタンドアローン。
 */
const char*
TiXmlDeclaration_Standalone(TiXmlDeclaration* This)
{
	return StdString_c_str(This->standalone);
}

/* 宣言ノードを複製します。
 * [out]
 *	戻り値		複製した宣言ノード。
 */
/*virtual*/ TiXmlNode*
_TiXmlDeclaration_Clone(TiXmlDeclaration* This)
{
	TiXmlDeclaration* clone = TiXmlDeclaration_new(
		StdString_c_str(This->version),		/* バージョンを複製 */
		StdString_c_str(This->encoding),	/* エンコーディングを複製 */
		StdString_c_str(This->standalone));	/* スタンドアローンを複製 */

	/* 宣言ノードはvalueを使っていないが、念のために複製しておく。 */
	StdString_assign(clone->value, StdString_c_str(This->value));

	return TiXmlDeclaration_super(clone);
}

/* 宣言ノードを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
/*virtual*/ void
_TiXmlDeclaration_Print(TiXmlDeclaration* This, FILE* fp, int depth)
{
	Indent(fp, depth);
	fprintf(fp, "<?xml ");
	if(*StdString_c_str(This->version)) {
		fprintf(fp, "version=\"%s\" ", StdString_c_str(This->version));
	}
	if(*StdString_c_str(This->encoding)) {
		fprintf(fp, "encoding=\"%s\" ", StdString_c_str(This->encoding));
	}
	if(*StdString_c_str(This->standalone)) {
		fprintf(fp, "standalone=\"%s\" ", StdString_c_str(This->standalone));
	}
	fprintf(fp, "?>");
}

/* 宣言ノードをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- 宣言ノード作成直後に呼ばれることが前提です。
 *	  既にバージョン、エンコーディング、スタンドアローンが設定されていると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlDeclaration_Parse(TiXmlDeclaration* This, const char* p)
{
	TiXmlAttribute* attribute;
	const char* end;
	const char* pos;

	/* 「?xml」を指した状態で呼ばれなければなりません。 */
	if(p[0] != '?' ||
	   p[1] != 'x' ||
	   p[2] != 'm' ||
	   p[3] != 'l') {
		DIE();
	}

	/* ポインタを「?xml」の直後へ進めます。 */
	p += 4;

	/* 「?>」を探し、無ければエラーとします。 */
	end = strstr(p, "?>");
	if(!end) {
		DIE();
	}

	/* 宣言タグの書式は、「<?xml version=... [encoding=...] [standalone=...] ?>」です。
	 * versionは必須、encoding,standaloneは任意ですが、順番が入れ替わってはいけません。
	 */
	pos = strstr(p, "version");
	if(pos && pos < end) {
		attribute = TiXmlAttribute_new(NULL, NULL);
		p = TiXmlAttribute_Parse(attribute, pos);
		StdString_assign(This->version, TiXmlAttribute_Value(attribute));
		TiXmlAttribute_delete(attribute);
	} else {
		DIE(); /* versionは必須 */
	}
	pos = strstr(p, "encoding");
	if(pos && pos < end) {
		attribute = TiXmlAttribute_new(NULL, NULL);
		p = TiXmlAttribute_Parse(attribute, pos);
		StdString_assign(This->encoding, TiXmlAttribute_Value(attribute));
		TiXmlAttribute_delete(attribute);
	}
	pos = strstr(p, "standalone");
	if(pos && pos < end) {
		attribute = TiXmlAttribute_new(NULL, NULL);
		p = TiXmlAttribute_Parse(attribute, pos);
		StdString_assign(This->standalone, TiXmlAttribute_Value(attribute));
		TiXmlAttribute_delete(attribute);
	}

	/* 「?>」の直後へのポインタを返します。 */
	return end + 2;
}

/****************************************************************************
 *	TiXmlUnknown
 ****************************************************************************/

static const TiXmlUnknown_vtbl _TiXmlUnknown_vtbl = {
	_TiXmlUnknown_destruct,	/*destruct*/
	_TiXmlUnknown_Print,	/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlUnknown_Clone,	/*Clone*/
	_TiXmlUnknown_Parse,	/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlUnknown_vtbl↑*/
};

/* 不明なノードを作成します。
 */
TiXmlUnknown*
TiXmlUnknown_new()
{
	TiXmlUnknown* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlUnknown_construct(This);
	return This;
}

/* 不明なノードを削除します。
 */
void
TiXmlUnknown_delete(TiXmlUnknown* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* 不明なノードのコンストラクタです。
 */
void
_TiXmlUnknown_construct(TiXmlUnknown* This)
{
	_TiXmlNode_construct(TiXmlUnknown_super(This));
	This->vptr = &_TiXmlUnknown_vtbl;
}

/* 不明なノードのデストラクタです。
 */
/*virtual*/ void
_TiXmlUnknown_destruct(TiXmlUnknown* This)
{
	_TiXmlNode_destruct(TiXmlUnknown_super(This));
}

/* 不明なノードを複製します。
 * [out]
 *	戻り値		複製した不明なノード。
 */
/*virtual*/ TiXmlNode*
_TiXmlUnknown_Clone(TiXmlUnknown* This)
{
	TiXmlUnknown* clone = TiXmlUnknown_new();

	StdString_assign(clone->value, StdString_c_str(This->value));

	return TiXmlUnknown_super(clone);
}

/* 不明なノードを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
/*virtual*/ void
_TiXmlUnknown_Print(TiXmlUnknown* This, FILE* fp, int depth)
{
	Indent(fp, depth);
	fprintf(fp, "<%s>", StdString_c_str(This->value));
}

/* 不明なノードをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- 不明なノード作成直後に呼ばれることが前提です。
 *	  既に内容が設定されていると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlUnknown_Parse(TiXmlUnknown* This, const char* p)
{
	int c;

	for(;;) {
		/* 一文字取得し、ポインタを次へ進めます。 */
		c = *p++;

		/* 「>」を見つける前に終端に達したら、エラーとします。 */
		if(!c) {
			DIE();
		}

		/* 「>」を見つけたら、「>」の直後へのポインタを返します。 */
		if(c == '>') {
			return p;
		}

		/* 一文字追加します。 */
		StdString_append(This->value, (char*)&c);
	}
}

/****************************************************************************
 *	TiXmlDocument
 ****************************************************************************/

static const TiXmlDocument_vtbl _TiXmlDocument_vtbl = {
	_TiXmlDocument_destruct,	/*destruct*/
	_TiXmlDocument_Print,		/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	_TiXmlDocument_Clone,		/*Clone*/
	_TiXmlDocument_Parse,		/*Parse*/
	/*↑TiXmlNode_vtbl↑*/
	/*↑TiXmlDocument_vtbl↑*/
};

/* XMLドキュメントを作成します。
 * [in]
 *	documentName	ファイル名。
 *			NULLを指定すると、空文字列と見なします。
 */
TiXmlDocument*
TiXmlDocument_new(const char* documentName/*=NULL*/)
{
	TiXmlDocument* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlDocument_construct(This, documentName);
	return This;
}

/* XMLドキュメントを削除します。
 */
void
TiXmlDocument_delete(TiXmlDocument* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* XMLドキュメントのコンストラクタです。
 * [in]
 *	documentName	ファイル名。
 *			NULLを指定すると、空文字列と見なします。
 */
void
_TiXmlDocument_construct(TiXmlDocument* This, const char* documentName/*=NULL*/)
{
	_TiXmlNode_construct(TiXmlDocument_super(This));
	This->vptr = &_TiXmlDocument_vtbl;

	/* ファイル名を設定します。 */
	StdString_assign(This->value, documentName);
}

/* XMLドキュメントのデストラクタです。
 */
/*virtual*/ void
_TiXmlDocument_destruct(TiXmlDocument* This)
{
	_TiXmlNode_destruct(TiXmlDocument_super(This));
}

/* XMLファイルを読み込みます。
 * [in]
 *	filename	ファイル名。
 *			NULLを指定すると、既に設定されているファイル名を用います。
 */
void
TiXmlDocument_LoadFile(TiXmlDocument* This, const char* filename/*=NULL*/)
{
	FILE* fp;
	int size;
	char* buf;

	if(!filename) {
		filename = StdString_c_str(This->value);
	}
	fp = fopen(filename, "rb");	/* P/ECEのI/O処理との互換のために、入出力時のCR<->CR+LF変換は行わないことにします。 */
	if(!fp) {
		DIE();
	}

	fseek(fp, 0, SEEK_END);
	size = ftell(fp);		/* "rb"で開いていることが前提です。"rt"で開いていると、正しいサイズが得られません。 */
	rewind(fp);

	buf = calloc(1, size + 1/*nul*/);
	if(!buf) {
		DIE();
	}
	fread(buf, 1, size, fp);	/* "rb"で開いていることが前提です。"rt"で開いていると、正しいサイズが得られません。 */
	This->vptr->Parse(This, buf);
	free(buf);

	fclose(fp);
}

/* XMLファイルを出力します。
 * [in]
 *	filename	ファイル名。
 *			NULLを指定すると、既に設定されているファイル名を用います。
 */
void
TiXmlDocument_SaveFile(TiXmlDocument* This, const char* filename/*=NULL*/)
{
	FILE* fp;

	if(!filename) {
		filename = StdString_c_str(This->value);
	}
	fp = fopen(filename, "wb");	/* P/ECEのI/O処理との互換のために、入出力時のCR<->CR+LF変換は行わないことにします。 */
	if(!fp) {
		DIE();
	}

	This->vptr->Print(This, fp, 0);

	fclose(fp);
}

/* XMLドキュメントを出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		インデントの深さ。
 */
/*virtual*/ void
_TiXmlDocument_Print(TiXmlDocument* This, FILE* fp, int depth)
{
	TiXmlNode* node;

	for(node = This->firstChild;
	    node;
	    node = TiXmlNode_NextSibling(node, NULL)) {
		node->vptr->Print(node, fp, 0);
		fprintf(fp, "\n");
	}
}

/* XMLドキュメントを複製します。
 * [out]
 *	戻り値		複製したXMLドキュメント。
 */
/*virtual*/ TiXmlNode*
_TiXmlDocument_Clone(TiXmlDocument* This)
{
	TiXmlDocument* clone = TiXmlDocument_new(StdString_c_str(This->value));	/* ファイル名を複製 */
	TiXmlNode* node;

	/* 子ノードを複製 */
	for(node = This->firstChild;
	    node;
	    node = TiXmlNode_NextSibling(node, NULL)) {
		TiXmlNode_InsertEndChild(TiXmlDocument_super(clone), node->vptr->Clone(node));
	}

	return TiXmlDocument_super(clone);
}

/* XMLドキュメントをパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- XMLドキュメント作成直後に呼ばれることが前提です。
 *	  既に子ノードが追加されていると、正しい結果となりません。
 */
/*virtual*/ const char*
_TiXmlDocument_Parse(TiXmlDocument* This, const char* p)
{
	TiXmlNode* node;

	/* ノードに先行する空白をスキップします。 */
	while(*(p = SkipWhiteSpace(p))) {
		if(*p != '<') {
			DIE();
		}

		/* ノードを読み込み、追加します。 */
		node = IdentifyAndParse(&p);
		TiXmlNode_InsertEndChild(TiXmlDocument_super(This), node);
	}

	/* ノードが一つも無ければ、エラーとします。 */
	if(!This->firstChild) {
		DIE();
	}

	return p;
}

/****************************************************************************
 *	TiXmlAttribute
 ****************************************************************************/

static const TiXmlAttribute_vtbl _TiXmlAttribute_vtbl = {
	_TiXmlAttribute_destruct,	/*destruct*/
	_TiXmlAttribute_Print,		/*Print*/
	/*↑TiXmlBase_vtbl↑*/
	/*↑TiXmlAttribute_vtbl↑*/
};

/* 属性を作成します。
 * [in]
 *	name		属性名。
 *			NULLを指定すると、空文字列と見なします。
 *	value		属性値。
 *			NULLを指定すると、空文字列と見なします。
 */
TiXmlAttribute*
TiXmlAttribute_new(const char* name/*=NULL*/, const char* value/*=NULL*/)
{
	TiXmlAttribute* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlAttribute_construct(This, name, value);
	return This;
}

/* 属性を削除します。
 */
void
TiXmlAttribute_delete(TiXmlAttribute* This)
{
	if(This) {
		This->vptr->destruct(This);
		free(This);
	}
}

/* 属性のコンストラクタです。
 * [in]
 *	name		属性名。
 *			NULLを指定すると、空文字列と見なします。
 *	value		属性値。
 *			NULLを指定すると、空文字列と見なします。
 */
void
_TiXmlAttribute_construct(TiXmlAttribute* This, const char* name/*=NULL*/, const char* value/*=NULL*/)
{
	_TiXmlBase_construct(TiXmlAttribute_super(This));
	This->vptr = &_TiXmlAttribute_vtbl;

	This->name = StdString_new(name);
	This->value = StdString_new(value);
}

/* 属性のデストラクタです。
 */
/*virtual*/ void
_TiXmlAttribute_destruct(TiXmlAttribute* This)
{
	StdString_delete(This->name);
	StdString_delete(This->value);

	_TiXmlBase_destruct(TiXmlAttribute_super(This));
}

/* 属性名を取得します。
 * [out]
 *	戻り値		属性名。
 */
const char*
TiXmlAttribute_Name(TiXmlAttribute* This)
{
	return StdString_c_str(This->name);
}

/* 属性値を取得します。
 * [out]
 *	戻り値		属性値。
 */
const char*
TiXmlAttribute_Value(TiXmlAttribute* This)
{
	return StdString_c_str(This->value);
}

/* 属性名を設定します。
 * [in]
 *	name		属性名。
 */
void
TiXmlAttribute_SetName(TiXmlAttribute* This, const char* name)
{
	StdString_assign(This->name, name);
}

/* 属性値を設定します。
 * [in]
 *	value		属性値。
 */
void
TiXmlAttribute_SetValue(TiXmlAttribute* This, const char* value)
{
	StdString_assign(This->value, value);
}

/* 次の属性を取得します。
 * [out]
 *	戻り値		次の属性。
 *			属性セットの末尾だった場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlAttribute_Next(TiXmlAttribute* This)
{
	if(!*StdString_c_str(This->next->name) &&
	   !*StdString_c_str(This->next->value)) {
		return NULL;
	}
	return This->next;
}

/* 前の属性を取得します。
 * [out]
 *	戻り値		次の属性。
 *			属性セットの先頭だった場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlAttribute_Previous(TiXmlAttribute* This)
{
	if(!*StdString_c_str(This->prev->name) &&
	   !*StdString_c_str(This->prev->value)) {
		return NULL;
	}
	return This->prev;
}

/* 属性を出力します。
 * [in]
 *	fp		出力先ストリーム。
 *	depth		使いません。
 *			属性は要素の開始タグの中に表示します。
 */
/*virtual*/ void
_TiXmlAttribute_Print(TiXmlAttribute* This, FILE* fp, int depth)
{
	int c = strchr(StdString_c_str(This->value), '"') ? '\'' : '"';

	fprintf(fp, "%s=%c%s%c", StdString_c_str(This->name), c, StdString_c_str(This->value), c);
}

/* 属性をパースします。
 * [in]
 *	p		パース開始位置へのポインタ。
 * [out]
 *	戻り値		パース終了位置へのポインタ。
 * [note]
 *	- 属性作成直後に呼ばれることが前提です。
 *	  既に属性名、属性値が設定されていると、正しい結果となりません。
 */
const char*
TiXmlAttribute_Parse(TiXmlAttribute* This, const char* p)
{
	int quot;
	int c;

	/* 属性名を取得します。 */
	p = ReadName(p, This->name);

	/* 属性名と「=」の間の空白をスキップします。 */
	p = SkipWhiteSpace(p);

	/* 「=」が存在することを確認し、ポインタを次へ進めます。 */
	if(*p++ != '=') {
		DIE();
	}

	/* 「=」と属性値の間の空白をスキップします。 */
	p = SkipWhiteSpace(p);

	/* 引用符を取得し、ポインタを次へ進めます。 */
	quot = *p++;

	/* 引用符が、「'」または「"」であることを確認します。 */
	if(quot != '\'' && quot != '"') {
		DIE();
	}

	for(;;) {
		/* 一文字取得し、ポインタを次へ進めます。 */
		c = *p++;

		/* 引用符を見つける前に終端に達したら、エラーとします。 */
		if(!c) {
			DIE();
		}

		/* 引用符を見つけたら、引用符の直後へのポインタを返します。 */
		if(c == quot) {
			return p;
		}

		/* 一文字追加します。 */
		StdString_append(This->value, (char*)&c);
	}
}

/****************************************************************************
 *	TiXmlAttributeSet
 ****************************************************************************/

/* 属性セットを作成します。
 */
TiXmlAttributeSet*
TiXmlAttributeSet_new()
{
	TiXmlAttributeSet* This = calloc(1, sizeof *This);
	if(!This) {
		DIE();
	}
	_TiXmlAttributeSet_construct(This);
	return This;
}

/* 属性セットを削除します。
 */
void
TiXmlAttributeSet_delete(TiXmlAttributeSet* This)
{
	if(This) {
		/** no virtual destructor **/
		_TiXmlAttributeSet_destruct(This);
		free(This);
	}
}

/* 属性セットのコンストラクタです。
 */
void
_TiXmlAttributeSet_construct(TiXmlAttributeSet* This)
{
	/** no base class **/
	/** no vptr **/

	This->sentinel = TiXmlAttribute_new(NULL, NULL);
	This->sentinel->next = This->sentinel;
	This->sentinel->prev = This->sentinel;
}

/* 属性セットのデストラクタです。
 * [note]
 *	- リンクされている属性を、自動的に全て削除します。
 */
void
_TiXmlAttributeSet_destruct(TiXmlAttributeSet* This)
{
	TiXmlAttribute* attribute = This->sentinel->next;

	while(attribute != This->sentinel) {
		TiXmlAttribute* next = attribute->next;
		TiXmlAttribute_delete(attribute);
		attribute = next;
	}

	TiXmlAttribute_delete(This->sentinel);

	/** no base class **/
}

/* 指定された属性をリンクに追加します。
 * [in]
 *	addThis		リンクに追加する属性。
 * [note]
 *	- 既に同じ属性名の属性がリンク内に存在する場合は、追加できません。
 */
void
TiXmlAttributeSet_Add(TiXmlAttributeSet* This, TiXmlAttribute* addThis)
{
	if(TiXmlAttributeSet_Find(This, TiXmlAttribute_Name(addThis))) {
		DIE();
	}

	addThis->next = This->sentinel;
	addThis->prev = This->sentinel->prev;

	This->sentinel->prev->next = addThis;
	This->sentinel->prev = addThis;
}

/* 指定された属性をリンクから取り外します。
 * [in]
 *	removeThis	リンクから取り外す属性。
 * [note]
 *	- 取り外した属性がもう不要ならば、TiXmlAttribute_delete()を呼び出して削除してください。
 *	  この関数は、取り外した属性を自動的に削除しません。
 */
void
TiXmlAttributeSet_Remove(TiXmlAttributeSet* This, TiXmlAttribute* removeThis)
{
	TiXmlAttribute* attribute;

	for(attribute = This->sentinel->next;
	    attribute != This->sentinel;
	    attribute = attribute->next) {
		if(attribute == removeThis) {
			removeThis->prev->next = removeThis->next;
			removeThis->next->prev = removeThis->prev;
			removeThis->next = NULL;
			removeThis->prev = NULL;
			return;
		}
	}

	DIE();
}

/* 先頭の属性を取得します。
 * [out]
 *	戻り値		属性のポインタ。
 *			属性が無い場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlAttributeSet_First(TiXmlAttributeSet* This)
{
	if(This->sentinel->next == This->sentinel) {
		return NULL;
	}
	return This->sentinel->next;
}

/* 末尾の属性を取得します。
 * [out]
 *	戻り値		属性のポインタ。
 *			属性が無い場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlAttributeSet_Last(TiXmlAttributeSet* This)
{
	if(This->sentinel->prev == This->sentinel) {
		return NULL;
	}
	return This->sentinel->prev;
}

/* 属性を検索します。
 * [in]
 *	name		属性名。
 * [note]
 *	- 指定された属性名に一致する属性が無い場合は、NULLを返します。
 */
TiXmlAttribute*
TiXmlAttributeSet_Find(TiXmlAttributeSet* This, const char* name)
{
	TiXmlAttribute* attribute;

	for(attribute = This->sentinel->next;
	    attribute != This->sentinel;
	    attribute = attribute->next) {
		if(!strcmp(TiXmlAttribute_Name(attribute), name)) {
			return attribute;
		}
	}

	return NULL;
}

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

/* 「_TiXml?????_vtbl」の前方参照を避けるために、最後に定義します。 */
TiXmlDocument   * TiXmlNode_ToDocument   (TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlDocument_vtbl    ? (TiXmlDocument   *)This : NULL; }
TiXmlElement    * TiXmlNode_ToElement    (TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlElement_vtbl     ? (TiXmlElement    *)This : NULL; }
TiXmlComment    * TiXmlNode_ToComment    (TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlComment_vtbl     ? (TiXmlComment    *)This : NULL; }
TiXmlUnknown    * TiXmlNode_ToUnknown    (TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlUnknown_vtbl     ? (TiXmlUnknown    *)This : NULL; }
TiXmlText       * TiXmlNode_ToText       (TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlText_vtbl        ? (TiXmlText       *)This : NULL; }
TiXmlDeclaration* TiXmlNode_ToDeclaration(TiXmlNode* This) { return This->vptr == (TiXmlNode_vtbl*)&_TiXmlDeclaration_vtbl ? (TiXmlDeclaration*)This : NULL; }

