<commit_before>
#include <ionConfig.h>

#ifdef _ION_CONFIG_USE_GWEN

#include "OpenGL3.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/swizzle.hpp>

namespace Gwen
{
	namespace Renderer
	{
		using namespace ion::GL;

		OpenGL3::OpenGL3(vec2i const & screenSize)
			: Shader(0),
			m_currentQuadCount(0),
			ScreenSize(screenSize),
			m_maxSpriteCount(2)
		{
			Init();
		}

		OpenGL3::~OpenGL3()
		{
			glDeleteBuffers(1, &m_vbo);
			glDeleteBuffers(1, &m_ebo);

			glDeleteVertexArrays(1, &m_vao);

			delete Shader;
		}

		void OpenGL3::Init()
		{
			static string const VertexShaderSource = R"SHADER(
				#version 330

				uniform mat4 mvp;

				in vec2 position;
				in vec2 texcoord;
				in vec4 color;

				out vec2 TextureCoordinates;
				out vec4 Color;

				void main()
				{
					gl_Position = mvp * vec4(position, 0.0, 1.0);
					TextureCoordinates = texcoord;
					Color = color;
				}
			)SHADER";

			static string const FragmentShaderSource = R"SHADER(
				#version 330

				uniform sampler2D tex;

				in vec2 TextureCoordinates;
				in vec4 Color;

				out vec4 FragColor;

				void main()
				{
					FragColor = Color * texture2D(tex, TextureCoordinates);
				}
			)SHADER";

			VertexShader * vert = new VertexShader;
			vert->Source(VertexShaderSource);
			if (! vert->Compile())
				std::cerr << "Failed to compile vertex shader!" << std::endl << vert->InfoLog() << std::endl;

			FragmentShader * frag = new FragmentShader;
			frag->Source(FragmentShaderSource);
			if (! frag->Compile())
				std::cerr << "Failed to compile vertex shader!" << std::endl << frag->InfoLog() << std::endl;

			Shader = new Program;
			Shader->AttachShader(vert);
			Shader->AttachShader(frag);
			Shader->Link();
			Shader->BindAttributeLocation(0, "position");
			Shader->BindAttributeLocation(1, "texcoord");
			Shader->BindAttributeLocation(2, "color");

			initGL();
			checkGLError();

			glGenTextures(1, & m_whiteTexture);
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, m_whiteTexture);

			checkGLError();

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

			GLubyte image[] = {255, 255, 255, 255};

			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
		}

		void OpenGL3::initGL()
		{
			glGenVertexArrays(1, & m_vao);
			glBindVertexArray(m_vao);

			glGenBuffers(1, & m_vbo);
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
			glBufferData(GL_ARRAY_BUFFER, m_maxSpriteCount * 4 * sizeof(Vertex), NULL, GL_DYNAMIC_DRAW);

			checkGLError();

			std::vector<u32> indicesv;
			const u32 indices[] = {0, 1, 2, 0, 2, 3};
			for (int j = 0; j < m_maxSpriteCount; j++)
				for (size_t i = 0; i < sizeof(indices) / sizeof(*indices); i++)
					indicesv.push_back(4 * j + indices[i]);

			glGenBuffers(1, & m_ebo);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
			glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesv.size() * sizeof(u32), indicesv.data(), GL_STATIC_DRAW);

			glBindVertexArray(0);

			checkGLError();
		}

		void OpenGL3::checkGLError()
		{
			GLenum error = glGetError();
			if (error != GL_NO_ERROR)
			{
				std::cout << gluErrorString(error) << "\n";
				assert(0);
			}
		}

		void OpenGL3::Begin()
		{
			m_currentQuadCount = 0;
		}

		void OpenGL3::End()
		{
			checkGLError();
		}

		void OpenGL3::DrawFilledRect(Gwen::Rect rect)
		{
			Translate(rect);

			addQuad(rect, Color, 0, 0, 1, 1);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, m_whiteTexture);

			finalizeDraw();
		}

		void OpenGL3::SetDrawColor(Gwen::Color color)
		{
			glColor4ubv((GLubyte *) & color);
			Color = color;
		}

		void OpenGL3::StartClip()
		{
			Gwen::Rect rect = ClipRegion();

			// OpenGL's coords are from the bottom left
			// so we need to translate them here.
			rect.y = ScreenSize.Y - (rect.y + rect.h);
			glScissor(rect.x * Scale(), rect.y * Scale(), rect.w * Scale(), rect.h * Scale());
			glEnable(GL_SCISSOR_TEST);
		}

		void OpenGL3::EndClip()
		{
			glDisable(GL_SCISSOR_TEST);
		}

		void OpenGL3::DrawTexturedRect(Gwen::Texture* pTexture, Gwen::Rect rect, float u1, float v1, float u2, float v2)
		{
			GLuint * tex = (GLuint *) pTexture->data;

			if (! tex)
			{
				std::cerr << "Texture for GWEN draw call is missing." << std::endl;
				return DrawMissingImage(rect);
			}

			Translate(rect);

			if (m_currentBoundTexture != * tex)
			{
				m_currentBoundTexture = * tex;

				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, * tex);
			}

			addQuad(rect, Gwen::Color(), u1, v1, u2, v2);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, * tex);

			finalizeDraw();
			checkGLError();
		}

		void OpenGL3::finalizeDraw()
		{
			m_currentQuadCount = 2;

			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
			glBindVertexArray(m_vao);

			size_t buffer_offset = 0;

			m_projectionMatrix = glm::ortho(0.0f, (f32) ScreenSize.X, (f32) ScreenSize.Y, 0.0f, -1.0f, 1.0f);
			glm::mat4 mvp = m_projectionMatrix;

			DrawContext context(Shader);
			context.BindUniform("mvp", new UniformValue<glm::mat4>(mvp));

			GLint pos_attrib = 0;
			glEnableVertexAttribArray(pos_attrib);
			glVertexAttribPointer(
				pos_attrib,
				2,
				GL_FLOAT,
				GL_FALSE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);
			buffer_offset += sizeof(f32) * 2;

			GLint color_attrib = 2;

			checkGLError();

			glEnableVertexAttribArray(color_attrib);
			glVertexAttribPointer(
				color_attrib,
				4,
				GL_UNSIGNED_BYTE,
				GL_TRUE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);
			buffer_offset += sizeof(u32);

			checkGLError();

			GLint texcoord_attrib = 1;
			glEnableVertexAttribArray(texcoord_attrib);
			glVertexAttribPointer(
				texcoord_attrib,
				2,
				GL_FLOAT,
				GL_FALSE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);

			glDrawElements(
				GL_TRIANGLES,
				6 * (m_currentQuadCount), // 6 indices per 2 triangles
				GL_UNSIGNED_INT,
				(const GLvoid*)0);

			glBindVertexArray(0);
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

			glDisable(GL_BLEND);
		}

		void OpenGL3::addQuad(const Gwen::Rect& rect, const Gwen::Color& color, float u1, float v1, float u2, float v2)
		{
			// vertices that will be uploaded.
			Vertex vertices[4];

			// vertices[n][0] -> X, and [1] -> Y
			// vertices[0] -> top left
			// vertices[1] -> bottom left
			// vertices[2] -> bottom right
			// vertices[3] -> top right

			vertices[0].x = rect.x;
			vertices[0].y = rect.y;

			vertices[1].x = rect.x;
			vertices[1].y = rect.y + rect.h;

			vertices[2].x = rect.x + rect.w;
			vertices[2].y = rect.y + rect.h;

			vertices[3].x = rect.x + rect.w;
			vertices[3].y = rect.y;

			checkGLError();

			// copy color to the buffer
			for (size_t i = 0; i < sizeof(vertices) / sizeof(*vertices); ++ i)
			{
				int colorPacked = color.r | (color.g << 8) | (color.b << 16) | (color.a << 24);
				vertices[i].color = colorPacked;
			}

			// copy texcoords to the buffer
			vertices[0].u = vertices[1].u = u1;
			vertices[0].v = vertices[3].v = v1;
			vertices[1].v = vertices[2].v = v2;
			vertices[2].u = vertices[3].u = u2;

			checkGLError();

			// finally upload everything to the actual vbo
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

			glBufferSubData(
				GL_ARRAY_BUFFER,
				sizeof(vertices) ,
				sizeof(vertices),
				vertices);

			glBindBuffer(GL_ARRAY_BUFFER, 0);

			++ m_currentQuadCount;
		}

		void OpenGL3::LoadTexture(Gwen::Texture* pTexture)
		{
			CImage * Image = CImage::Load(pTexture->name.c_str());

			// Image failed to load..
			if (! Image)
			{
				pTexture->failed = true;
				std::string str;
				str.append("Texture load failure, image format unknown or file does not exist: ");
				str.append(pTexture->name.Get());
				return;
			}

			Image->FlipY();

			// Create a little texture pointer..
			GLuint* pglTexture = new GLuint;

			// Sort out our GWEN texture
			pTexture->data = pglTexture;
			pTexture->width = Image->GetWidth();
			pTexture->height = Image->GetHeight();

			glActiveTexture(GL_TEXTURE0);
			// Create the opengl texture
			glGenTextures( 1, pglTexture );
			glBindTexture( GL_TEXTURE_2D, *pglTexture );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

			m_currentBoundTexture = *pglTexture;

			GLenum format = GL_RGBA;

			glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, pTexture->width, pTexture->height, 0, format, GL_UNSIGNED_BYTE, Image->GetData() );

			checkGLError();
		}

		void OpenGL3::FreeTexture( Gwen::Texture* pTexture )
		{
			checkGLError();
			GLuint* tex = (GLuint*)pTexture->data;
			if ( !tex ) return;

			glDeleteTextures( 1, tex );
			delete tex;
			pTexture->data = NULL;
			checkGLError();
		}

		Gwen::Color OpenGL3::PixelColour( Gwen::Texture* pTexture, unsigned int x, unsigned int y, const Gwen::Color& col_default )
		{
			checkGLError();
			GLuint* tex = (GLuint*)pTexture->data;
			if ( !tex ) return col_default;

			unsigned int iPixelSize = sizeof(unsigned char) * 4;

			glBindTexture( GL_TEXTURE_2D, *tex );

			unsigned char* data = (unsigned char*) malloc( iPixelSize * pTexture->width * pTexture->height );

			glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

			unsigned int iOffset = (y * pTexture->width + x) * 4;

			Gwen::Color c;
			c.r = data[0 + iOffset];
			c.g = data[1 + iOffset];
			c.b = data[2 + iOffset];
			c.a = data[3 + iOffset];

			//
			// Retrieving the entire texture for a single pixel read
			// is kind of a waste - maybe cache this pointer in the texture
			// data and then release later on? It's never called during runtime
			// - only during initialization.
			//
			free( data );
			checkGLError();

			return c;
		}

		bool OpenGL3::InitializeContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::ShutdownContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::PresentContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::ResizedContext( Gwen::WindowProvider* pWindow, int w, int h )
		{

			return false;
		}

		bool OpenGL3::BeginContext( Gwen::WindowProvider* pWindow )
		{
			return true;
		}

		bool OpenGL3::EndContext( Gwen::WindowProvider* pWindow )
		{
			return true;
		}

	}
}

