static void writeXmlCaselist (TestHierarchyIterator& iter, qpXmlWriter* writer)
{
	DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
			  iter.getNode()->getNodeType() == NODETYPE_PACKAGE);

	{
		const TestNode* node		= iter.getNode();
		qpXmlAttribute	attribs[2];
		int				numAttribs	= 0;
		attribs[numAttribs++] = qpSetStringAttrib("PackageName", node->getName());
		attribs[numAttribs++] = qpSetStringAttrib("Description", node->getDescription());
		DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));

		if (!qpXmlWriter_startDocument(writer) ||
			!qpXmlWriter_startElement(writer, "TestCaseList", numAttribs, attribs))
			throw Exception("Failed to start XML document");
	}

	iter.next();

	while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
	{
		const TestNode* const	node		= iter.getNode();
		const TestNodeType		nodeType	= node->getNodeType();
		const bool				isEnter		= iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE;

		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE ||
				  iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE);
		{
			if (isEnter)
			{
				const string	caseName	= node->getName();
				const string	description	= node->getDescription();
				qpXmlAttribute	attribs[3];
				int				numAttribs = 0;

				attribs[numAttribs++] = qpSetStringAttrib("Name",			caseName.c_str());
				attribs[numAttribs++] = qpSetStringAttrib("CaseType",		getNodeTypeName(nodeType));
				attribs[numAttribs++] = qpSetStringAttrib("Description",	description.c_str());
				DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));

				if (!qpXmlWriter_startElement(writer, "TestCase", numAttribs, attribs))
					throw Exception("Writing to case list file failed");
			}
			else
			{
				if (!qpXmlWriter_endElement(writer, "TestCase"))
					throw tcu::Exception("Writing to case list file failed");
			}
		}

		iter.next();
	}

	// This could be done in catch, but the file is corrupt at that point anyways.
	if (!qpXmlWriter_endElement(writer, "TestCaseList") ||
		!qpXmlWriter_endDocument(writer))
		throw Exception("Failed to terminate XML document");
}
/*--------------------------------------------------------------------*//*!
 * \brief Export the test list of each package into a separate XML file.
 *//*--------------------------------------------------------------------*/
void writeXmlCaselistsToFiles (TestPackageRoot& root, TestContext& testCtx, const CommandLine& cmdLine)
{
	DefaultHierarchyInflater			inflater		(testCtx);
	de::MovePtr<const CaseListFilter>	caseListFilter	(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));

	TestHierarchyIterator				iter			(root, inflater, *caseListFilter);
	const char* const					filenamePattern = cmdLine.getCaseListExportFile();

	while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
	{
		const TestNode* node		= iter.getNode();
		const char*		pkgName		= node->getName();
		const string	filename	= makePackageFilename(filenamePattern, pkgName, "xml");

		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
				  node->getNodeType() == NODETYPE_PACKAGE);

		FILE*			file	= DE_NULL;
		qpXmlWriter*	writer	= DE_NULL;

		try
		{
			file = fopen(filename.c_str(), "wb");
			if (!file)
				throw Exception("Failed to open " + filename);

			writer = qpXmlWriter_createFileWriter(file, DE_FALSE, DE_FALSE);
			if (!writer)
				throw Exception("XML writer creation failed");

			print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());

			writeXmlCaselist(iter, writer);

			qpXmlWriter_destroy(writer);
			writer = DE_NULL;

			fclose(file);
			file = DE_NULL;
		}
		catch (...)
		{
			if (writer)
				qpXmlWriter_destroy(writer);
			if (file)
				fclose(file);
			throw;
		}

		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
				  iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
		iter.next();
	}
}
/*--------------------------------------------------------------------*//*!
 * \brief Export the test list of each package into a separate ascii file.
 *//*--------------------------------------------------------------------*/
void writeTxtCaselistsToFiles (TestPackageRoot& root, TestContext& testCtx, const CommandLine& cmdLine)
{
	DefaultHierarchyInflater			inflater		(testCtx);
	de::MovePtr<const CaseListFilter>	caseListFilter	(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));

	TestHierarchyIterator				iter			(root, inflater, *caseListFilter);
	const char* const					filenamePattern = cmdLine.getCaseListExportFile();

	while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
	{
		const TestNode* node		= iter.getNode();
		const char*		pkgName		= node->getName();
		const string	filename	= makePackageFilename(filenamePattern, pkgName, "txt");

		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
				  node->getNodeType() == NODETYPE_PACKAGE);

		std::ofstream out(filename.c_str(), std::ios_base::binary);
		if (!out.is_open() || !out.good())
			throw Exception("Failed to open " + filename);

		print("Writing test cases from '%s' to file '%s'..\n", pkgName, filename.c_str());

		iter.next();

		while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
		{
			if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
				out << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": " << iter.getNodePath() << "\n";
			iter.next();
		}

		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
				  iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
		iter.next();
	}
}