CMarkupTag* CMarkupTag::AppendTag(char* szName)
{
	CMarkupTag*	pcTag;

	pcTag = mpcDoc->mpcMarkup->AllocateTag(mpcDoc);
	pcTag->Init(szName, this);
	macBases.Add((CMarkupBase**)&pcTag);
	return pcTag;
}
CMarkupTag* CMarkupDoc::SetRootTag(char* szTagName)
{
	CMarkupTag*	pcTag;

	if (mpcRootTag == NULL)
	{
		pcTag = mpcMarkup->AllocateTag(this);
		pcTag->Init(szTagName, NULL);
		mpcRootTag = pcTag;
		return pcTag;
	}
	return NULL;
}
BOOL CObjectSourcesXML::ImportObjectClass(CTileWorld* pcWorld, CMarkupTag* pcTag)
{
	CMarkupTag*	pcClass;
	CMarkupTag*	pcFields;
	CMarkupTag*	pcObjects;
	CChars		szClass;
	CTileType*	pcType;
	BOOL		bResult;

	pcClass = CMarkupTextParser::GetTag(pcTag, "Class");
	if (!pcClass)
	{
		return FALSE;
	}

	pcFields = CMarkupTextParser::GetTag(pcTag, "Fields");

	pcObjects = CMarkupTextParser::GetTag(pcTag, "Objects");
	if (!pcClass)
	{
		return FALSE;
	}

	szClass.Init();
	pcClass->GetText(&szClass);

	bResult = FALSE;
	if (szClass.EqualsIgnoreCase("Image"))
	{
		pcType = pcWorld->GetType("Image");
		bResult = ImportImages(pcType, pcObjects);
	}
	else if (szClass.EqualsIgnoreCase("Boolean"))
	{
		pcType = pcWorld->GetType("Boolean");
		bResult = ImportBooleans(pcType, pcObjects);
	}
	else
	{
		CMarkupTextParser::LogError(pcClass, "Type not allowed.  Must be Image or Boolean.");
	}

	if (!bResult)
	{
		return FALSE;
	}
	return TRUE;
}
BOOL CImageCelsSourceXML::ImportCelSource(CMarkupTag* pcBrushSourceTag, char* szTexturePath)
{
	CMarkupTag*			pcFileName;
	CChars				szFileName;
	CChars				szShortFileName;
	BOOL				bResult;
	CMarkupTag*			pcCels;
	CFileUtil			cFileUtil;

	pcFileName = CMarkupTextParser::GetTag(pcBrushSourceTag, "FileName");
	if (!pcFileName)
	{
		return FALSE;
	}

	szShortFileName.Init();
	pcFileName->GetText(&szShortFileName);
	if (szFileName.Empty())
	{
		szShortFileName.Kill();
		CMarkupTextParser::LogErrorTagWasEmpty(pcBrushSourceTag);
		return FALSE;
	}
	
	pcCels = CMarkupTextParser::GetTag(pcBrushSourceTag, "Cels");
	if (!pcCels)
	{
		szShortFileName.Kill();
		return FALSE;
	}

	szFileName.Init(szTexturePath);
	cFileUtil.AppendToPath(&szFileName, szShortFileName.Text());

	bResult = ImportCels(pcCels, szFileName.Text());
	return bResult;
}
CMarkupTag* CMarkupTag::GetTagFromIndex(char* szTagName, STagIterator* psIter)
{
	CMarkupBase*	pcBase;
	CMarkupTag*		pcTag;
	CMarkupRefDoc*	pcRefDoc;
	int				i;
	int				iIndex;

	iIndex = psIter->iIndex +1;
	for (i = iIndex; i < macBases.NumElements(); i++)
	{
		pcBase = *(macBases.Get(i));
		if (pcBase->IsTag())
		{
			pcTag = (CMarkupTag*)pcBase;
			if (pcTag->Is(szTagName))
			{
				psIter->iIndex = i;
				psIter->mpcCurrent = pcTag;
				return pcTag;
			}
		}
		else if (pcBase->IsRefDoc())
		{
			pcRefDoc = (CMarkupRefDoc*)pcBase;
			if (pcRefDoc->Is(szTagName))
			{
				pcTag = pcRefDoc->GetRootTag(); 
				psIter->iIndex = i;
				psIter->mpcCurrent = pcTag;
				return pcTag;
			}
		}
	}
	return NULL;
}
void TestReadExternalReference(void)
{
	CXMLFile	cXMLFile;
	CChars		szDoc;
	int			iLine;
	char		szExpected[] = "<InputDevices>\n\
  This is text &lt; and doom stuff\n\
  <RootInSecond>\n\
    Hello\n\
  </RootInSecond>\n\
  Sweet &gt; other stuff\n\
  <ThirdsRoot>\n\
    World\n\
  </ThirdsRoot>\n\
</InputDevices>\n";
	CMarkupTag*	pcTag;
	CMarkupTag*	pcSecondTag;
	CMarkupTag*	pcThirdTag;
	CChars		szText;

	cXMLFile.Init();
	cXMLFile.Read("First.xml", ".");

	szDoc.Init(16);
	iLine = cXMLFile.mcMarkup.mpcDoc->ToString(&szDoc);
	AssertInt(10, iLine);
	AssertString(szExpected, szDoc.Text());
	szDoc.Kill();

	pcTag = cXMLFile.mcMarkup.mpcDoc->GetRootTag();
	pcSecondTag = pcTag->GetTag("RootInSecond");
	AssertNotNull(pcSecondTag);
	szText.Init();
	pcSecondTag->GetText(&szText);
	szText.StripWhiteSpace(TRUE);
	AssertString("Hello", szText.Text());
	szText.Kill();

	pcTag = cXMLFile.mcMarkup.mpcDoc->GetRootTag();
	pcThirdTag = pcTag->GetTag("ThirdsRoot");
	AssertNotNull(pcThirdTag);
	szText.Init();
	pcThirdTag->GetText(&szText);
	szText.StripWhiteSpace(TRUE);
	AssertString("World", szText.Text());
	szText.Kill();

	cXMLFile.Kill();
}
void TestRepeatedExternalTags(void)
{
	CXMLFile		cXMLFile;
	CChars			szDoc;
	int				iLine;
	char			szExpected[] = "<Root>\n\
  <ExtTag>\n\
    <SubTag>Look at me!  I&apos;m going to be an elite pilot.</SubTag>\n\
    <SubTag>Also *very* messed up.</SubTag>\n\
  </ExtTag>\n\
  <ExtTag>\n\
    <SubTag>Look at me!  I&apos;m going to be an elite pilot.</SubTag>\n\
    <SubTag>Also *very* messed up.</SubTag>\n\
  </ExtTag>\n\
  <ExtTag>\n\
    <SubTag>Look at me!  I&apos;m going to be an elite pilot.</SubTag>\n\
    <SubTag>Also *very* messed up.</SubTag>\n\
  </ExtTag>\n\
  <ExtTag>\n\
    <SubTag>Look at me!  I&apos;m going to be an elite pilot.</SubTag>\n\
    <SubTag>Also *very* messed up.</SubTag>\n\
  </ExtTag>\n\
</Root>\n";
	CMarkupTag*		pcRoot;
	int				iCount;
	CMarkupTag*		pcExtTag;
	CMarkupTag*		pcSubTag1;
	CMarkupTag*		pcSubTag2;
	CMarkupTag*		pcSubTag3;
	CChars			szText;
	STagIterator	sIter;

	cXMLFile.Init();
	cXMLFile.Read("File.xml", ".");

	szDoc.Init(16);
	iLine = cXMLFile.mcMarkup.mpcDoc->ToString(&szDoc);
	AssertInt(18, iLine);
	AssertString(szExpected, szDoc.Text());
	szDoc.Kill();

	pcRoot = cXMLFile.mcMarkup.mpcDoc->GetRootTag();

	iCount = 0;
	pcExtTag = pcRoot->GetTag("ExtTag", &sIter);
	while (pcExtTag)
	{
		iCount++;

		if (iCount > 4)
		{
			//This is to take care of the case where GetNextTag always get's the first tag.
			break;
		}

		pcSubTag1 = pcExtTag->GetTag("SubTag", 0);
		pcSubTag2 = pcExtTag->GetTag("SubTag", 1);
		pcSubTag3 = pcExtTag->GetTag("SubTag", 2);

		szText.Init();
		pcSubTag1->GetText(&szText);
		AssertString("Look at me!  I'm going to be an elite pilot.", szText.Text());
		szText.Kill();		
		
		szText.Init();
		pcSubTag2->GetText(&szText);
		AssertString("Also *very* messed up.", szText.Text());
		szText.Kill();

		AssertNull(pcSubTag3);

		pcExtTag = pcRoot->GetNextTag(&sIter);
	}

	AssertInt(4, iCount);
	cXMLFile.Kill();
}
BOOL CObjectSourcesXML::ImportImage(CTileType* pcType, CMarkupTag* pcTag)
{
	CMarkupTag*					pcName;
	CMarkupTag*					pcCelIndex;
	CMarkupTag*					pcBrushID;
	CMarkupTag*					pcSourceName;
	CMarkupTag*					pcProperties;
	CChars						szName;
	int							iCelIndex;
	int							iBrushID;
	CChars						szSourceName;
	CTileImageCel*				pcTile;
	Ptr<CImageCelGroup>	pcGroup;
	CImageCel*					pcCel;

	pcName = CMarkupTextParser::GetTag(pcTag, "Name");
	if (!pcName)
	{
		return FALSE;
	}
	pcCelIndex = CMarkupTextParser::GetTag(pcTag, "CelIndex");
	if (!pcCelIndex)
	{
		return FALSE;
	}
	pcBrushID = CMarkupTextParser::GetTag(pcTag, "BrushID");
	if (!pcBrushID)
	{
		return FALSE;
	}
	pcSourceName = CMarkupTextParser::GetTag(pcTag, "SourceName");
	if (!pcSourceName)
	{
		return FALSE;
	}
	pcProperties = CMarkupTextParser::GetTag(pcTag, "Properties");

	szName.Init();
	pcName->GetText(&szName);
	if (!CMarkupTextParser::ReadInteger(pcCelIndex, &iCelIndex))
	{
		szName.Kill();
		return FALSE;
	}
	if (!CMarkupTextParser::ReadInteger(pcBrushID, &iBrushID))
	{
		szName.Kill();
		return FALSE;
	}
	szSourceName.Init();
	pcSourceName->GetText(&szSourceName);
	if (szSourceName.Empty())
	{
		CMarkupTextParser::LogErrorTagWasEmpty(pcSourceName);
		szName.Kill();
		szSourceName.Kill();
		return FALSE;
	}


	pcGroup = mpcWorld->GetGroup(szSourceName.Text());
	if (!pcGroup)
	{
		szName.Kill();
		szSourceName.Kill();
		gcLogger.Error("Couldn't find Cel Group.");
		return FALSE;
	}

	pcCel = pcGroup->GetCel(iCelIndex);
	if (!pcCel)
	{
		szName.Kill();
		szSourceName.Kill();
		gcLogger.Error("Couldn't find Cel.");
		return FALSE;
	}

	pcTile = UMalloc(CTileImageCel);
	pcTile->Init(pcCel, pcType, szName.Text());
	pcType->AddTile(pcTile);

	return TRUE;
}
BOOL CTileMapXML::ImportLayer(CMarkupTag* pcTag, CTileMap* pcMap)
{
	CMarkupTag*		pcName;
	CMarkupTag*		pcObjectClass;
	CMarkupTag*		pcTiles;
	CChars			szName;
	CChars			szObjectClass;
	BOOL			bResult;
	CTileType*		pcType;
	CTileLayer*		pcLayer;

	pcName = CMarkupTextParser::GetTag(pcTag, "Name");
	if (!pcName)
	{
		return FALSE;
	}
	pcObjectClass = CMarkupTextParser::GetTag(pcTag, "ObjectClass");
	if (!pcObjectClass)
	{
		return FALSE;
	}
	pcTiles = CMarkupTextParser::GetTag(pcTag, "Tiles");
	if (!pcTiles)
	{
		return FALSE;
	}

	szName.Init();
	pcName->GetText(&szName);
	if (szName.Empty())
	{
		szName.Kill();
		CMarkupTextParser::LogErrorTagWasEmpty(pcName);
		return FALSE;
	}

	szObjectClass.Init();
	pcObjectClass->GetText(&szObjectClass);
	if (szObjectClass.Empty())
	{
		szName.Kill();
		szObjectClass.Kill();
		CMarkupTextParser::LogErrorTagWasEmpty(pcObjectClass);
		return FALSE;
	}

	pcType = mpcWorld->GetType(szObjectClass.Text());
	if (!pcType)
	{
		CMarkupTextParser::LogError(pcObjectClass, "Could not find a TileType for Tag.");
		return FALSE;
	}

	pcLayer = pcMap->AddLayer(szName.Text(), pcType);

	bResult = ImportTiles(pcTiles, pcLayer);

	szObjectClass.Kill();
	szName.Kill();
	return bResult;
}
BOOL CTileMapXML::ImportMap(CMarkupTag* pcTag)
{
	CMarkupTag*		pcTileMap;
	CMarkupTag*		pcName;
	CMarkupTag*		pcCelWidth;
	CMarkupTag*		pcCelHeight;
	BOOL			bResult;
	CChars			szName;
	int				iCelWidth;
	int				iCelHeight;
	CTileMap*		pcMap;

	pcTileMap = CMarkupTextParser::GetTag(pcTag, "TileMap");
	if (!pcTileMap)
	{
		return FALSE;
	}

	pcName = CMarkupTextParser::GetTag(pcTag, "Name");
	if (!pcName)
	{
		return FALSE;
	}

	pcCelWidth = CMarkupTextParser::GetTag(pcTag, "CelWidth");
	if (!pcCelWidth)
	{
		return FALSE;
	}

	pcCelHeight = CMarkupTextParser::GetTag(pcTag, "CelHeight");
	if (!pcCelHeight)
	{
		return FALSE;
	}

	if (!CMarkupTextParser::ReadInteger(pcCelWidth, &iCelWidth))
	{
		return FALSE;
	}
	if (!CMarkupTextParser::ReadInteger(pcCelHeight, &iCelHeight))
	{
		return FALSE;
	}

	szName.Init();
	pcName->GetText(&szName);
	if (szName.Empty())
	{
		szName.Kill();
		CMarkupTextParser::LogErrorTagWasEmpty(pcName);
		return FALSE;
	}

	pcMap = mpcWorld->AddMap(szName.Text(), iCelWidth, iCelHeight);

	bResult = ImportMap2(pcTileMap, pcMap);
	if (!bResult)
	{
		return FALSE;
	}

	szName.Kill();
	return TRUE;
}