#endif
<commit_msg>Extra GL error check<commit_after>
#include <ionConfig.h>

#ifdef _ION_CONFIG_USE_GWEN

#include "OpenGL3.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/swizzle.hpp>

namespace Gwen
{
	namespace Renderer
	{
		using namespace ion::GL;

		OpenGL3::OpenGL3(vec2i const & screenSize)
			: Shader(0),
			m_currentQuadCount(0),
			ScreenSize(screenSize),
			m_maxSpriteCount(2)
		{
			Init();
		}

		OpenGL3::~OpenGL3()
		{
			glDeleteBuffers(1, &m_vbo);
			glDeleteBuffers(1, &m_ebo);

			glDeleteVertexArrays(1, &m_vao);

			delete Shader;
		}

		void OpenGL3::Init()
		{
			static string const VertexShaderSource = R"SHADER(
				#version 330

				uniform mat4 mvp;

				in vec2 position;
				in vec2 texcoord;
				in vec4 color;

				out vec2 TextureCoordinates;
				out vec4 Color;

				void main()
				{
					gl_Position = mvp * vec4(position, 0.0, 1.0);
					TextureCoordinates = texcoord;
					Color = color;
				}
			)SHADER";

			static string const FragmentShaderSource = R"SHADER(
				#version 330

				uniform sampler2D tex;

				in vec2 TextureCoordinates;
				in vec4 Color;

				out vec4 FragColor;

				void main()
				{
					FragColor = Color * texture2D(tex, TextureCoordinates);
				}
			)SHADER";

			VertexShader * vert = new VertexShader;
			vert->Source(VertexShaderSource);
			if (! vert->Compile())
				std::cerr << "Failed to compile vertex shader!" << std::endl << vert->InfoLog() << std::endl;

			FragmentShader * frag = new FragmentShader;
			frag->Source(FragmentShaderSource);
			if (! frag->Compile())
				std::cerr << "Failed to compile vertex shader!" << std::endl << frag->InfoLog() << std::endl;

			Shader = new Program;
			Shader->AttachShader(vert);
			Shader->AttachShader(frag);
			Shader->Link();
			Shader->BindAttributeLocation(0, "position");
			Shader->BindAttributeLocation(1, "texcoord");
			Shader->BindAttributeLocation(2, "color");

			initGL();
			checkGLError();

			glGenTextures(1, & m_whiteTexture);
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, m_whiteTexture);

			checkGLError();

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

			GLubyte image[] = {255, 255, 255, 255};

			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
		}

		void OpenGL3::initGL()
		{
			glGenVertexArrays(1, & m_vao);
			glBindVertexArray(m_vao);

			glGenBuffers(1, & m_vbo);
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
			glBufferData(GL_ARRAY_BUFFER, m_maxSpriteCount * 4 * sizeof(Vertex), NULL, GL_DYNAMIC_DRAW);

			checkGLError();

			std::vector<u32> indicesv;
			const u32 indices[] = {0, 1, 2, 0, 2, 3};
			for (int j = 0; j < m_maxSpriteCount; j++)
				for (size_t i = 0; i < sizeof(indices) / sizeof(*indices); i++)
					indicesv.push_back(4 * j + indices[i]);

			glGenBuffers(1, & m_ebo);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
			glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesv.size() * sizeof(u32), indicesv.data(), GL_STATIC_DRAW);

			glBindVertexArray(0);

			checkGLError();
		}

		void OpenGL3::checkGLError()
		{
			GLenum error = glGetError();
			if (error != GL_NO_ERROR)
			{
				std::cout << gluErrorString(error) << "\n";
				assert(0);
			}
		}

		void OpenGL3::Begin()
		{
			m_currentQuadCount = 0;
		}

		void OpenGL3::End()
		{
			checkGLError();
		}

		void OpenGL3::DrawFilledRect(Gwen::Rect rect)
		{
			Translate(rect);

			addQuad(rect, Color, 0, 0, 1, 1);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, m_whiteTexture);

			finalizeDraw();
		}

		void OpenGL3::SetDrawColor(Gwen::Color color)
		{
			glColor4ubv((GLubyte *) & color);
			Color = color;
		}

		void OpenGL3::StartClip()
		{
			Gwen::Rect rect = ClipRegion();

			// OpenGL's coords are from the bottom left
			// so we need to translate them here.
			rect.y = ScreenSize.Y - (rect.y + rect.h);
			glScissor(rect.x * Scale(), rect.y * Scale(), rect.w * Scale(), rect.h * Scale());
			glEnable(GL_SCISSOR_TEST);
		}

		void OpenGL3::EndClip()
		{
			glDisable(GL_SCISSOR_TEST);
		}

		void OpenGL3::DrawTexturedRect(Gwen::Texture* pTexture, Gwen::Rect rect, float u1, float v1, float u2, float v2)
		{
			GLuint * tex = (GLuint *) pTexture->data;

			if (! tex)
			{
				std::cerr << "Texture for GWEN draw call is missing." << std::endl;
				return DrawMissingImage(rect);
			}

			Translate(rect);

			if (m_currentBoundTexture != * tex)
			{
				m_currentBoundTexture = * tex;

				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, * tex);
			}

			addQuad(rect, Gwen::Color(), u1, v1, u2, v2);

			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, * tex);

			finalizeDraw();
			checkGLError();
		}

		void OpenGL3::finalizeDraw()
		{
			m_currentQuadCount = 2;

			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
			glBindVertexArray(m_vao);

			size_t buffer_offset = 0;

			m_projectionMatrix = glm::ortho(0.0f, (f32) ScreenSize.X, (f32) ScreenSize.Y, 0.0f, -1.0f, 1.0f);
			glm::mat4 mvp = m_projectionMatrix;

			DrawContext context(Shader);
			context.BindUniform("mvp", new UniformValue<glm::mat4>(mvp));

			GLint pos_attrib = 0;
			glEnableVertexAttribArray(pos_attrib);
			glVertexAttribPointer(
				pos_attrib,
				2,
				GL_FLOAT,
				GL_FALSE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);
			buffer_offset += sizeof(f32) * 2;

			GLint color_attrib = 2;

			checkGLError();

			glEnableVertexAttribArray(color_attrib);
			glVertexAttribPointer(
				color_attrib,
				4,
				GL_UNSIGNED_BYTE,
				GL_TRUE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);
			buffer_offset += sizeof(u32);

			checkGLError();

			GLint texcoord_attrib = 1;
			glEnableVertexAttribArray(texcoord_attrib);
			glVertexAttribPointer(
				texcoord_attrib,
				2,
				GL_FLOAT,
				GL_FALSE,
				sizeof(Vertex),
				(const GLvoid*)buffer_offset);

			checkGLError();

			glDrawElements(
				GL_TRIANGLES,
				6 * (m_currentQuadCount), // 6 indices per 2 triangles
				GL_UNSIGNED_INT,
				(const GLvoid*)0);

			glBindVertexArray(0);
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

			glDisable(GL_BLEND);
		}

		void OpenGL3::addQuad(const Gwen::Rect& rect, const Gwen::Color& color, float u1, float v1, float u2, float v2)
		{
			// vertices that will be uploaded.
			Vertex vertices[4];

			// vertices[n][0] -> X, and [1] -> Y
			// vertices[0] -> top left
			// vertices[1] -> bottom left
			// vertices[2] -> bottom right
			// vertices[3] -> top right

			vertices[0].x = rect.x;
			vertices[0].y = rect.y;

			vertices[1].x = rect.x;
			vertices[1].y = rect.y + rect.h;

			vertices[2].x = rect.x + rect.w;
			vertices[2].y = rect.y + rect.h;

			vertices[3].x = rect.x + rect.w;
			vertices[3].y = rect.y;

			checkGLError();

			// copy color to the buffer
			for (size_t i = 0; i < sizeof(vertices) / sizeof(*vertices); ++ i)
			{
				int colorPacked = color.r | (color.g << 8) | (color.b << 16) | (color.a << 24);
				vertices[i].color = colorPacked;
			}

			// copy texcoords to the buffer
			vertices[0].u = vertices[1].u = u1;
			vertices[0].v = vertices[3].v = v1;
			vertices[1].v = vertices[2].v = v2;
			vertices[2].u = vertices[3].u = u2;

			checkGLError();

			// finally upload everything to the actual vbo
			glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

			glBufferSubData(
				GL_ARRAY_BUFFER,
				sizeof(vertices) ,
				sizeof(vertices),
				vertices);

			glBindBuffer(GL_ARRAY_BUFFER, 0);

			++ m_currentQuadCount;
		}

		void OpenGL3::LoadTexture(Gwen::Texture* pTexture)
		{
			CImage * Image = CImage::Load(pTexture->name.c_str());

			// Image failed to load..
			if (! Image)
			{
				pTexture->failed = true;
				std::string str;
				str.append("Texture load failure, image format unknown or file does not exist: ");
				str.append(pTexture->name.Get());
				return;
			}

			Image->FlipY();

			// Create a little texture pointer..
			GLuint* pglTexture = new GLuint;

			// Sort out our GWEN texture
			pTexture->data = pglTexture;
			pTexture->width = Image->GetWidth();
			pTexture->height = Image->GetHeight();

			glActiveTexture(GL_TEXTURE0);
			// Create the opengl texture
			glGenTextures( 1, pglTexture );
			glBindTexture( GL_TEXTURE_2D, *pglTexture );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

			m_currentBoundTexture = *pglTexture;

			GLenum format = GL_RGBA;

			glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, pTexture->width, pTexture->height, 0, format, GL_UNSIGNED_BYTE, Image->GetData() );

			checkGLError();
		}

		void OpenGL3::FreeTexture( Gwen::Texture* pTexture )
		{
			checkGLError();
			GLuint* tex = (GLuint*)pTexture->data;
			if ( !tex ) return;

			glDeleteTextures( 1, tex );
			delete tex;
			pTexture->data = NULL;
			checkGLError();
		}

		Gwen::Color OpenGL3::PixelColour( Gwen::Texture* pTexture, unsigned int x, unsigned int y, const Gwen::Color& col_default )
		{
			checkGLError();
			GLuint* tex = (GLuint*)pTexture->data;
			if ( !tex ) return col_default;

			unsigned int iPixelSize = sizeof(unsigned char) * 4;

			glBindTexture( GL_TEXTURE_2D, *tex );

			unsigned char* data = (unsigned char*) malloc( iPixelSize * pTexture->width * pTexture->height );

			glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

			unsigned int iOffset = (y * pTexture->width + x) * 4;

			Gwen::Color c;
			c.r = data[0 + iOffset];
			c.g = data[1 + iOffset];
			c.b = data[2 + iOffset];
			c.a = data[3 + iOffset];

			//
			// Retrieving the entire texture for a single pixel read
			// is kind of a waste - maybe cache this pointer in the texture
			// data and then release later on? It's never called during runtime
			// - only during initialization.
			//
			free( data );
			checkGLError();

			return c;
		}

		bool OpenGL3::InitializeContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::ShutdownContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::PresentContext( Gwen::WindowProvider* pWindow )
		{
			return false;
		}

		bool OpenGL3::ResizedContext( Gwen::WindowProvider* pWindow, int w, int h )
		{

			return false;
		}

		bool OpenGL3::BeginContext( Gwen::WindowProvider* pWindow )
		{
			return true;
		}

		bool OpenGL3::EndContext( Gwen::WindowProvider* pWindow )
		{
			return true;
		}

	}
}

