Import dEQP.

Import drawElements Quality Program from an internal repository.

Bug: 17388917
Change-Id: Ic109fe4a57e31b2a816113d90fbdf51a43e7abeb
diff --git a/executor/xeContainerFormatParser.cpp b/executor/xeContainerFormatParser.cpp
new file mode 100644
index 0000000..a15449c
--- /dev/null
+++ b/executor/xeContainerFormatParser.cpp
@@ -0,0 +1,326 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Test Executor
+ * ------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test log container format parser.
+ *//*--------------------------------------------------------------------*/
+
+#include "xeContainerFormatParser.hpp"
+#include "deInt32.h"
+
+namespace xe
+{
+
+enum
+{
+	CONTAINERFORMATPARSER_INITIAL_BUFFER_SIZE = 1024
+};
+
+static int getNextBufferSize (int curSize, int minNewSize)
+{
+	return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize));
+}
+
+ContainerFormatParser::ContainerFormatParser (void)
+	: m_element		(CONTAINERELEMENT_INCOMPLETE)
+	, m_elementLen	(0)
+	, m_state		(STATE_AT_LINE_START)
+	, m_buf			(CONTAINERFORMATPARSER_INITIAL_BUFFER_SIZE)
+{
+}
+
+ContainerFormatParser::~ContainerFormatParser (void)
+{
+}
+
+void ContainerFormatParser::clear (void)
+{
+	m_element		= CONTAINERELEMENT_INCOMPLETE;
+	m_elementLen	= 0;
+	m_state			= STATE_AT_LINE_START;
+	m_buf.clear();
+}
+
+void ContainerFormatParser::error (const std::string& what)
+{
+	throw ContainerParseError(what);
+}
+
+void ContainerFormatParser::feed (const deUint8* bytes, int numBytes)
+{
+	// Grow buffer if necessary.
+	if (m_buf.getNumFree() < numBytes)
+		m_buf.resize(getNextBufferSize(m_buf.getSize(), m_buf.getNumElements()+numBytes));
+
+	// Append to front.
+	m_buf.pushFront(bytes, numBytes);
+
+	// If we haven't parsed complete element, re-try after data feed.
+	if (m_element == CONTAINERELEMENT_INCOMPLETE)
+		advance();
+}
+
+const char* ContainerFormatParser::getSessionInfoAttribute (void) const
+{
+	DE_ASSERT(m_element == CONTAINERELEMENT_SESSION_INFO);
+	return m_attribute.c_str();
+}
+
+const char* ContainerFormatParser::getSessionInfoValue (void) const
+{
+	DE_ASSERT(m_element == CONTAINERELEMENT_SESSION_INFO);
+	return m_value.c_str();
+}
+
+const char* ContainerFormatParser::getTestCasePath (void) const
+{
+	DE_ASSERT(m_element == CONTAINERELEMENT_BEGIN_TEST_CASE_RESULT);
+	return m_value.c_str();
+}
+
+const char* ContainerFormatParser::getTerminateReason (void) const
+{
+	DE_ASSERT(m_element == CONTAINERELEMENT_TERMINATE_TEST_CASE_RESULT);
+	return m_value.c_str();
+}
+
+int ContainerFormatParser::getDataSize (void) const
+{
+	DE_ASSERT(m_element == CONTAINERELEMENT_TEST_LOG_DATA);
+	return m_elementLen;
+}
+
+void ContainerFormatParser::getData (deUint8* dst, int numBytes, int offset)
+{
+	DE_ASSERT(de::inBounds(offset, 0, m_elementLen) && numBytes > 0 && de::inRange(numBytes+offset, 0, m_elementLen));
+
+	for (int ndx = 0; ndx < numBytes; ndx++)
+		dst[ndx] = m_buf.peekBack(offset+ndx);
+}
+
+int ContainerFormatParser::getChar (int offset) const
+{
+	DE_ASSERT(de::inRange(offset, 0, m_buf.getNumElements()));
+
+	if (offset < m_buf.getNumElements())
+		return m_buf.peekBack(offset);
+	else
+		return END_OF_BUFFER;
+}
+
+void ContainerFormatParser::advance (void)
+{
+	if (m_element != CONTAINERELEMENT_INCOMPLETE)
+	{
+		m_buf.popBack(m_elementLen);
+
+		m_element		= CONTAINERELEMENT_INCOMPLETE;
+		m_elementLen	= 0;
+		m_attribute.clear();
+		m_value.clear();
+	}
+
+	for (;;)
+	{
+		int curChar = getChar(m_elementLen);
+
+		if (curChar != (int)END_OF_BUFFER)
+			m_elementLen += 1;
+
+		if (curChar == END_OF_STRING)
+		{
+			if (m_elementLen == 1)
+				m_element = CONTAINERELEMENT_END_OF_STRING;
+			else if (m_state == STATE_CONTAINER_LINE)
+				parseContainerLine();
+			else
+				m_element = CONTAINERELEMENT_TEST_LOG_DATA;
+
+			break;
+		}
+		else if (curChar == (int)END_OF_BUFFER)
+		{
+			if (m_elementLen > 0 && m_state == STATE_DATA)
+				m_element = CONTAINERELEMENT_TEST_LOG_DATA;
+
+			break;
+		}
+		else if (curChar == '\r' || curChar == '\n')
+		{
+			// Check for \r\n
+			int nextChar = getChar(m_elementLen);
+			if (curChar == '\n' || (nextChar != (int)END_OF_BUFFER && nextChar != '\n'))
+			{
+				if (m_state == STATE_CONTAINER_LINE)
+					parseContainerLine();
+				else
+					m_element = CONTAINERELEMENT_TEST_LOG_DATA;
+
+				m_state = STATE_AT_LINE_START;
+				break;
+			}
+			// else handle following end or \n in next iteration.
+		}
+		else if (m_state == STATE_AT_LINE_START)
+		{
+			DE_ASSERT(m_elementLen == 1);
+			m_state = (curChar == '#') ? STATE_CONTAINER_LINE : STATE_DATA;
+		}
+	}
+}
+
+void ContainerFormatParser::parseContainerLine (void)
+{
+	static const struct
+	{
+		const char*			name;
+		ContainerElement	element;
+	} s_elements[] =
+	{
+		{ "beginTestCaseResult",		CONTAINERELEMENT_BEGIN_TEST_CASE_RESULT		},
+		{ "endTestCaseResult",			CONTAINERELEMENT_END_TEST_CASE_RESULT		},
+		{ "terminateTestCaseResult",	CONTAINERELEMENT_TERMINATE_TEST_CASE_RESULT	},
+		{ "sessionInfo",				CONTAINERELEMENT_SESSION_INFO				},
+		{ "beginSession",				CONTAINERELEMENT_BEGIN_SESSION				},
+		{ "endSession",					CONTAINERELEMENT_END_SESSION				}
+	};
+
+	DE_ASSERT(m_elementLen >= 1);
+	DE_ASSERT(getChar(0) == '#');
+
+	int offset = 1;
+
+	for (int elemNdx = 0; elemNdx < DE_LENGTH_OF_ARRAY(s_elements); elemNdx++)
+	{
+		bool	isMatch	= false;
+		int		ndx		= 0;
+
+		for (;;)
+		{
+			int		bufChar		= (offset+ndx < m_elementLen) ? getChar(offset+ndx) : 0;
+			bool	bufEnd		= bufChar == 0 || bufChar == ' ' || bufChar == '\r' || bufChar == '\n' || bufChar == (int)END_OF_BUFFER;
+			int		elemChar	= s_elements[elemNdx].name[ndx];
+			bool	elemEnd		= elemChar == 0;
+
+			if (bufEnd || elemEnd)
+			{
+				isMatch = bufEnd == elemEnd;
+				break;
+			}
+			else if (bufChar != elemChar)
+				break;
+
+			ndx += 1;
+		}
+
+		if (isMatch)
+		{
+			m_element	 = s_elements[elemNdx].element;
+			offset		+= ndx;
+			break;
+		}
+	}
+
+	switch (m_element)
+	{
+		case CONTAINERELEMENT_BEGIN_SESSION:
+		case CONTAINERELEMENT_END_SESSION:
+		case CONTAINERELEMENT_END_TEST_CASE_RESULT:
+			break; // No attribute or value.
+
+		case CONTAINERELEMENT_BEGIN_TEST_CASE_RESULT:
+		case CONTAINERELEMENT_TERMINATE_TEST_CASE_RESULT:
+			if (getChar(offset) != ' ')
+				error("Expected value after instruction");
+			offset += 1;
+			parseContainerValue(m_value, offset);
+			break;
+
+		case CONTAINERELEMENT_SESSION_INFO:
+			if (getChar(offset) != ' ')
+				error("Expected attribute name after #sessionInfo");
+			offset += 1;
+			parseContainerValue(m_attribute, offset);
+			if (getChar(offset) != ' ')
+				error("No value for #sessionInfo attribute");
+			offset += 1;
+
+			if (m_attribute == "timestamp")
+			{
+				m_value.clear();
+
+				// \note Candy produces timestamps in very stupid fashion.
+				for (;;)
+				{
+					const int	curChar	= offset < m_elementLen ? getChar(offset) : 0;
+					const bool	isEnd	= curChar == 0 || curChar == (int)END_OF_BUFFER || curChar == '\n' || curChar == '\t';
+
+					if (isEnd)
+						break;
+					else
+						m_value.push_back((char)curChar);
+
+					offset += 1;
+				}
+			}
+			else
+				parseContainerValue(m_value, offset);
+			break;
+
+		default:
+			// \todo [2012-06-09 pyry] Implement better way to handle # at the beginning of log lines.
+			m_element = CONTAINERELEMENT_TEST_LOG_DATA;
+			break;
+	}
+}
+
+void ContainerFormatParser::parseContainerValue (std::string& dst, int& offset) const
+{
+	DE_ASSERT(offset < m_elementLen);
+
+	bool	isString	= getChar(offset) == '"' || getChar(offset) == '\'';
+	int		quotChar	= isString ? getChar(offset) : 0;
+
+	if (isString)
+		offset += 1;
+
+	dst.clear();
+
+	for (;;)
+	{
+		int		curChar		= offset < m_elementLen ? getChar(offset) : 0;
+		bool	isEnd		= curChar == 0 || curChar == (int)END_OF_BUFFER ||
+							  (isString ? (curChar == quotChar) : (curChar == ' ' || curChar == '\n' || curChar == '\r'));
+
+		if (isEnd)
+			break;
+		else
+		{
+			// \todo [2012-06-09 pyry] Escapes.
+			dst.push_back((char)curChar);
+		}
+
+		offset += 1;
+	}
+
+	if (isString && getChar(offset) == quotChar)
+		offset += 1;
+}
+
+} // xe