#endif
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkComposeShader.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkColorShader.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkXfermode.h"
#include "SkString.h"

///////////////////////////////////////////////////////////////////////////////

SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
    fShaderA = sA;  sA->ref();
    fShaderB = sB;  sB->ref();
    // mode may be null
    fMode = mode;
    SkSafeRef(mode);
}

SkComposeShader::~SkComposeShader() {
    SkSafeUnref(fMode);
    fShaderB->unref();
    fShaderA->unref();
}

size_t SkComposeShader::contextSize() const {
    return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
}

class SkAutoAlphaRestore {
public:
    SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
        fAlpha = paint->getAlpha();
        fPaint = paint;
        paint->setAlpha(newAlpha);
    }

    ~SkAutoAlphaRestore() {
        fPaint->setAlpha(fAlpha);
    }
private:
    SkPaint*    fPaint;
    uint8_t     fAlpha;
};
#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)

SkFlattenable* SkComposeShader::CreateProc(SkReadBuffer& buffer) {
    SkAutoTUnref<SkShader> shaderA(buffer.readShader());
    SkAutoTUnref<SkShader> shaderB(buffer.readShader());
    SkAutoTUnref<SkXfermode> mode(buffer.readXfermode());
    if (!shaderA.get() || !shaderB.get()) {
        return nullptr;
    }
    return new SkComposeShader(shaderA, shaderB, mode);
}

void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
    buffer.writeFlattenable(fShaderA);
    buffer.writeFlattenable(fShaderB);
    buffer.writeFlattenable(fMode);
}

template <typename T> void safe_call_destructor(T* obj) {
    if (obj) {
        obj->~T();
    }
}

SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const {
    char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
    char* bStorage = aStorage + fShaderA->contextSize();

    // we preconcat our localMatrix (if any) with the device matrix
    // before calling our sub-shaders
    SkMatrix tmpM;
    tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());

    // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
    // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
    // sub-shaders.
    SkPaint opaquePaint(*rec.fPaint);
    opaquePaint.setAlpha(0xFF);

    ContextRec newRec(rec);
    newRec.fMatrix = &tmpM;
    newRec.fPaint = &opaquePaint;

    SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage);
    SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage);
    if (!contextA || !contextB) {
        safe_call_destructor(contextA);
        safe_call_destructor(contextB);
        return nullptr;
    }

    return new (storage) ComposeShaderContext(*this, rec, contextA, contextB);
}

SkComposeShader::ComposeShaderContext::ComposeShaderContext(
        const SkComposeShader& shader, const ContextRec& rec,
        SkShader::Context* contextA, SkShader::Context* contextB)
    : INHERITED(shader, rec)
    , fShaderContextA(contextA)
    , fShaderContextB(contextB) {}

SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
    fShaderContextA->~Context();
    fShaderContextB->~Context();
}

bool SkComposeShader::asACompose(ComposeRec* rec) const {
    if (rec) {
        rec->fShaderA = fShaderA;
        rec->fShaderB = fShaderB;
        rec->fMode = fMode;
    }
    return true;
}

// larger is better (fewer times we have to loop), but we shouldn't
// take up too much stack-space (each element is 4 bytes)
#define TMP_COLOR_COUNT     64

void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
    SkShader::Context* shaderContextA = fShaderContextA;
    SkShader::Context* shaderContextB = fShaderContextB;
    SkXfermode*        mode = static_cast<const SkComposeShader&>(fShader).fMode;
    unsigned           scale = SkAlpha255To256(this->getPaintAlpha());

#ifdef SK_BUILD_FOR_ANDROID
    scale = 256;    // ugh -- maintain old bug/behavior for now
#endif

    SkPMColor   tmp[TMP_COLOR_COUNT];

    if (nullptr == mode) {   // implied SRC_OVER
        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
        // for these loops
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);

            if (256 == scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkPMSrcOver(tmp[i], result[i]);
                }
            } else {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
                                            scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    } else {    // use mode for the composition
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);
            mode->xfer32(result, tmp, n, nullptr);

            if (256 != scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(result[i], scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    }
}

#if SK_SUPPORT_GPU

#include "effects/GrConstColorProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"

/////////////////////////////////////////////////////////////////////

const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* context,
                                                            const SkMatrix& viewM,
                                                            const SkMatrix* localMatrix,
                                                            SkFilterQuality fq) const {
    // Fragment processor will only support SkXfermode::Mode modes currently.
    SkXfermode::Mode mode;
    if (!(SkXfermode::AsMode(fMode, &mode))) {
        return nullptr;
    }

    switch (mode) {
        case SkXfermode::kClear_Mode:
            return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
                                                 GrConstColorProcessor::kIgnore_InputMode);
            break;
        case SkXfermode::kSrc_Mode:
            return fShaderB->asFragmentProcessor(context, viewM, localMatrix, fq);
            break;
        case SkXfermode::kDst_Mode:
            return fShaderA->asFragmentProcessor(context, viewM, localMatrix, fq);
            break;
        default:
            SkAutoTUnref<const GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(context,
                                                        viewM, localMatrix, fq));
            if (!fpA.get()) {
                return nullptr;
            }
            SkAutoTUnref<const GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(context,
                                                        viewM, localMatrix, fq));
            if (!fpB.get()) {
                return nullptr;
            }
            return GrXfermodeFragmentProcessor::CreateFromTwoProcessors(fpB, fpA, mode);
    }
}
#endif

#ifndef SK_IGNORE_TO_STRING
void SkComposeShader::toString(SkString* str) const {
    str->append("SkComposeShader: (");

    str->append("ShaderA: ");
    fShaderA->toString(str);
    str->append(" ShaderB: ");
    fShaderB->toString(str);
    if (fMode) {
        str->append(" Xfermode: ");
        fMode->toString(str);
    }

    this->INHERITED::toString(str);

    str->append(")");
}
#endif
<commit_msg>Use SK_BUILD_FOR_ANDROID_FRAMEWORK in compose<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkComposeShader.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkColorShader.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkXfermode.h"
#include "SkString.h"

///////////////////////////////////////////////////////////////////////////////

SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
    fShaderA = sA;  sA->ref();
    fShaderB = sB;  sB->ref();
    // mode may be null
    fMode = mode;
    SkSafeRef(mode);
}

SkComposeShader::~SkComposeShader() {
    SkSafeUnref(fMode);
    fShaderB->unref();
    fShaderA->unref();
}

size_t SkComposeShader::contextSize() const {
    return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
}

class SkAutoAlphaRestore {
public:
    SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
        fAlpha = paint->getAlpha();
        fPaint = paint;
        paint->setAlpha(newAlpha);
    }

    ~SkAutoAlphaRestore() {
        fPaint->setAlpha(fAlpha);
    }
private:
    SkPaint*    fPaint;
    uint8_t     fAlpha;
};
#define SkAutoAlphaRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoAlphaRestore)

SkFlattenable* SkComposeShader::CreateProc(SkReadBuffer& buffer) {
    SkAutoTUnref<SkShader> shaderA(buffer.readShader());
    SkAutoTUnref<SkShader> shaderB(buffer.readShader());
    SkAutoTUnref<SkXfermode> mode(buffer.readXfermode());
    if (!shaderA.get() || !shaderB.get()) {
        return nullptr;
    }
    return new SkComposeShader(shaderA, shaderB, mode);
}

void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
    buffer.writeFlattenable(fShaderA);
    buffer.writeFlattenable(fShaderB);
    buffer.writeFlattenable(fMode);
}

template <typename T> void safe_call_destructor(T* obj) {
    if (obj) {
        obj->~T();
    }
}

SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const {
    char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
    char* bStorage = aStorage + fShaderA->contextSize();

    // we preconcat our localMatrix (if any) with the device matrix
    // before calling our sub-shaders
    SkMatrix tmpM;
    tmpM.setConcat(*rec.fMatrix, this->getLocalMatrix());

    // Our sub-shaders need to see opaque, so by combining them we don't double-alphatize the
    // result. ComposeShader itself will respect the alpha, and post-apply it after calling the
    // sub-shaders.
    SkPaint opaquePaint(*rec.fPaint);
    opaquePaint.setAlpha(0xFF);

    ContextRec newRec(rec);
    newRec.fMatrix = &tmpM;
    newRec.fPaint = &opaquePaint;

    SkShader::Context* contextA = fShaderA->createContext(newRec, aStorage);
    SkShader::Context* contextB = fShaderB->createContext(newRec, bStorage);
    if (!contextA || !contextB) {
        safe_call_destructor(contextA);
        safe_call_destructor(contextB);
        return nullptr;
    }

    return new (storage) ComposeShaderContext(*this, rec, contextA, contextB);
}

SkComposeShader::ComposeShaderContext::ComposeShaderContext(
        const SkComposeShader& shader, const ContextRec& rec,
        SkShader::Context* contextA, SkShader::Context* contextB)
    : INHERITED(shader, rec)
    , fShaderContextA(contextA)
    , fShaderContextB(contextB) {}

SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
    fShaderContextA->~Context();
    fShaderContextB->~Context();
}

bool SkComposeShader::asACompose(ComposeRec* rec) const {
    if (rec) {
        rec->fShaderA = fShaderA;
        rec->fShaderB = fShaderB;
        rec->fMode = fMode;
    }
    return true;
}

// larger is better (fewer times we have to loop), but we shouldn't
// take up too much stack-space (each element is 4 bytes)
#define TMP_COLOR_COUNT     64

void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
    SkShader::Context* shaderContextA = fShaderContextA;
    SkShader::Context* shaderContextB = fShaderContextB;
    SkXfermode*        mode = static_cast<const SkComposeShader&>(fShader).fMode;
    unsigned           scale = SkAlpha255To256(this->getPaintAlpha());

#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    // In the Android framework, make compose shader ignore the paint's alpha.
    // This matches the old behavior. FIXME: Can we remove this difference?
    scale = 256;
#endif

    SkPMColor   tmp[TMP_COLOR_COUNT];

    if (nullptr == mode) {   // implied SRC_OVER
        // TODO: when we have a good test-case, should use SkBlitRow::Proc32
        // for these loops
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);

            if (256 == scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkPMSrcOver(tmp[i], result[i]);
                }
            } else {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(SkPMSrcOver(tmp[i], result[i]),
                                            scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    } else {    // use mode for the composition
        do {
            int n = count;
            if (n > TMP_COLOR_COUNT) {
                n = TMP_COLOR_COUNT;
            }

            shaderContextA->shadeSpan(x, y, result, n);
            shaderContextB->shadeSpan(x, y, tmp, n);
            mode->xfer32(result, tmp, n, nullptr);

            if (256 != scale) {
                for (int i = 0; i < n; i++) {
                    result[i] = SkAlphaMulQ(result[i], scale);
                }
            }

            result += n;
            x += n;
            count -= n;
        } while (count > 0);
    }
}

#if SK_SUPPORT_GPU

#include "effects/GrConstColorProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"

/////////////////////////////////////////////////////////////////////

const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* context,
                                                            const SkMatrix& viewM,
                                                            const SkMatrix* localMatrix,
                                                            SkFilterQuality fq) const {
    // Fragment processor will only support SkXfermode::Mode modes currently.
    SkXfermode::Mode mode;
    if (!(SkXfermode::AsMode(fMode, &mode))) {
        return nullptr;
    }

    switch (mode) {
        case SkXfermode::kClear_Mode:
            return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
                                                 GrConstColorProcessor::kIgnore_InputMode);
            break;
        case SkXfermode::kSrc_Mode:
            return fShaderB->asFragmentProcessor(context, viewM, localMatrix, fq);
            break;
        case SkXfermode::kDst_Mode:
            return fShaderA->asFragmentProcessor(context, viewM, localMatrix, fq);
            break;
        default:
            SkAutoTUnref<const GrFragmentProcessor> fpA(fShaderA->asFragmentProcessor(context,
                                                        viewM, localMatrix, fq));
            if (!fpA.get()) {
                return nullptr;
            }
            SkAutoTUnref<const GrFragmentProcessor> fpB(fShaderB->asFragmentProcessor(context,
                                                        viewM, localMatrix, fq));
            if (!fpB.get()) {
                return nullptr;
            }
            return GrXfermodeFragmentProcessor::CreateFromTwoProcessors(fpB, fpA, mode);
    }
}
#endif

#ifndef SK_IGNORE_TO_STRING
void SkComposeShader::toString(SkString* str) const {
    str->append("SkComposeShader: (");

    str->append("ShaderA: ");
    fShaderA->toString(str);
    str->append(" ShaderB: ");
    fShaderB->toString(str);
    if (fMode) {
        str->append(" Xfermode: ");
        fMode->toString(str);
    }

    this->INHERITED::toString(str);

    str->append(")");
}
#endif
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "makestep.h"
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
#include <extensionsystem/pluginmanager.h>

#include <utils/qtcassert.h>
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QCheckBox>
#include <QtGui/QLineEdit>
#include <QtGui/QListWidget>

namespace {
bool debug = false;
}

using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;

MakeStep::MakeStep(CMakeProject *pro)
    : AbstractProcessStep(pro), m_pro(pro)
{
}

MakeStep::~MakeStep()
{
    delete m_buildParser;
    m_buildParser = 0;
}

bool MakeStep::init(const QString &buildConfiguration)
{
    // TODO figure out the correct build parser
    delete m_buildParser;
    m_buildParser = 0;
    QString buildParser = m_pro->buildParser(buildConfiguration);
    QList<ProjectExplorer::IBuildParserFactory *> buildParserFactories =
            ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::IBuildParserFactory>();

    foreach (ProjectExplorer::IBuildParserFactory * factory, buildParserFactories)
        if (factory->canCreate(buildParser)) {
            m_buildParser = factory->create(buildParser);
            break;
        }
    if (m_buildParser) {
        connect(m_buildParser, SIGNAL(addToOutputWindow(const QString &)),
                this, SIGNAL(addToOutputWindow(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(addToTaskWindow(const QString &, int, int, const QString &)),
                this, SLOT(slotAddToTaskWindow(const QString &, int, int, const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(enterDirectory(const QString &)),
                this, SLOT(addDirectory(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(leaveDirectory(const QString &)),
                this, SLOT(removeDirectory(const QString &)),
                Qt::DirectConnection);
    }

    m_openDirectories.clear();
    addDirectory(m_pro->buildDirectory(buildConfiguration));

    setEnabled(buildConfiguration, true);
    setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration));
    setCommand(buildConfiguration, "make"); // TODO give full path here?
    setArguments(buildConfiguration, value(buildConfiguration, "buildTargets").toStringList()); // TODO
    setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration));
    return AbstractProcessStep::init(buildConfiguration);
}

void MakeStep::run(QFutureInterface<bool> &fi)
{
    AbstractProcessStep::run(fi);
}

QString MakeStep::name()
{
    return Constants::MAKESTEP;
}

QString MakeStep::displayName()
{
    return "Make";
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
    return new MakeBuildStepConfigWidget(this);
}

bool MakeStep::immutable() const
{
    return true;
}

void MakeStep::stdOut(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdOutput(line);
    AbstractProcessStep::stdOut(line);
}

void MakeStep::stdError(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdError(line);
    AbstractProcessStep::stdError(line);
}

void MakeStep::slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description)
{
    QString filePath = fn;
    if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
        // We have no save way to decide which file in which subfolder
        // is meant. Therefore we apply following heuristics:
        // 1. Search for unique file in directories currently indicated as open by GNU make
        //    (Enter directory xxx, Leave directory xxx...) + current directory
        // 3. Check if file is unique in whole project
        // 4. Otherwise give up

        filePath = filePath.trimmed();

        QList<QFileInfo> possibleFiles;
        foreach (const QString &dir, m_openDirectories) {
            QFileInfo candidate(dir + QLatin1Char('/') + filePath);
            if (debug)
                qDebug() << "Checking path " << candidate.filePath();
            if (candidate.exists()
                    && !possibleFiles.contains(candidate)) {
                if (debug)
                    qDebug() << candidate.filePath() << "exists!";
                possibleFiles << candidate;
            }
        }
        if (possibleFiles.count() == 0) {
            if (debug)
                qDebug() << "No success. Trying all files in project ...";
            QString fileName = QFileInfo(filePath).fileName();
            foreach (const QString &file, project()->files(ProjectExplorer::Project::AllFiles)) {
                QFileInfo candidate(file);
                if (candidate.fileName() == fileName) {
                    if (debug)
                        qDebug() << "Found " << file;
                    possibleFiles << candidate;
                }
            }
        }
        if (possibleFiles.count() == 1)
            filePath = possibleFiles.first().filePath();
        else
            qWarning() << "Could not find absolute location of file " << filePath;
    }
    emit addToTaskWindow(filePath, type, linenumber, description);
}

void MakeStep::addDirectory(const QString &dir)
{
    if (!m_openDirectories.contains(dir))
        m_openDirectories.insert(dir);
}

void MakeStep::removeDirectory(const QString &dir)
{
    if (m_openDirectories.contains(dir))
        m_openDirectories.remove(dir);
}

CMakeProject *MakeStep::project() const
{
    return m_pro;
}

bool MakeStep::buildsTarget(const QString &buildConfiguration, const QString &target) const
{
    return value(buildConfiguration, "buildTargets").toStringList().contains(target);
}

void MakeStep::setBuildTarget(const QString &buildConfiguration, const QString &target, bool on)
{
    QStringList old = value(buildConfiguration, "buildTargets").toStringList();
    if (on && !old.contains(target))
        setValue(buildConfiguration, "buildTargets", old << target);
    else if(!on && old.contains(target))
        setValue(buildConfiguration, "buildTargets", old.removeOne(target));
}

//
// CMakeBuildStepConfigWidget
//
MakeBuildStepConfigWidget::MakeBuildStepConfigWidget(MakeStep *makeStep)
    : m_makeStep(makeStep)
{
    QFormLayout *fl = new QFormLayout(this);
    setLayout(fl);

    m_targetsList = new QListWidget;
    fl->addRow("Targets:", m_targetsList);

    // TODO update this list also on rescans of the CMakeLists.txt
    CMakeProject *pro = m_makeStep->project();
    foreach(const QString& target, pro->targets()) {
        QListWidgetItem *item = new QListWidgetItem(target, m_targetsList);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
        item->setCheckState(Qt::Unchecked);
    }
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

void MakeBuildStepConfigWidget::itemChanged(QListWidgetItem *item)
{
    m_makeStep->setBuildTarget(m_buildConfiguration, item->text(), item->checkState() & Qt::Checked);
}

QString MakeBuildStepConfigWidget::displayName() const
{
    return "Make";
}

void MakeBuildStepConfigWidget::init(const QString &buildConfiguration)
{
    // TODO

    // disconnect to make the changes to the items
    disconnect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
    m_buildConfiguration = buildConfiguration;
    int count = m_targetsList->count();
    for(int i = 0; i < count; ++i) {
        QListWidgetItem *item = m_targetsList->item(i);
        item->setCheckState(m_makeStep->buildsTarget(buildConfiguration, item->text()) ? Qt::Checked : Qt::Unchecked);
    }
    // and connect again
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

//
// MakeBuildStepFactory
//

bool MakeBuildStepFactory::canCreate(const QString &name) const
{
    return (Constants::MAKESTEP == name);
}

ProjectExplorer::BuildStep *MakeBuildStepFactory::create(ProjectExplorer::Project *project, const QString &name) const
{
    Q_ASSERT(name == Constants::MAKESTEP);
    CMakeProject *pro = qobject_cast<CMakeProject *>(project);
    Q_ASSERT(pro);
    return new MakeStep(pro);
}

QStringList MakeBuildStepFactory::canCreateForProject(ProjectExplorer::Project * /* pro */) const
{
    return QStringList();
}

QString MakeBuildStepFactory::displayNameForName(const QString & /* name */) const
{
    return "Make";
}

<commit_msg>Fixes:    Uninitialized value of m_buildParser<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "makestep.h"
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
#include <extensionsystem/pluginmanager.h>

#include <utils/qtcassert.h>
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QCheckBox>
#include <QtGui/QLineEdit>
#include <QtGui/QListWidget>

namespace {
bool debug = false;
}

using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;

MakeStep::MakeStep(CMakeProject *pro)
    : AbstractProcessStep(pro), m_pro(pro), m_buildParser(0)
{
}

MakeStep::~MakeStep()
{
    delete m_buildParser;
    m_buildParser = 0;
}

bool MakeStep::init(const QString &buildConfiguration)
{
    // TODO figure out the correct build parser
    delete m_buildParser;
    m_buildParser = 0;
    QString buildParser = m_pro->buildParser(buildConfiguration);
    QList<ProjectExplorer::IBuildParserFactory *> buildParserFactories =
            ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::IBuildParserFactory>();

    foreach (ProjectExplorer::IBuildParserFactory * factory, buildParserFactories)
        if (factory->canCreate(buildParser)) {
            m_buildParser = factory->create(buildParser);
            break;
        }
    if (m_buildParser) {
        connect(m_buildParser, SIGNAL(addToOutputWindow(const QString &)),
                this, SIGNAL(addToOutputWindow(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(addToTaskWindow(const QString &, int, int, const QString &)),
                this, SLOT(slotAddToTaskWindow(const QString &, int, int, const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(enterDirectory(const QString &)),
                this, SLOT(addDirectory(const QString &)),
                Qt::DirectConnection);
        connect(m_buildParser, SIGNAL(leaveDirectory(const QString &)),
                this, SLOT(removeDirectory(const QString &)),
                Qt::DirectConnection);
    }

    m_openDirectories.clear();
    addDirectory(m_pro->buildDirectory(buildConfiguration));

    setEnabled(buildConfiguration, true);
    setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration));
    setCommand(buildConfiguration, "make"); // TODO give full path here?
    setArguments(buildConfiguration, value(buildConfiguration, "buildTargets").toStringList()); // TODO
    setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration));
    return AbstractProcessStep::init(buildConfiguration);
}

void MakeStep::run(QFutureInterface<bool> &fi)
{
    AbstractProcessStep::run(fi);
}

QString MakeStep::name()
{
    return Constants::MAKESTEP;
}

QString MakeStep::displayName()
{
    return "Make";
}

ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
{
    return new MakeBuildStepConfigWidget(this);
}

bool MakeStep::immutable() const
{
    return true;
}

void MakeStep::stdOut(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdOutput(line);
    AbstractProcessStep::stdOut(line);
}

void MakeStep::stdError(const QString &line)
{
    if (m_buildParser)
        m_buildParser->stdError(line);
    AbstractProcessStep::stdError(line);
}

void MakeStep::slotAddToTaskWindow(const QString & fn, int type, int linenumber, const QString & description)
{
    QString filePath = fn;
    if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
        // We have no save way to decide which file in which subfolder
        // is meant. Therefore we apply following heuristics:
        // 1. Search for unique file in directories currently indicated as open by GNU make
        //    (Enter directory xxx, Leave directory xxx...) + current directory
        // 3. Check if file is unique in whole project
        // 4. Otherwise give up

        filePath = filePath.trimmed();

        QList<QFileInfo> possibleFiles;
        foreach (const QString &dir, m_openDirectories) {
            QFileInfo candidate(dir + QLatin1Char('/') + filePath);
            if (debug)
                qDebug() << "Checking path " << candidate.filePath();
            if (candidate.exists()
                    && !possibleFiles.contains(candidate)) {
                if (debug)
                    qDebug() << candidate.filePath() << "exists!";
                possibleFiles << candidate;
            }
        }
        if (possibleFiles.count() == 0) {
            if (debug)
                qDebug() << "No success. Trying all files in project ...";
            QString fileName = QFileInfo(filePath).fileName();
            foreach (const QString &file, project()->files(ProjectExplorer::Project::AllFiles)) {
                QFileInfo candidate(file);
                if (candidate.fileName() == fileName) {
                    if (debug)
                        qDebug() << "Found " << file;
                    possibleFiles << candidate;
                }
            }
        }
        if (possibleFiles.count() == 1)
            filePath = possibleFiles.first().filePath();
        else
            qWarning() << "Could not find absolute location of file " << filePath;
    }
    emit addToTaskWindow(filePath, type, linenumber, description);
}

void MakeStep::addDirectory(const QString &dir)
{
    if (!m_openDirectories.contains(dir))
        m_openDirectories.insert(dir);
}

void MakeStep::removeDirectory(const QString &dir)
{
    if (m_openDirectories.contains(dir))
        m_openDirectories.remove(dir);
}

CMakeProject *MakeStep::project() const
{
    return m_pro;
}

bool MakeStep::buildsTarget(const QString &buildConfiguration, const QString &target) const
{
    return value(buildConfiguration, "buildTargets").toStringList().contains(target);
}

void MakeStep::setBuildTarget(const QString &buildConfiguration, const QString &target, bool on)
{
    QStringList old = value(buildConfiguration, "buildTargets").toStringList();
    if (on && !old.contains(target))
        setValue(buildConfiguration, "buildTargets", old << target);
    else if(!on && old.contains(target))
        setValue(buildConfiguration, "buildTargets", old.removeOne(target));
}

//
// CMakeBuildStepConfigWidget
//
MakeBuildStepConfigWidget::MakeBuildStepConfigWidget(MakeStep *makeStep)
    : m_makeStep(makeStep)
{
    QFormLayout *fl = new QFormLayout(this);
    setLayout(fl);

    m_targetsList = new QListWidget;
    fl->addRow("Targets:", m_targetsList);

    // TODO update this list also on rescans of the CMakeLists.txt
    CMakeProject *pro = m_makeStep->project();
    foreach(const QString& target, pro->targets()) {
        QListWidgetItem *item = new QListWidgetItem(target, m_targetsList);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
        item->setCheckState(Qt::Unchecked);
    }
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

void MakeBuildStepConfigWidget::itemChanged(QListWidgetItem *item)
{
    m_makeStep->setBuildTarget(m_buildConfiguration, item->text(), item->checkState() & Qt::Checked);
}

QString MakeBuildStepConfigWidget::displayName() const
{
    return "Make";
}

void MakeBuildStepConfigWidget::init(const QString &buildConfiguration)
{
    // TODO

    // disconnect to make the changes to the items
    disconnect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
    m_buildConfiguration = buildConfiguration;
    int count = m_targetsList->count();
    for(int i = 0; i < count; ++i) {
        QListWidgetItem *item = m_targetsList->item(i);
        item->setCheckState(m_makeStep->buildsTarget(buildConfiguration, item->text()) ? Qt::Checked : Qt::Unchecked);
    }
    // and connect again
    connect(m_targetsList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(itemChanged(QListWidgetItem*)));
}

//
// MakeBuildStepFactory
//

bool MakeBuildStepFactory::canCreate(const QString &name) const
{
    return (Constants::MAKESTEP == name);
}

ProjectExplorer::BuildStep *MakeBuildStepFactory::create(ProjectExplorer::Project *project, const QString &name) const
{
    Q_ASSERT(name == Constants::MAKESTEP);
    CMakeProject *pro = qobject_cast<CMakeProject *>(project);
    Q_ASSERT(pro);
    return new MakeStep(pro);
}

QStringList MakeBuildStepFactory::canCreateForProject(ProjectExplorer::Project * /* pro */) const
{
    return QStringList();
}

QString MakeBuildStepFactory::displayNameForName(const QString & /* name */) const
{
    return "Make";
}

<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "plaingdbadapter.h"

#include "debuggeractions.h"
#include "gdbengine.h"
#include "procinterrupt.h"
#include "debuggerstringutils.h"

#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <coreplugin/icore.h>

#include <QtCore/QFileInfo>
#include <QtCore/QVariant>
#include <QtGui/QMessageBox>

namespace Debugger {
namespace Internal {

#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
#define CB(callback) \
    static_cast<GdbEngine::AdapterCallback>(&PlainGdbAdapter::callback), \
    STRINGIFY(callback)

///////////////////////////////////////////////////////////////////////
//
// PlainGdbAdapter
//
///////////////////////////////////////////////////////////////////////

PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
    : AbstractGdbAdapter(engine, parent)
{
    QTC_ASSERT(state() == DebuggerNotReady, qDebug() << state());
    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
        this, SLOT(handleGdbError(QProcess::ProcessError)));
    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
        this, SIGNAL(readyReadStandardOutput()));
    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
        this, SIGNAL(readyReadStandardError()));
    connect(&m_gdbProc, SIGNAL(started()),
        this, SLOT(handleGdbStarted()));
    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));

    m_stubProc.setMode(Utils::ConsoleProcess::Debug);
#ifdef Q_OS_UNIX
    m_stubProc.setSettings(Core::ICore::instance()->settings());
#endif

    connect(&m_stubProc, SIGNAL(processError(QString)),
        this, SLOT(stubError(QString)));
    connect(&m_stubProc, SIGNAL(processStarted()),
        this, SLOT(stubStarted()));
// FIXME:
//    connect(&m_stubProc, SIGNAL(wrapperStopped()),
//        m_manager, SLOT(exitDebugger()));
}

void PlainGdbAdapter::startAdapter()
{
    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
    setState(AdapterStarting);
    debugMessage(_("TRYING TO START ADAPTER"));

    QStringList gdbArgs;
    gdbArgs.prepend(_("mi"));
    gdbArgs.prepend(_("-i"));

    if (startParameters().useTerminal) {
        m_stubProc.stop(); // We leave the console open, so recycle it now.

        m_stubProc.setWorkingDirectory(startParameters().workingDir);
        m_stubProc.setEnvironment(startParameters().environment);
        if (!m_stubProc.start(startParameters().executable,
                             startParameters().processArgs)) {
            // Error message for user is delivered via a signal.
            emitAdapterStartFailed(QString());
            return;
        }
    } else {
        if (!m_engine->m_outputCollector.listen()) {
            emitAdapterStartFailed(tr("Cannot set up communication with child process: %1")
                    .arg(m_engine->m_outputCollector.errorString()));
            return;
        }
        gdbArgs.prepend(_("--tty=") + m_engine->m_outputCollector.serverName());

        if (!startParameters().workingDir.isEmpty())
            setWorkingDirectory(startParameters().workingDir);
        if (!startParameters().environment.isEmpty())
            setEnvironment(startParameters().environment);
    }

    m_gdbProc.start(theDebuggerStringSetting(GdbLocation), gdbArgs);
}

void PlainGdbAdapter::handleGdbStarted()
{
    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
    setState(AdapterStarted);
    emit adapterStarted();
}

void PlainGdbAdapter::handleGdbError(QProcess::ProcessError error)
{
    debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
    emit adapterCrashed(m_engine->errorMessage(error));
}

void PlainGdbAdapter::prepareInferior()
{
    QTC_ASSERT(state() == AdapterStarted, qDebug() << state());
    setState(InferiorPreparing);
    if (!startParameters().processArgs.isEmpty())
        m_engine->postCommand(_("-exec-arguments ")
            + startParameters().processArgs.join(_(" ")));
    QFileInfo fi(startParameters().executable);
    m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()),
        CB(handleFileExecAndSymbols));
}

void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
    QTC_ASSERT(state() == InferiorPreparing, qDebug() << state());
    if (response.resultClass == GdbResultDone) {
        //m_breakHandler->clearBreakMarkers();
        setState(InferiorPrepared);
        emit inferiorPrepared();
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Starting executable failed:\n") +
            __(response.data.findChild("msg").data());
        setState(InferiorPreparationFailed);
        emit inferiorPreparationFailed(msg);
    }
}

void PlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
{
    QTC_ASSERT(state() == DebuggerNotReady, qDebug() << state());
#if defined(Q_OS_MAC)
    Q_UNUSED(response)
#else
/*
    #ifdef Q_OS_MAC
    m_engine->postCommand(_("sharedlibrary apply-load-rules all"));
    // On MacOS, breaking in at the entry point wreaks havoc.
    m_engine->postCommand(_("tbreak main"));
    m_waitingForFirstBreakpointToBeHit = true;
    m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
    #else
// FIXME:
//    if (!m_dumperInjectionLoad)
//        m_engine->postCommand(_("set auto-solib-add off"));
    m_engine->postCommand(_("info target"), CB(handleInfoTarget));
    #endif
*/
    if (response.resultClass == GdbResultDone) {
        // [some leading stdout here]
        // >&"        Entry point: 0x80831f0  0x08048134 - 0x08048147 is .interp\n"
        // [some trailing stdout here]
        QString msg = _(response.data.findChild("consolestreamoutput").data());
        QRegExp needle(_("\\bEntry point: (0x[0-9a-f]+)\\b"));
        if (needle.indexIn(msg) != -1) {
            //debugMessage(_("STREAM: ") + msg + " " + needle.cap(1));
            m_engine->postCommand(_("tbreak *") + needle.cap(1));
// FIXME:            m_waitingForFirstBreakpointToBeHit = true;
            setState(InferiorRunningRequested);
            m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
        } else {
            debugMessage(_("PARSING START ADDRESS FAILED: ") + msg);
            emit inferiorStartFailed(_("Parsing start address failed"));
        }
    } else if (response.resultClass == GdbResultError) {
        debugMessage(_("FETCHING START ADDRESS FAILED: " + response.toString()));
        emit inferiorStartFailed(_("Fetching start address failed"));
    }
#endif
}

void PlainGdbAdapter::handleExecRun(const GdbResponse &response)
{
    if (response.resultClass == GdbResultRunning) {
        QTC_ASSERT(state() == InferiorRunning, qDebug() << state());
        debugMessage(_("INFERIOR STARTED"));
        showStatusMessage(tr("Inferior started."));
    } else {
        QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
        QTC_ASSERT(response.resultClass == GdbResultError, /**/);
        const QByteArray &msg = response.data.findChild("msg").data();
        //QTC_ASSERT(status() == InferiorRunning, /**/);
        //interruptInferior();
        setState(InferiorStartFailed);
        emit inferiorStartFailed(msg);
    }
}

void PlainGdbAdapter::startInferior()
{
    QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
    setState(InferiorRunningRequested);
    m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
}

void PlainGdbAdapter::interruptInferior()
{
    debugMessage(_("TRYING TO INTERUPT INFERIOR"));
    const qint64 attachedPID = m_engine->inferiorPid();
    if (attachedPID <= 0) {
        debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
        return;
    }

    if (!interruptProcess(attachedPID))
        debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}

void PlainGdbAdapter::shutdown()
{
    debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
    switch (state()) {

    case InferiorRunningRequested:
    case InferiorRunning:
    case InferiorStopping:
    case InferiorStopped:
        setState(InferiorShuttingDown);
        m_engine->postCommand(_("kill"), CB(handleKill));
        return;

    case InferiorShutDown:
        setState(AdapterShuttingDown);
        m_engine->postCommand(_("-gdb-exit"), CB(handleExit));
        return;

/*
    case InferiorShutdownFailed:
        m_gdbProc.terminate();
        // 20s can easily happen when loading webkit debug information
        m_gdbProc.waitForFinished(20000);
        setState(AdapterShuttingDown);
        debugMessage(_("FORCING TERMINATION: %1").arg(state()));
        if (state() != QProcess::NotRunning) {
            debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1")
                .arg(state()));
            m_gdbProc.kill();
        }
        m_engine->postCommand(_("-gdb-exit"), CB(handleExit));
        return;
*/
    default:
        QTC_ASSERT(false, qDebug() << state());
    }
}

void PlainGdbAdapter::handleKill(const GdbResponse &response)
{
    debugMessage(_("PLAIN ADAPTER HANDLE KILL " + response.toString()));
    if (response.resultClass == GdbResultDone) {
        setState(InferiorShutDown);
        emit inferiorShutDown();
        shutdown(); // re-iterate...
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Inferior process could not be stopped:\n") +
            __(response.data.findChild("msg").data());
        setState(InferiorShutdownFailed);
        emit inferiorShutdownFailed(msg);
    }
}

void PlainGdbAdapter::handleExit(const GdbResponse &response)
{
    if (response.resultClass == GdbResultDone) {
        // don't set state here, this will be handled in handleGdbFinished()
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Gdb process could not be stopped:\n") +
            __(response.data.findChild("msg").data());
        emit adapterShutdownFailed(msg);
    }
}

void PlainGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
{
    debugMessage(_("GDB PROCESS FINISHED"));
    emit adapterShutDown();
}

void PlainGdbAdapter::stubStarted()
{
    const qint64 attachedPID = m_stubProc.applicationPID();
    emit inferiorPidChanged(attachedPID);
    m_engine->postCommand(_("attach %1").arg(attachedPID), CB(handleStubAttached));
}

void PlainGdbAdapter::handleStubAttached(const GdbResponse &)
{
    qDebug() << "STUB ATTACHED, FIXME";
    //qq->notifyInferiorStopped();
    //handleAqcuiredInferior();
}

void PlainGdbAdapter::stubError(const QString &msg)
{
    QMessageBox::critical(m_engine->mainWindow(), tr("Debugger Error"), msg);
}

void PlainGdbAdapter::emitAdapterStartFailed(const QString &msg)
{
    //  QMessageBox::critical(mainWindow(), tr("Debugger Startup Failure"),
    //    tr("Cannot start debugger: %1").arg(m_gdbAdapter->errorString()));
    bool blocked = m_stubProc.blockSignals(true);
    m_stubProc.stop();
    m_stubProc.blockSignals(blocked);
    emit adapterStartFailed(msg);
}

} // namespace Internal
} // namespace Debugger
<commit_msg>debugger: escape from an unexpected state<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "plaingdbadapter.h"

#include "debuggeractions.h"
#include "gdbengine.h"
#include "procinterrupt.h"
#include "debuggerstringutils.h"

#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <coreplugin/icore.h>

#include <QtCore/QFileInfo>
#include <QtCore/QVariant>
#include <QtGui/QMessageBox>

namespace Debugger {
namespace Internal {

#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
#define CB(callback) \
    static_cast<GdbEngine::AdapterCallback>(&PlainGdbAdapter::callback), \
    STRINGIFY(callback)

///////////////////////////////////////////////////////////////////////
//
// PlainGdbAdapter
//
///////////////////////////////////////////////////////////////////////

PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
    : AbstractGdbAdapter(engine, parent)
{
    QTC_ASSERT(state() == DebuggerNotReady, qDebug() << state());
    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
        this, SLOT(handleGdbError(QProcess::ProcessError)));
    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
        this, SIGNAL(readyReadStandardOutput()));
    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
        this, SIGNAL(readyReadStandardError()));
    connect(&m_gdbProc, SIGNAL(started()),
        this, SLOT(handleGdbStarted()));
    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));

    m_stubProc.setMode(Utils::ConsoleProcess::Debug);
#ifdef Q_OS_UNIX
    m_stubProc.setSettings(Core::ICore::instance()->settings());
#endif

    connect(&m_stubProc, SIGNAL(processError(QString)),
        this, SLOT(stubError(QString)));
    connect(&m_stubProc, SIGNAL(processStarted()),
        this, SLOT(stubStarted()));
// FIXME:
//    connect(&m_stubProc, SIGNAL(wrapperStopped()),
//        m_manager, SLOT(exitDebugger()));
}

void PlainGdbAdapter::startAdapter()
{
    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
    setState(AdapterStarting);
    debugMessage(_("TRYING TO START ADAPTER"));

    QStringList gdbArgs;
    gdbArgs.prepend(_("mi"));
    gdbArgs.prepend(_("-i"));

    if (startParameters().useTerminal) {
        m_stubProc.stop(); // We leave the console open, so recycle it now.

        m_stubProc.setWorkingDirectory(startParameters().workingDir);
        m_stubProc.setEnvironment(startParameters().environment);
        if (!m_stubProc.start(startParameters().executable,
                             startParameters().processArgs)) {
            // Error message for user is delivered via a signal.
            emitAdapterStartFailed(QString());
            return;
        }
    } else {
        if (!m_engine->m_outputCollector.listen()) {
            emitAdapterStartFailed(tr("Cannot set up communication with child process: %1")
                    .arg(m_engine->m_outputCollector.errorString()));
            return;
        }
        gdbArgs.prepend(_("--tty=") + m_engine->m_outputCollector.serverName());

        if (!startParameters().workingDir.isEmpty())
            setWorkingDirectory(startParameters().workingDir);
        if (!startParameters().environment.isEmpty())
            setEnvironment(startParameters().environment);
    }

    m_gdbProc.start(theDebuggerStringSetting(GdbLocation), gdbArgs);
}

void PlainGdbAdapter::handleGdbStarted()
{
    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
    setState(AdapterStarted);
    emit adapterStarted();
}

void PlainGdbAdapter::handleGdbError(QProcess::ProcessError error)
{
    debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
    emit adapterCrashed(m_engine->errorMessage(error));
}

void PlainGdbAdapter::prepareInferior()
{
    QTC_ASSERT(state() == AdapterStarted, qDebug() << state());
    setState(InferiorPreparing);
    if (!startParameters().processArgs.isEmpty())
        m_engine->postCommand(_("-exec-arguments ")
            + startParameters().processArgs.join(_(" ")));
    QFileInfo fi(startParameters().executable);
    m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fi.absoluteFilePath()),
        CB(handleFileExecAndSymbols));
}

void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
    QTC_ASSERT(state() == InferiorPreparing, qDebug() << state());
    if (response.resultClass == GdbResultDone) {
        //m_breakHandler->clearBreakMarkers();
        setState(InferiorPrepared);
        emit inferiorPrepared();
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Starting executable failed:\n") +
            __(response.data.findChild("msg").data());
        setState(InferiorPreparationFailed);
        emit inferiorPreparationFailed(msg);
    }
}

void PlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
{
    QTC_ASSERT(state() == DebuggerNotReady, qDebug() << state());
#if defined(Q_OS_MAC)
    Q_UNUSED(response)
#else
/*
    #ifdef Q_OS_MAC
    m_engine->postCommand(_("sharedlibrary apply-load-rules all"));
    // On MacOS, breaking in at the entry point wreaks havoc.
    m_engine->postCommand(_("tbreak main"));
    m_waitingForFirstBreakpointToBeHit = true;
    m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
    #else
// FIXME:
//    if (!m_dumperInjectionLoad)
//        m_engine->postCommand(_("set auto-solib-add off"));
    m_engine->postCommand(_("info target"), CB(handleInfoTarget));
    #endif
*/
    if (response.resultClass == GdbResultDone) {
        // [some leading stdout here]
        // >&"        Entry point: 0x80831f0  0x08048134 - 0x08048147 is .interp\n"
        // [some trailing stdout here]
        QString msg = _(response.data.findChild("consolestreamoutput").data());
        QRegExp needle(_("\\bEntry point: (0x[0-9a-f]+)\\b"));
        if (needle.indexIn(msg) != -1) {
            //debugMessage(_("STREAM: ") + msg + " " + needle.cap(1));
            m_engine->postCommand(_("tbreak *") + needle.cap(1));
// FIXME:            m_waitingForFirstBreakpointToBeHit = true;
            setState(InferiorRunningRequested);
            m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
        } else {
            debugMessage(_("PARSING START ADDRESS FAILED: ") + msg);
            emit inferiorStartFailed(_("Parsing start address failed"));
        }
    } else if (response.resultClass == GdbResultError) {
        debugMessage(_("FETCHING START ADDRESS FAILED: " + response.toString()));
        emit inferiorStartFailed(_("Fetching start address failed"));
    }
#endif
}

void PlainGdbAdapter::handleExecRun(const GdbResponse &response)
{
    if (response.resultClass == GdbResultRunning) {
        QTC_ASSERT(state() == InferiorRunning, qDebug() << state());
        debugMessage(_("INFERIOR STARTED"));
        showStatusMessage(tr("Inferior started."));
    } else {
        QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
        QTC_ASSERT(response.resultClass == GdbResultError, /**/);
        const QByteArray &msg = response.data.findChild("msg").data();
        //QTC_ASSERT(status() == InferiorRunning, /**/);
        //interruptInferior();
        setState(InferiorStartFailed);
        emit inferiorStartFailed(msg);
    }
}

void PlainGdbAdapter::startInferior()
{
    QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
    setState(InferiorRunningRequested);
    m_engine->postCommand(_("-exec-run"), CB(handleExecRun));
}

void PlainGdbAdapter::interruptInferior()
{
    debugMessage(_("TRYING TO INTERUPT INFERIOR"));
    const qint64 attachedPID = m_engine->inferiorPid();
    if (attachedPID <= 0) {
        debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
        return;
    }

    if (!interruptProcess(attachedPID))
        debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}

void PlainGdbAdapter::shutdown()
{
    debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
    switch (state()) {

    case InferiorRunningRequested:
    case InferiorRunning:
    case InferiorStopping:
    case InferiorStopped:
        setState(InferiorShuttingDown);
        m_engine->postCommand(_("kill"), CB(handleKill));
        return;

    case InferiorShuttingDown:
        // FIXME: How can we end up here?
        QTC_ASSERT(false, qDebug() << state());
        // Fall through.

    case InferiorShutDown:
        setState(AdapterShuttingDown);
        m_engine->postCommand(_("-gdb-exit"), CB(handleExit));
        return;

/*
    case InferiorShutdownFailed:
        m_gdbProc.terminate();
        // 20s can easily happen when loading webkit debug information
        m_gdbProc.waitForFinished(20000);
        setState(AdapterShuttingDown);
        debugMessage(_("FORCING TERMINATION: %1").arg(state()));
        if (state() != QProcess::NotRunning) {
            debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1")
                .arg(state()));
            m_gdbProc.kill();
        }
        m_engine->postCommand(_("-gdb-exit"), CB(handleExit));
        return;
*/
    default:
        QTC_ASSERT(false, qDebug() << state());
    }
}

void PlainGdbAdapter::handleKill(const GdbResponse &response)
{
    debugMessage(_("PLAIN ADAPTER HANDLE KILL " + response.toString()));
    if (response.resultClass == GdbResultDone) {
        setState(InferiorShutDown);
        emit inferiorShutDown();
        shutdown(); // re-iterate...
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Inferior process could not be stopped:\n") +
            __(response.data.findChild("msg").data());
        setState(InferiorShutdownFailed);
        emit inferiorShutdownFailed(msg);
    }
}

void PlainGdbAdapter::handleExit(const GdbResponse &response)
{
    if (response.resultClass == GdbResultDone) {
        // don't set state here, this will be handled in handleGdbFinished()
    } else if (response.resultClass == GdbResultError) {
        QString msg = tr("Gdb process could not be stopped:\n") +
            __(response.data.findChild("msg").data());
        emit adapterShutdownFailed(msg);
    }
}

void PlainGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
{
    debugMessage(_("GDB PROCESS FINISHED"));
    emit adapterShutDown();
}

void PlainGdbAdapter::stubStarted()
{
    const qint64 attachedPID = m_stubProc.applicationPID();
    emit inferiorPidChanged(attachedPID);
    m_engine->postCommand(_("attach %1").arg(attachedPID), CB(handleStubAttached));
}

void PlainGdbAdapter::handleStubAttached(const GdbResponse &)
{
    qDebug() << "STUB ATTACHED, FIXME";
    //qq->notifyInferiorStopped();
    //handleAqcuiredInferior();
}

void PlainGdbAdapter::stubError(const QString &msg)
{
    QMessageBox::critical(m_engine->mainWindow(), tr("Debugger Error"), msg);
}

void PlainGdbAdapter::emitAdapterStartFailed(const QString &msg)
{
    //  QMessageBox::critical(mainWindow(), tr("Debugger Startup Failure"),
    //    tr("Cannot start debugger: %1").arg(m_gdbAdapter->errorString()));
    bool blocked = m_stubProc.blockSignals(true);
    m_stubProc.stop();
    m_stubProc.blockSignals(blocked);
    emit adapterStartFailed(msg);
}

} // namespace Internal
} // namespace Debugger
<|endoftext|>


<commit_before>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "cesdkhandler.h"

#include <QtCore/QFile>
#include <QtCore/QDebug>
#include <QtCore/QXmlStreamReader>

using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
using ProjectExplorer::Environment;

CeSdkInfo::CeSdkInfo()
    : m_major(0), m_minor(0)
{
}

void CeSdkInfo::addToEnvironment(Environment &env)
{
    qDebug() << "adding " << name() << "to Environment";
    env.set("INCLUDE", m_include);
    env.set("LIB", m_lib);
    env.prependOrSetPath(m_bin);
    qDebug()<<env.toStringList();
}

CeSdkHandler::CeSdkHandler()
{
}

QString CeSdkHandler::platformName(const QString &qtpath)
{
    QString platformName;
    QString CE_SDK;
    QString CE_ARCH;
    QFile f(qtpath);
    if (f.exists() && f.open(QIODevice::ReadOnly)) {
        while (!f.atEnd()) {
            QByteArray line = f.readLine();
            if (line.startsWith("CE_SDK")) {
                int index = line.indexOf('=');
                if (index >= 0) {
                    CE_SDK = line.mid(index + 1).trimmed();
                }
            } else if (line.startsWith("CE_ARCH")) {
                int index = line.indexOf('=');
                if (index >= 0) {
                    CE_ARCH = line.mid(index + 1).trimmed();
                }
            }
            if (!CE_SDK.isEmpty() && !CE_ARCH.isEmpty()) {
                platformName = CE_SDK + " (" + CE_ARCH + ")";
                break;
            }
        }
    }
    return platformName;
}

bool CeSdkHandler::parse(const QString &vsdir)
{
    // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config
    // and scan through all installed sdks...
    m_list.clear();

    VCInstallDir = vsdir + "/VC/";
    VSInstallDir = vsdir;

    QDir vStudioDir(VCInstallDir);
    if (!vStudioDir.cd("vcpackages"))
        return false;

    QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config")));
    qDebug()<<"##";
    if (!configFile.exists() || !configFile.open(QIODevice::ReadOnly))
        return false;

    qDebug()<<"parsing";

    QString currentElement;
    CeSdkInfo currentItem;
    QXmlStreamReader xml(&configFile);
    while (!xml.atEnd()) {
        xml.readNext();
        if (xml.isStartElement()) {
            currentElement = xml.name().toString();
            if (currentElement == QLatin1String("Platform"))
                currentItem = CeSdkInfo();
            else if (currentElement == QLatin1String("Directories")) {
                QXmlStreamAttributes attr = xml.attributes();
                currentItem.m_include = fixPaths(attr.value(QLatin1String("Include")).toString());
                currentItem.m_lib = fixPaths(attr.value(QLatin1String("Library")).toString());
                currentItem.m_bin = fixPaths(attr.value(QLatin1String("Path")).toString());
            }
        } else if (xml.isEndElement()) {
            if (xml.name().toString() == QLatin1String("Platform"))
                m_list.append(currentItem);
        } else if (xml.isCharacters() && !xml.isWhitespace()) {
            if (currentElement == QLatin1String("PlatformName"))
                currentItem.m_name = xml.text().toString();
            else if (currentElement == QLatin1String("OSMajorVersion"))
                currentItem.m_major = xml.text().toString().toInt();
            else if (currentElement == QLatin1String("OSMinorVersion"))
                currentItem.m_minor = xml.text().toString().toInt();
        }
    }

    if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
        qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
        return false;
    }
    return m_list.size() > 0 ? true : false;
}

CeSdkInfo CeSdkHandler::find(const QString &name)
{
    qDebug() << "looking for platform " << name;
    for (QList<CeSdkInfo>::iterator it = m_list.begin(); it != m_list.end(); ++it) {
        qDebug() << "...." << it->name();
        if (it->name() == name)
            return *it;
    }
    return CeSdkInfo();
}
<commit_msg>Compile.<commit_after>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "cesdkhandler.h"

#include <QtCore/QFile>
#include <QtCore/QDebug>
#include <QtCore/QXmlStreamReader>

using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;
using ProjectExplorer::Environment;

CeSdkInfo::CeSdkInfo()
    : m_major(0), m_minor(0)
{
}

void CeSdkInfo::addToEnvironment(Environment &env)
{
    qDebug() << "adding " << name() << "to Environment";
    env.set("INCLUDE", m_include);
    env.set("LIB", m_lib);
    env.prependOrSetPath(m_bin);
    qDebug()<<env.toStringList();
}

CeSdkHandler::CeSdkHandler()
{
}

QString CeSdkHandler::platformName(const QString &qtpath)
{
    QString platformName;
    QString CE_SDK;
    QString CE_ARCH;
    QFile f(qtpath);
    if (f.exists() && f.open(QIODevice::ReadOnly)) {
        while (!f.atEnd()) {
            QByteArray line = f.readLine();
            if (line.startsWith("CE_SDK")) {
                int index = line.indexOf('=');
                if (index >= 0) {
                    CE_SDK = line.mid(index + 1).trimmed();
                }
            } else if (line.startsWith("CE_ARCH")) {
                int index = line.indexOf('=');
                if (index >= 0) {
                    CE_ARCH = line.mid(index + 1).trimmed();
                }
            }
            if (!CE_SDK.isEmpty() && !CE_ARCH.isEmpty()) {
                platformName = CE_SDK + " (" + CE_ARCH + ")";
                break;
            }
        }
    }
    return platformName;
}

bool CeSdkHandler::parse(const QString &vsdir)
{
    // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config
    // and scan through all installed sdks...
    m_list.clear();

    VCInstallDir = vsdir + "/VC/";
    VSInstallDir = vsdir;

    QDir vStudioDir(VCInstallDir);
    if (!vStudioDir.cd("vcpackages"))
        return false;

    QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config")));
    qDebug()<<"##";
    if (!configFile.exists() || !configFile.open(QIODevice::ReadOnly))
        return false;

    qDebug()<<"parsing";

    QString currentElement;
    CeSdkInfo currentItem;
    QXmlStreamReader xml(&configFile);
    while (!xml.atEnd()) {
        xml.readNext();
        if (xml.isStartElement()) {
            currentElement = xml.name().toString();
            if (currentElement == QLatin1String("Platform"))
                currentItem = CeSdkInfo();
            else if (currentElement == QLatin1String("Directories")) {
                QXmlStreamAttributes attr = xml.attributes();
                currentItem.m_include = fixPaths(attr.value(QLatin1String("Include")).toString());
                currentItem.m_lib = fixPaths(attr.value(QLatin1String("Library")).toString());
                currentItem.m_bin = fixPaths(attr.value(QLatin1String("Path")).toString());
            }
        } else if (xml.isEndElement()) {
            if (xml.name().toString() == QLatin1String("Platform"))
                m_list.append(currentItem);
        } else if (xml.isCharacters() && !xml.isWhitespace()) {
            if (currentElement == QLatin1String("PlatformName"))
                currentItem.m_name = xml.text().toString();
            else if (currentElement == QLatin1String("OSMajorVersion"))
                currentItem.m_major = xml.text().toString().toInt();
            else if (currentElement == QLatin1String("OSMinorVersion"))
                currentItem.m_minor = xml.text().toString().toInt();
        }
    }

    if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
        qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
        return false;
    }
    return m_list.size() > 0 ? true : false;
}

CeSdkInfo CeSdkHandler::find(const QString &name)
{
    qDebug() << "looking for platform " << name;
    for (QList<CeSdkInfo>::iterator it = m_list.begin(); it != m_list.end(); ++it) {
        qDebug() << "...." << it->name();
        if (it->name() == name)
            return *it;
    }
    return CeSdkInfo();
}
<|endoftext|>