<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreResourceBackgroundQueue.h"
#include "OgreLogManager.h"
#include "OgreException.h"
#include "OgreResourceGroupManager.h"
#include "OgreResourceManager.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"

namespace Ogre {

	// Note, no locks are required here anymore because all of the parallelisation
	// is now contained in WorkQueue - this class is entirely single-threaded

#define RESOURCE_CHANNEL Root::MAX_USER_WORKQUEUE_CHANNEL + 1

	//------------------------------------------------------------------------
    //-----------------------------------------------------------------------
    template<> ResourceBackgroundQueue* Singleton<ResourceBackgroundQueue>::ms_Singleton = 0;
    ResourceBackgroundQueue* ResourceBackgroundQueue::getSingletonPtr(void)
    {
        return ms_Singleton;
    }
    ResourceBackgroundQueue& ResourceBackgroundQueue::getSingleton(void)
    {
        assert( ms_Singleton );  return ( *ms_Singleton );
    }
    //-----------------------------------------------------------------------
	//------------------------------------------------------------------------
	ResourceBackgroundQueue::ResourceBackgroundQueue()
	{
	}
	//------------------------------------------------------------------------
	ResourceBackgroundQueue::~ResourceBackgroundQueue()
	{
		shutdown();
	}
	//---------------------------------------------------------------------
	void ResourceBackgroundQueue::initialise()
	{
		Root::getSingleton().getWorkQueue()->addResponseHandler(RESOURCE_CHANNEL, this);
		Root::getSingleton().getWorkQueue()->addRequestHandler(RESOURCE_CHANNEL, this);
	}
	//---------------------------------------------------------------------
	void ResourceBackgroundQueue::shutdown()
	{
		Root::getSingleton().getWorkQueue()->removeRequestHandler(RESOURCE_CHANNEL, this);
		Root::getSingleton().getWorkQueue()->removeResponseHandler(RESOURCE_CHANNEL, this);
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::initialiseResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_INITIALISE_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().initialiseResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket
	ResourceBackgroundQueue::initialiseAllResourceGroups(
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_INITIALISE_ALL_GROUPS;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::prepareResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_PREPARE_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().prepareResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::loadResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_LOAD_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().loadResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::prepare(
		const String& resType, const String& name,
		const String& group, bool isManual,
		ManualResourceLoader* loader,
		const NameValuePairList* loadParams,
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_PREPARE_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.groupName = group;
		req.isManual = isManual;
		req.loader = loader;
		req.loadParams = loadParams;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->prepare(name, group, isManual, loader, loadParams);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::load(
		const String& resType, const String& name,
		const String& group, bool isManual,
		ManualResourceLoader* loader,
		const NameValuePairList* loadParams,
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_LOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.groupName = group;
		req.isManual = isManual;
		req.loader = loader;
		req.loadParams = loadParams;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->load(name, group, isManual, loader, loadParams);
		return 0;
#endif
	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unload(
		const String& resType, const String& name, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->unload(name);
		return 0;
#endif

	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unload(
		const String& resType, ResourceHandle handle, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceHandle = handle;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->unload(handle);
		return 0;
#endif

	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unloadResourceGroup(
		const String& name, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().unloadResourceGroup(name);
		return 0;
#endif

	}
	//------------------------------------------------------------------------
	bool ResourceBackgroundQueue::isProcessComplete(
			BackgroundProcessTicket ticket)
	{
		return mOutstandingRequestSet.find(ticket) == mOutstandingRequestSet.end();
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::addRequest(ResourceRequest& req)
	{
		WorkQueue* queue = Root::getSingleton().getWorkQueue();

		Any data(req);

		WorkQueue::RequestID requestID =
			queue->addRequest(RESOURCE_CHANNEL, (uint16)req.type, data);

		mOutstandingRequestSet.insert(requestID);

		return requestID;
	}
	//-----------------------------------------------------------------------
	WorkQueue::Response* ResourceBackgroundQueue::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
	{

		ResourceRequest resreq = any_cast<ResourceRequest>(req->getData());

		ResourceManager* rm = 0;
		Resource* resource = 0;
		try
		{

			switch (resreq.type)
			{
			case RT_INITIALISE_GROUP:
				ResourceGroupManager::getSingleton().initialiseResourceGroup(
					resreq.groupName);
				break;
			case RT_INITIALISE_ALL_GROUPS:
				ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
				break;
			case RT_PREPARE_GROUP:
				ResourceGroupManager::getSingleton().prepareResourceGroup(
					resreq.groupName);
				break;
			case RT_LOAD_GROUP:
	#if OGRE_THREAD_SUPPORT == 2
				ResourceGroupManager::getSingleton().prepareResourceGroup(
					resreq.groupName);
	#else
				ResourceGroupManager::getSingleton().loadResourceGroup(
					resreq.groupName);
	#endif
				break;
			case RT_UNLOAD_GROUP:
				ResourceGroupManager::getSingleton().unloadResourceGroup(
					resreq.groupName);
				break;
			case RT_PREPARE_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
				resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
				break;
			case RT_LOAD_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
	#if OGRE_THREAD_SUPPORT == 2
				resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
	#else
				resource = rm->load(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
	#endif
				break;
			case RT_UNLOAD_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
				if (resreq.resourceName.empty())
					rm->unload(resreq.resourceHandle);
				else
					rm->unload(resreq.resourceName);
				break;
			};
		}
		catch (Exception& e)
		{
			resreq.result.error = true;
			resreq.result.message = e.getFullDescription();

			// return error response
			ResourceResponse resresp(resource, resreq);
			return OGRE_NEW WorkQueue::Response(req, false, Any(resresp), e.getFullDescription());
		}

		// success
		resreq.result.error = false;
		ResourceResponse resresp(resource, resreq);
		return OGRE_NEW WorkQueue::Response(req, true, Any(resresp));

	}
	//------------------------------------------------------------------------
	void ResourceBackgroundQueue::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
	{
		if (res->succeeded())
		{
			ResourceResponse resresp = any_cast<ResourceResponse>(res->getData());

			// Complete full loading in main thread if semithreading
			const ResourceRequest& req = resresp.request;
#if OGRE_THREAD_SUPPORT == 2
			// These load commands would have been downgraded to prepare() for the background
			if (req.type == RT_LOAD_RESOURCE)
			{
				ResourceManager *rm = ResourceGroupManager::getSingleton()
					._getResourceManager(req.resourceType);
				rm->load(req.resourceName, req.groupName, req.isManual, req.loader, req.loadParams);
			}
			else if (req.type == RT_LOAD_GROUP)
			{
				ResourceGroupManager::getSingleton().loadResourceGroup(req.groupName);
			}
#endif

			// Call resource listener
			if (resresp.resource)
			{

				if (req.type == RT_LOAD_RESOURCE)
				{
					resresp.resource->_fireLoadingComplete();
				}
				else
				{
					resresp.resource->_firePreparingComplete();
				}
			}

			// Call queue listener
			if (req.listener)
				req.listener->operationCompleted(res->getRequest()->getID(), req.result);

		}
	}
	//------------------------------------------------------------------------

}

<commit_msg>Patch 2853328: make sure we remove the request from the outstanding list<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreResourceBackgroundQueue.h"
#include "OgreLogManager.h"
#include "OgreException.h"
#include "OgreResourceGroupManager.h"
#include "OgreResourceManager.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"

namespace Ogre {

	// Note, no locks are required here anymore because all of the parallelisation
	// is now contained in WorkQueue - this class is entirely single-threaded

#define RESOURCE_CHANNEL Root::MAX_USER_WORKQUEUE_CHANNEL + 1

	//------------------------------------------------------------------------
    //-----------------------------------------------------------------------
    template<> ResourceBackgroundQueue* Singleton<ResourceBackgroundQueue>::ms_Singleton = 0;
    ResourceBackgroundQueue* ResourceBackgroundQueue::getSingletonPtr(void)
    {
        return ms_Singleton;
    }
    ResourceBackgroundQueue& ResourceBackgroundQueue::getSingleton(void)
    {
        assert( ms_Singleton );  return ( *ms_Singleton );
    }
    //-----------------------------------------------------------------------
	//------------------------------------------------------------------------
	ResourceBackgroundQueue::ResourceBackgroundQueue()
	{
	}
	//------------------------------------------------------------------------
	ResourceBackgroundQueue::~ResourceBackgroundQueue()
	{
		shutdown();
	}
	//---------------------------------------------------------------------
	void ResourceBackgroundQueue::initialise()
	{
		Root::getSingleton().getWorkQueue()->addResponseHandler(RESOURCE_CHANNEL, this);
		Root::getSingleton().getWorkQueue()->addRequestHandler(RESOURCE_CHANNEL, this);
	}
	//---------------------------------------------------------------------
	void ResourceBackgroundQueue::shutdown()
	{
		Root::getSingleton().getWorkQueue()->removeRequestHandler(RESOURCE_CHANNEL, this);
		Root::getSingleton().getWorkQueue()->removeResponseHandler(RESOURCE_CHANNEL, this);
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::initialiseResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_INITIALISE_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().initialiseResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket
	ResourceBackgroundQueue::initialiseAllResourceGroups(
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_INITIALISE_ALL_GROUPS;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::prepareResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_PREPARE_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().prepareResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::loadResourceGroup(
		const String& name, ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_LOAD_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().loadResourceGroup(name);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::prepare(
		const String& resType, const String& name,
		const String& group, bool isManual,
		ManualResourceLoader* loader,
		const NameValuePairList* loadParams,
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_PREPARE_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.groupName = group;
		req.isManual = isManual;
		req.loader = loader;
		req.loadParams = loadParams;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->prepare(name, group, isManual, loader, loadParams);
		return 0;
#endif
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::load(
		const String& resType, const String& name,
		const String& group, bool isManual,
		ManualResourceLoader* loader,
		const NameValuePairList* loadParams,
		ResourceBackgroundQueue::Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_LOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.groupName = group;
		req.isManual = isManual;
		req.loader = loader;
		req.loadParams = loadParams;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->load(name, group, isManual, loader, loadParams);
		return 0;
#endif
	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unload(
		const String& resType, const String& name, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->unload(name);
		return 0;
#endif

	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unload(
		const String& resType, ResourceHandle handle, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_RESOURCE;
		req.resourceType = resType;
		req.resourceHandle = handle;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceManager* rm =
			ResourceGroupManager::getSingleton()._getResourceManager(resType);
		rm->unload(handle);
		return 0;
#endif

	}
	//---------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::unloadResourceGroup(
		const String& name, Listener* listener)
	{
#if OGRE_THREAD_SUPPORT
		// queue a request
		ResourceRequest req;
		req.type = RT_UNLOAD_GROUP;
		req.groupName = name;
		req.listener = listener;
		return addRequest(req);
#else
		// synchronous
		ResourceGroupManager::getSingleton().unloadResourceGroup(name);
		return 0;
#endif

	}
	//------------------------------------------------------------------------
	bool ResourceBackgroundQueue::isProcessComplete(
			BackgroundProcessTicket ticket)
	{
		return mOutstandingRequestSet.find(ticket) == mOutstandingRequestSet.end();
	}
	//------------------------------------------------------------------------
	BackgroundProcessTicket ResourceBackgroundQueue::addRequest(ResourceRequest& req)
	{
		WorkQueue* queue = Root::getSingleton().getWorkQueue();

		Any data(req);

		WorkQueue::RequestID requestID =
			queue->addRequest(RESOURCE_CHANNEL, (uint16)req.type, data);

		mOutstandingRequestSet.insert(requestID);

		return requestID;
	}
	//-----------------------------------------------------------------------
	WorkQueue::Response* ResourceBackgroundQueue::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
	{

		ResourceRequest resreq = any_cast<ResourceRequest>(req->getData());

		ResourceManager* rm = 0;
		Resource* resource = 0;
		try
		{

			switch (resreq.type)
			{
			case RT_INITIALISE_GROUP:
				ResourceGroupManager::getSingleton().initialiseResourceGroup(
					resreq.groupName);
				break;
			case RT_INITIALISE_ALL_GROUPS:
				ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
				break;
			case RT_PREPARE_GROUP:
				ResourceGroupManager::getSingleton().prepareResourceGroup(
					resreq.groupName);
				break;
			case RT_LOAD_GROUP:
	#if OGRE_THREAD_SUPPORT == 2
				ResourceGroupManager::getSingleton().prepareResourceGroup(
					resreq.groupName);
	#else
				ResourceGroupManager::getSingleton().loadResourceGroup(
					resreq.groupName);
	#endif
				break;
			case RT_UNLOAD_GROUP:
				ResourceGroupManager::getSingleton().unloadResourceGroup(
					resreq.groupName);
				break;
			case RT_PREPARE_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
				resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
				break;
			case RT_LOAD_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
	#if OGRE_THREAD_SUPPORT == 2
				resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
	#else
				resource = rm->load(resreq.resourceName, resreq.groupName, resreq.isManual,
					resreq.loader, resreq.loadParams).get();
	#endif
				break;
			case RT_UNLOAD_RESOURCE:
				rm = ResourceGroupManager::getSingleton()._getResourceManager(
					resreq.resourceType);
				if (resreq.resourceName.empty())
					rm->unload(resreq.resourceHandle);
				else
					rm->unload(resreq.resourceName);
				break;
			};
		}
		catch (Exception& e)
		{
			resreq.result.error = true;
			resreq.result.message = e.getFullDescription();

			// return error response
			ResourceResponse resresp(resource, resreq);
			return OGRE_NEW WorkQueue::Response(req, false, Any(resresp), e.getFullDescription());
		}

		// success
		resreq.result.error = false;
		ResourceResponse resresp(resource, resreq);
		return OGRE_NEW WorkQueue::Response(req, true, Any(resresp));

	}
	//------------------------------------------------------------------------
	void ResourceBackgroundQueue::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
	{
		if (res->succeeded())
		{
			ResourceResponse resresp = any_cast<ResourceResponse>(res->getData());

			// Complete full loading in main thread if semithreading
			const ResourceRequest& req = resresp.request;
#if OGRE_THREAD_SUPPORT == 2
			// These load commands would have been downgraded to prepare() for the background
			if (req.type == RT_LOAD_RESOURCE)
			{
				ResourceManager *rm = ResourceGroupManager::getSingleton()
					._getResourceManager(req.resourceType);
				rm->load(req.resourceName, req.groupName, req.isManual, req.loader, req.loadParams);
			}
			else if (req.type == RT_LOAD_GROUP)
			{
				ResourceGroupManager::getSingleton().loadResourceGroup(req.groupName);
			}
#endif
			mOutstandingRequestSet.erase(res->getRequest()->getID());

			// Call resource listener
			if (resresp.resource)
			{

				if (req.type == RT_LOAD_RESOURCE)
				{
					resresp.resource->_fireLoadingComplete();
				}
				else
				{
					resresp.resource->_firePreparingComplete();
				}
			}

			// Call queue listener
			if (req.listener)
				req.listener->operationCompleted(res->getRequest()->getID(), req.result);

		}
	}
	//------------------------------------------------------------------------

}

<|endoftext|>


<commit_before>#include "KAI/KAI.h"

#include <iostream>
#include <strstream>
#include <stdarg.h>

#include "KAI/Translator/Lexer.h"

using namespace std;

KAI_BEGIN

Lexer::Lexer(const char *in)
	: input(in)
{
	CreateLines();
	AddKeywords();
	Run();
}

void Lexer::AddKeywords()
{
	keyWords["if"] = Token::If;
	keyWords["else"] = Token::Else;
	keyWords["for"] = Token::For;
	keyWords["true"] = Token::True;
	keyWords["false"] = Token::False;
	keyWords["return"] = Token::Return;
	keyWords["self"] = Token::Self;
	keyWords["fun"] = Token::Fun;
	keyWords["yield"] = Token::Yield;
	keyWords["in"] = Token::In;
	keyWords["while"] = Token::While;
	keyWords["assert"] = Token::Assert;
}

bool Lexer::Run()
{
	offset = 0;
	lineNumber = 0;

	while (!Failed && NextToken())
		;

	return Add(Token::None, 0);
}

void Lexer::Print() const
{
	//std::copy(tokens.begin(), tokens.end(), ostream_iterator<Token>(std::cout, " "));
	for (auto tok : tokens)
		std::cout << tok << " ";

	std::cout << std::endl;
}

Slice Lexer::Gather(int (*filt)(int))
{
	int start = offset;
	while (filt(Next()))
		;

	return Slice(start, offset);
}

bool Lexer::Add(Token::Type type, Slice slice)
{
	tokens.push_back(Token(type, *this, lineNumber, slice));
	return true;
}

bool Lexer::Add(Token::Type type, int len)
{
	Add(type, Slice(offset, offset + len));
	while (len--)
		Next();

	return true;
}

bool Lexer::LexAlpha()
{
	Token tok(Token::Ident, *this, lineNumber, Gather(isalnum));

	auto kw = keyWords.find(tok.Text());
	if (kw != keyWords.end())
		tok.type = kw->second;

	tokens.push_back(tok);

	return true;
}

int IsSpaceChar(int ch)
{
	return ch == ' ';
}

bool Lexer::NextToken()
{
	auto current = Current();
	if (current == 0)
		return false;

	if (isalpha(current))
		return LexAlpha();

	if (isdigit(current))
		return Add(Token::Int, Gather(isdigit));

	switch (current)
	{
	case '\t': return Add(Token::Tab);
	case '\n': return Add(Token::NewLine);
	case ';': return Add(Token::Semi);
	case '{': return Add(Token::OpenBrace);
	case '}': return Add(Token::CloseBrace);
	case '(': return Add(Token::OpenParan);
	case ')': return Add(Token::CloseParan);
	case ':': return Add(Token::Colon);
	case ' ': return Add(Token::Whitespace, Gather(IsSpaceChar));
	case '@': return Add(Token::Lookup);
	case ',': return Add(Token::Comma);
	case '*': return Add(Token::Mul);
	case '[': return Add(Token::OpenSquareBracket);
	case ']': return Add(Token::CloseSquareBracket);
	case '=': return AddIfNext('=', Token::Equiv, Token::Assign);
	case '!': return AddIfNext('=', Token::NotEquiv, Token::Not);
	case '&': return AddIfNext('&', Token::And, Token::BitAnd);
	case '|': return AddIfNext('|', Token::Or, Token::BitOr);
	case '<': return AddIfNext('=', Token::LessEquiv, Token::Less);
	case '>': return AddIfNext('=', Token::GreaterEquiv, Token::Greater);
	case '"': return LexString();
	case '\'': return LexAlpha();
	case '-':
		if (Peek() == '-')
			return AddTwoCharOp(Token::Decrement);
		if (Peek() == '=')
			return AddTwoCharOp(Token::MinusAssign);
		return Add(Token::Minus);

	case '.':
		if (Peek() == '.')
		{
			Next();
			if (Peek() == '.')
			{
				Next();
				return Add(Token::Replace, 3);
			}
			return Fail("Two dots doesn't work");
		}
		return Add(Token::Dot);

	case '+':
		if (Peek() == '+')
			return AddTwoCharOp(Token::Increment);
		if (Peek() == '=')
			return AddTwoCharOp(Token::PlusAssign);
		return Add(Token::Plus);

	case '/':
		if (Peek() == '/')
		{
			Next();
			int start = offset;
			while (Next() != '\n')
				;
			return Add(Token::Comment, offset - start);
		}
		return Add(Token::Divide);
	}

	LexError("Unrecognised %c");

	return false;
}

bool Process::Fail(const std::string &err)
{
	Failed = true;
	Error = err;

	return false;
}

bool Process::Fail(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	char buffer[1000];
	vsprintf_s(buffer, fmt, ap);

	return Fail(std::string(buffer));
}

char Lexer::Current() const
{
	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

const std::string &Lexer::Line() const
{
	return lines[lineNumber];
}

char Lexer::Next()
{
	if (EndOfLine())
	{
		offset = 0;
		++lineNumber;
	}
	else
		++offset;

	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

char Lexer::Peek() const
{
	if (EndOfLine())
		return 0;

	return Line()[offset + 1];
}

void Lexer::CreateLines()
{
	// ensure we end with a newline.
	input.push_back('\n');

	size_t lineStart = 0;
	for (size_t n = 0; n < input.size(); ++n)
	{
		if (input[n] == '\n')
		{
			lines.push_back(input.substr(lineStart, n - lineStart + 1));
			lineStart = n + 1;
		}
	}
}

bool Lexer::EndOfLine() const
{
	return offset == (int)Line().size() - 1;
}

bool Lexer::AddIfNext(char ch, Token::Type thenType, Token::Type elseType)
{
	if (Peek() == ch)
	{
		Next();
		return Add(thenType, 2);
	}

	return Add(elseType, 1);
}

bool Lexer::AddTwoCharOp(Token::Type ty)
{
	Add(ty, 2);
	Next();

	return true;
}

bool Lexer::LexString()
{
	int start = offset;
	Next();
	while (!Failed && Current() != '"')
	{
		if (Current() == '\\')
		{
			switch (Next())
			{
			case '"':
			case 'n':
			case 't':
				break;

			default:
				LexError("Bad escape sequence %c");
				return false;
			}
		}

		if (Peek() == 0)
		{
			Fail("Bad string literal");
			return false;
		}

		Next();
	}

	Next();

	// the +1 and -1 to remove the start and end double quote characters
	tokens.push_back(Token(Token::String, *this, lineNumber, Slice(start + 1, offset - 1)));
	return true;
}

void Lexer::LexError(const char *text)
{
	Fail(CreateError(Token(Token::None, *this, lineNumber, Slice(offset, offset)), text, Current()));
}

std::string Lexer::CreateError(Token tok, const char *fmt, ...)
{
	char buff0[2000];
	va_list ap;
	va_start(ap, fmt);
	vsprintf_s(buff0, fmt, ap);

	const char *fmt1 = "%s(%d):[%d]: %s\n";
	char buff[2000];
	sprintf_s(buff, fmt1, "", tok.lineNumber, tok.slice.Start, buff0);
	int beforeContext = 1;
	int afterContext = 0;

	const Lexer &lex = *tok.lexer;
	int start = std::max(0, tok.lineNumber - beforeContext);
	int end = std::min((int)lex.lines.size() - 1, tok.lineNumber + afterContext);

	strstream err;
	err << buff << endl;
	for (int n = start; n <= end; ++n)
	{
		for (auto ch : lex.lines[n])
		{
			if (ch == '\t')
				err << "    ";
			else
				err << ch;
		}

		if (n == tok.lineNumber)
		{
			for (int ch = 0; ch < (int)lex.lines[n].size(); ++ch)
			{
				if (lex.lines[tok.lineNumber][ch] == '\t')
					err << "    ";
				else if (ch == tok.slice.Start)
				{
					err << '^';
					break;
				}
			}

			err << endl;
		}
	}

	err << ends;

	return err.str();
}

KAI_END

<commit_msg>Re-ordered methods.<commit_after>#include "KAI/KAI.h"

#include <iostream>
#include <strstream>
#include <stdarg.h>

#include "KAI/Translator/Lexer.h"

using namespace std;

KAI_BEGIN

Lexer::Lexer(const char *in)
	: input(in)
{
	CreateLines();
	AddKeywords();
	Run();
}

void Lexer::CreateLines()
{
	if (input.back() != '\n')
		input.push_back('\n');

	size_t lineStart = 0;
	for (size_t n = 0; n < input.size(); ++n)
	{
		if (input[n] == '\n')
		{
			lines.push_back(input.substr(lineStart, n - lineStart + 1));
			lineStart = n + 1;
		}
	}
}

void Lexer::AddKeywords()
{
	keyWords["if"] = Token::If;
	keyWords["else"] = Token::Else;
	keyWords["for"] = Token::For;
	keyWords["true"] = Token::True;
	keyWords["false"] = Token::False;
	keyWords["return"] = Token::Return;
	keyWords["self"] = Token::Self;
	keyWords["fun"] = Token::Fun;
	keyWords["yield"] = Token::Yield;
	keyWords["in"] = Token::In;
	keyWords["while"] = Token::While;
	keyWords["assert"] = Token::Assert;
}

bool Lexer::Run()
{
	offset = 0;
	lineNumber = 0;

	while (!Failed && NextToken())
		;

	return Add(Token::None, 0);
}

bool Lexer::NextToken()
{
	auto current = Current();
	if (current == 0)
		return false;

	if (isalpha(current))
		return LexAlpha();

	if (isdigit(current))
		return Add(Token::Int, Gather(isdigit));

	switch (current)
	{
	case '\t': return Add(Token::Tab);
	case '\n': return Add(Token::NewLine);
	case ';': return Add(Token::Semi);
	case '{': return Add(Token::OpenBrace);
	case '}': return Add(Token::CloseBrace);
	case '(': return Add(Token::OpenParan);
	case ')': return Add(Token::CloseParan);
	case ':': return Add(Token::Colon);
	case ' ': return Add(Token::Whitespace, Gather(IsSpaceChar));
	case '@': return Add(Token::Lookup);
	case ',': return Add(Token::Comma);
	case '*': return Add(Token::Mul);
	case '[': return Add(Token::OpenSquareBracket);
	case ']': return Add(Token::CloseSquareBracket);
	case '=': return AddIfNext('=', Token::Equiv, Token::Assign);
	case '!': return AddIfNext('=', Token::NotEquiv, Token::Not);
	case '&': return AddIfNext('&', Token::And, Token::BitAnd);
	case '|': return AddIfNext('|', Token::Or, Token::BitOr);
	case '<': return AddIfNext('=', Token::LessEquiv, Token::Less);
	case '>': return AddIfNext('=', Token::GreaterEquiv, Token::Greater);
	case '"': return LexString();
	case '\'': return LexAlpha();
	case '-':
		if (Peek() == '-')
			return AddTwoCharOp(Token::Decrement);
		if (Peek() == '=')
			return AddTwoCharOp(Token::MinusAssign);
		return Add(Token::Minus);

	case '.':
		if (Peek() == '.')
		{
			Next();
			if (Peek() == '.')
			{
				Next();
				return Add(Token::Replace, 3);
			}
			return Fail("Two dots doesn't work");
		}
		return Add(Token::Dot);

	case '+':
		if (Peek() == '+')
			return AddTwoCharOp(Token::Increment);
		if (Peek() == '=')
			return AddTwoCharOp(Token::PlusAssign);
		return Add(Token::Plus);

	case '/':
		if (Peek() == '/')
		{
			Next();
			int start = offset;
			while (Next() != '\n')
				;
			return Add(Token::Comment, offset - start);
		}
		return Add(Token::Divide);
	}

	LexError("Unrecognised %c");

	return false;
}

Slice Lexer::Gather(int (*filt)(int))
{
	int start = offset;
	while (filt(Next()))
		;

	return Slice(start, offset);
}

bool Lexer::Add(Token::Type type, Slice slice)
{
	tokens.push_back(Token(type, *this, lineNumber, slice));
	return true;
}

bool Lexer::Add(Token::Type type, int len)
{
	Add(type, Slice(offset, offset + len));
	while (len--)
		Next();

	return true;
}

bool Lexer::LexAlpha()
{
	Token tok(Token::Ident, *this, lineNumber, Gather(isalnum));

	auto kw = keyWords.find(tok.Text());
	if (kw != keyWords.end())
		tok.type = kw->second;

	tokens.push_back(tok);

	return true;
}

int IsSpaceChar(int ch)
{
	return ch == ' ';
}

bool Process::Fail(const std::string &err)
{
	Failed = true;
	Error = err;

	return false;
}

bool Process::Fail(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	char buffer[1000];
	vsprintf_s(buffer, fmt, ap);

	return Fail(std::string(buffer));
}

char Lexer::Current() const
{
	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

const std::string &Lexer::Line() const
{
	return lines[lineNumber];
}

char Lexer::Next()
{
	if (EndOfLine())
	{
		offset = 0;
		++lineNumber;
	}
	else
		++offset;

	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

char Lexer::Peek() const
{
	if (EndOfLine())
		return 0;

	return Line()[offset + 1];
}

bool Lexer::EndOfLine() const
{
	return offset == (int)Line().size() - 1;
}

bool Lexer::AddIfNext(char ch, Token::Type thenType, Token::Type elseType)
{
	if (Peek() == ch)
	{
		Next();
		return Add(thenType, 2);
	}

	return Add(elseType, 1);
}

bool Lexer::AddTwoCharOp(Token::Type ty)
{
	Add(ty, 2);
	Next();

	return true;
}

bool Lexer::LexString()
{
	int start = offset;
	Next();
	while (!Failed && Current() != '"')
	{
		if (Current() == '\\')
		{
			switch (Next())
			{
			case '"':
			case 'n':
			case 't':
				break;

			default:
				LexError("Bad escape sequence %c");
				return false;
			}
		}

		if (Peek() == 0)
		{
			Fail("Bad string literal");
			return false;
		}

		Next();
	}

	Next();

	// the +1 and -1 to remove the start and end double quote characters
	tokens.push_back(Token(Token::String, *this, lineNumber, Slice(start + 1, offset - 1)));
	return true;
}

void Lexer::LexError(const char *text)
{
	Fail(CreateError(Token(Token::None, *this, lineNumber, Slice(offset, offset)), text, Current()));
}

std::string Lexer::CreateError(Token tok, const char *fmt, ...)
{
	char buff0[2000];
	va_list ap;
	va_start(ap, fmt);
	vsprintf_s(buff0, fmt, ap);

	const char *fmt1 = "%s(%d):[%d]: %s\n";
	char buff[2000];
	sprintf_s(buff, fmt1, "", tok.lineNumber, tok.slice.Start, buff0);
	int beforeContext = 1;
	int afterContext = 0;

	const Lexer &lex = *tok.lexer;
	int start = std::max(0, tok.lineNumber - beforeContext);
	int end = std::min((int)lex.lines.size() - 1, tok.lineNumber + afterContext);

	strstream err;
	err << buff << endl;
	for (int n = start; n <= end; ++n)
	{
		for (auto ch : lex.lines[n])
		{
			if (ch == '\t')
				err << "    ";
			else
				err << ch;
		}

		if (n == tok.lineNumber)
		{
			for (int ch = 0; ch < (int)lex.lines[n].size(); ++ch)
			{
				if (lex.lines[tok.lineNumber][ch] == '\t')
					err << "    ";
				else if (ch == tok.slice.Start)
				{
					err << '^';
					break;
				}
			}

			err << endl;
		}
	}

	err << ends;

	return err.str();
}

void Lexer::Print() const
{
	for (auto tok : tokens)
		std::cout << tok << " ";

	std::cout << std::endl;
}

KAI_END

<|endoftext|>


<commit_before>/*
 * THE UNICODE TEST SUITE FOR CINDER: https://github.com/arielm/Unicode
 * COPYRIGHT (C) 2013, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE MODIFIED BSD LICENSE:
 * https://github.com/arielm/Unicode/blob/master/LICENSE.md
 */

/*
 * TESTING SHAPING FALLBACK, AS TAKING PLACE IN:
 * https://github.com/mapnik/mapnik/blob/64d5153aeaeb1c9e736bfead297dfea39b066d2c/include/mapnik/text/harfbuzz_shaper.hpp
 *
 *
 * DroidSansHebrew-Regular.ttf IS ONLY CONTAINING HEBREW CHARACTERS AND DIACRITICS
 * THEREFORE, WE RELY ON DroidSans.ttf FOR ANYTHING ELSE
 *
 *
 * UPDATE:
 * - SOME PROGRESS WITH CLUSTERS AND DIACRITICS, BUT STILL NOT THERE
 *   - std::multimap IS NOT THE RIGHT CONTAINER:
 *     DIACRITICS ARE PLACE AFTER THE LETTER,
 *     WHICH IS PROBLEMATIC WITH THE CURRENT ADVANCEMENT METHOD
 */

#include "cinder/app/AppNative.h"

#include "YFont.h"

using namespace std;
using namespace ci;
using namespace app;

const float FONT_SIZE = 56;

class Application : public AppNative
{
    shared_ptr<FreetypeHelper> ftHelper; // THE UNDERLYING FT_Library WILL BE DESTROYED AFTER ALL THE YFont INSTANCES

    shared_ptr<YFont> font1;
    shared_ptr<YFont> font2;

public:
    void prepareSettings(Settings *settings);
    void setup();

    void draw();
    void drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float y);
    void drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float x, float y);
    void drawHLine(float y);
};

void Application::prepareSettings(Settings *settings)
{
    settings->setWindowSize(1024, 512);
}

void Application::setup()
{
    ftHelper = make_shared<FreetypeHelper>();

    font1 = make_shared<YFont>(ftHelper, FontDescriptor(loadAsset("fonts/DroidSansHebrew-Regular.ttf")), FONT_SIZE, ColorA(1, 1, 1, 1));
    font2 = make_shared<YFont>(ftHelper, FontDescriptor(loadAsset("fonts/DroidSans.ttf")), FONT_SIZE, ColorA(1, 1, 0.5f, 1));

    // ---

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

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
}

void Application::draw()
{
    gl::clear(Color::gray(0.5f), false);
    gl::setMatricesWindow(toPixels(getWindowSize()), true);

    drawSpan(*font1, *font2, TextSpan("וְהָהַר, מַהוּ לַזֵּה? – זֹאת הִיא הַשְּׁאֵלָה.", HB_SCRIPT_HEBREW, HB_DIRECTION_RTL, "he"), 256);
}

void Application::drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float y)
{
    drawSpan(font1, font2, span, 24, y);

    glColor4f(1, 0.75f, 0, 0.5f);
    drawHLine(y);
}

void Application::drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float x, float y)
{
    const char *shapers[]  = { "ot", "fallback", NULL };
    hb_buffer_t *buffer = hb_buffer_create();

    multimap<uint32_t, Shape> shapes;

    /*
     * FIRST PASS
     */

    span.apply(buffer);
    hb_shape_full(font1.hbFont, buffer, NULL, 0, shapers);

    auto glyphCount = hb_buffer_get_length(buffer);
    auto glyph_info = hb_buffer_get_glyph_infos(buffer, nullptr);
    auto glyph_pos = hb_buffer_get_glyph_positions(buffer, nullptr);

    for (int i = 0; i < glyphCount; i++)
    {
        auto codepoint = glyph_info[i].codepoint;
        Vec2f offset(glyph_pos[i].x_offset, -glyph_pos[i].y_offset);
        float advance = glyph_pos[i].x_advance;

        if (codepoint)
        {
            shapes.emplace(glyph_info[i].cluster, Shape(&font1, codepoint, offset, advance));
        }

//      cout << codepoint << " | " << glyph_info[i].cluster << " | " << advance * font1.scale.x << endl;
    }
//  cout << endl;

    hb_buffer_clear_contents(buffer);

    /*
     * SECOND PASS
     */

    span.apply(buffer);
    hb_shape_full(font2.hbFont, buffer, NULL, 0, shapers);

    glyphCount = hb_buffer_get_length(buffer);
    glyph_info = hb_buffer_get_glyph_infos(buffer, nullptr);
    glyph_pos = hb_buffer_get_glyph_positions(buffer, nullptr);

    for (int i = 0; i < glyphCount; i++)
    {
        auto codepoint = glyph_info[i].codepoint;
        Vec2f offset(glyph_pos[i].x_offset, -glyph_pos[i].y_offset);
        float advance = glyph_pos[i].x_advance;

        if (codepoint)
        {
            shapes.emplace(glyph_info[i].cluster, Shape(&font2, codepoint, offset, advance));
        }

//      cout << codepoint << " | " << glyph_info[i].cluster << " | " << advance * font2.scale.x << endl;
    }
//  cout << endl;

    hb_buffer_destroy(buffer);

    // ---

    glPushMatrix();
    glTranslatef(x, y, 0);

    for (auto it = shapes.rbegin(); it != shapes.rend(); ++it)
    {
        float advance = it->second.draw();
        glTranslatef(advance, 0, 0);
    }

    glPopMatrix();
}

void Application::drawHLine(float y)
{
    gl::drawLine(Vec2f(-9999, y), Vec2f(+9999, y));
}

CINDER_APP_NATIVE(Application, RendererGl(RendererGl::AA_NONE))
<commit_msg>ShapingFallback: SEEMS TO WORK AS INTENDED NOW<commit_after>/*
 * THE UNICODE TEST SUITE FOR CINDER: https://github.com/arielm/Unicode
 * COPYRIGHT (C) 2013, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE MODIFIED BSD LICENSE:
 * https://github.com/arielm/Unicode/blob/master/LICENSE.md
 */

/*
 * TESTING SHAPING FALLBACK, AS TAKING PLACE IN:
 * https://github.com/mapnik/mapnik/blob/64d5153aeaeb1c9e736bfead297dfea39b066d2c/include/mapnik/text/harfbuzz_shaper.hpp
 *
 *
 * DroidSansHebrew-Regular.ttf IS ONLY CONTAINING HEBREW LETTERS AND DIACRITICS
 * THEREFORE, WE RELY ON DroidSans.ttf FOR ANYTHING ELSE
 *
 *
 * UPDATE:
 * - NOW SEEMS TO WORKS AS INTENDED
 * - LET'S FIND A MORE ELEGANT WAY TO HANDLE THIS...
 */

#include "cinder/app/AppNative.h"

#include "YFont.h"

using namespace std;
using namespace ci;
using namespace app;

const float FONT_SIZE = 56;

class Application : public AppNative
{
    shared_ptr<FreetypeHelper> ftHelper; // THE UNDERLYING FT_Library WILL BE DESTROYED AFTER ALL THE YFont INSTANCES

    shared_ptr<YFont> font1;
    shared_ptr<YFont> font2;

public:
    void prepareSettings(Settings *settings);
    void setup();

    void draw();
    void drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float y);
    void drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float x, float y);
    void drawHLine(float y);
};

void Application::prepareSettings(Settings *settings)
{
    settings->setWindowSize(1024, 512);
}

void Application::setup()
{
    ftHelper = make_shared<FreetypeHelper>();

    font1 = make_shared<YFont>(ftHelper, FontDescriptor(loadAsset("fonts/DroidSansHebrew-Regular.ttf")), FONT_SIZE, ColorA(1, 1, 1, 1));
    font2 = make_shared<YFont>(ftHelper, FontDescriptor(loadAsset("fonts/DroidSans.ttf")), FONT_SIZE, ColorA(1, 1, 0.5f, 1));

    // ---

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

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
}

void Application::draw()
{
    gl::clear(Color::gray(0.5f), false);
    gl::setMatricesWindow(toPixels(getWindowSize()), true);

    drawSpan(*font1, *font2, TextSpan("וְהָהַר, מַהוּ לַזֵּה? – זֹאת הִיא הַשְּׁאֵלָה.", HB_SCRIPT_HEBREW, HB_DIRECTION_RTL, "he"), 256);
}

void Application::drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float y)
{
    drawSpan(font1, font2, span, 24, y);

    glColor4f(1, 0.75f, 0, 0.5f);
    drawHLine(y);
}

void Application::drawSpan(YFont &font1, YFont &font2, const TextSpan &span, float x, float y)
{
    const char *shapers[]  = { "ot", "fallback", NULL };
    hb_buffer_t *buffer = hb_buffer_create();

    multimap<uint32_t, Shape> shapes;

    /*
     * FIRST PASS
     */

    span.apply(buffer);
    hb_shape_full(font1.hbFont, buffer, NULL, 0, shapers);

    auto glyphCount = hb_buffer_get_length(buffer);
    auto glyph_info = hb_buffer_get_glyph_infos(buffer, nullptr);
    auto glyph_pos = hb_buffer_get_glyph_positions(buffer, nullptr);

    for (int i = 0; i < glyphCount; i++)
    {
        auto codepoint = glyph_info[i].codepoint;
        Vec2f offset(glyph_pos[i].x_offset, -glyph_pos[i].y_offset);
        float advance = glyph_pos[i].x_advance;

        if (codepoint)
        {
            shapes.emplace(glyph_info[i].cluster, Shape(&font1, codepoint, offset, advance));
        }

//      cout << codepoint << " | " << glyph_info[i].cluster << " | " << advance * font1.scale.x << endl;
    }
//  cout << endl;

    hb_buffer_clear_contents(buffer);

    /*
     * SECOND PASS
     */

    span.apply(buffer);
    hb_shape_full(font2.hbFont, buffer, NULL, 0, shapers);

    glyphCount = hb_buffer_get_length(buffer);
    glyph_info = hb_buffer_get_glyph_infos(buffer, nullptr);
    glyph_pos = hb_buffer_get_glyph_positions(buffer, nullptr);

    for (int i = 0; i < glyphCount; i++)
    {
        auto codepoint = glyph_info[i].codepoint;
        Vec2f offset(glyph_pos[i].x_offset, -glyph_pos[i].y_offset);
        float advance = glyph_pos[i].x_advance;

        if (codepoint)
        {
            shapes.emplace(glyph_info[i].cluster, Shape(&font2, codepoint, offset, advance));
        }

//      cout << codepoint << " | " << glyph_info[i].cluster << " | " << advance * font2.scale.x << endl;
    }
//  cout << endl;

    hb_buffer_destroy(buffer);

    // ---

    glPushMatrix();
    glTranslatef(x, y, 0);

    uint32_t lastCluster = -1;
    float advance = 0;

    for (auto it = shapes.rbegin(); it != shapes.rend(); ++it)
    {
        if (it->first != lastCluster)
        {
            glTranslatef(advance, 0, 0);
            advance = 0;
            lastCluster = it->first;
        }

        advance += it->second.draw();
    }

    glPopMatrix();
}

void Application::drawHLine(float y)
{
    gl::drawLine(Vec2f(-9999, y), Vec2f(+9999, y));
}

CINDER_APP_NATIVE(Application, RendererGl(RendererGl::AA_NONE))
<|endoftext|>


<commit_before>#include "algoritmos/clarke_wright.h"
#include "algoritmos/gillet_johnson.h"
#include "domain/rota.h"
#include <vector>
#include <algorithm>

using namespace std;
using namespace rotas::algoritmos;

namespace rotas {
	namespace algoritmos {

		static vector<Cidade> cidades_entrada;
		static vector<vector<Rota>> todos_savings;

		vector<Cidade> encontra_pontos_demandas(Cidade facilidade)
		{
			vector<Cidade> pontos_demanda = vector<Cidade>();
			for (unsigned int i = 0; i < cidades_entrada.size(); i++) {
				if (!cidades_entrada[i].is_mediana() &&
					cidades_entrada[i].get_id_mediana() == facilidade.get_id()) {
					pontos_demanda.push_back(cidades_entrada[i]);
				}
			}

			return pontos_demanda;
		}

		vector<Cidade> encontra_facilidades()
		{
			vector<Cidade> facilidades = vector<Cidade>();
			for (unsigned int i = 0; i < cidades_entrada.size(); i++) {
				if (cidades_entrada[i].is_mediana()) {
					facilidades.push_back(cidades_entrada[i]);
				}
			}

			return facilidades;
		}

		bool compara_rotas(Rota rota_a, Rota rota_b)
		{
			return rota_a.get_distancia() > rota_b.get_distancia();
		}

		void ordena_maior_pro_menor(vector<Rota> &savings)
		{
			sort(savings.begin(), savings.end(), compara_rotas);
		}

		vector<Rota> inicializa_savings(Cidade facilidade)
		{
			vector<Cidade> pontos_demanda = encontra_pontos_demandas(facilidade);

			vector<Rota> savings = vector<Rota>();

			ClarkeWright clarke = ClarkeWright();

			for (unsigned int i = 0; i < pontos_demanda.size(); i++)
			{
				int id_cidade_origem_atual = pontos_demanda[i].get_id();
				for (unsigned int j = i; j < pontos_demanda.size(); j++)
				{
					if (i != j)
					{
						int id_cidade_destino = pontos_demanda[j].get_id();
						double distancia_origem_facilidade = cidades_entrada[id_cidade_origem_atual].get_distancia(facilidade);
						double distancia_facilidade_destino = facilidade.get_distancia(cidades_entrada[id_cidade_destino]);
						double distancia_origem_destino = cidades_entrada[id_cidade_origem_atual].get_distancia(cidades_entrada[id_cidade_destino]);
						double distancia_saving_atual = distancia_origem_facilidade + distancia_facilidade_destino - distancia_origem_destino;

						savings.push_back(Rota(id_cidade_origem_atual,id_cidade_destino,distancia_saving_atual));
					}
				}
			}

			return savings;
		}

		bool saving_e_valido(Rota rota_saving)
		{
			if(rota_saving.get_distancia() < 0)
				return false;
			return true;
		}

		void adiciona_saving_na_rota(Rota saving, vector<Rota> &rota_encontradas)
		{

		}

		void incrementa_demandas_cobertas(vector<Rota> &rota_encontrada, int *contador_atual)
		{

		}

		vector<Rota> encontra_rota_partindo_dos_savings(vector<Rota> &savings_atual, Cidade facilidade)
		{
			vector<Rota> melhor_rota_encontrada = vector<Rota>();

			size_t total_demandas = encontra_pontos_demandas(facilidade).size();

			Cidade destino = cidades_entrada[savings_atual[0].get_id_origem()];

			// Adiciona a rota da origem pra primeira cidade do saving
			melhor_rota_encontrada.push_back(Rota(facilidade.get_id(),destino.get_id(),facilidade.get_distancia(destino)));

			int demandas_cobertas = 1;

			for (unsigned int i = 0; demandas_cobertas < total_demandas || i < savings_atual.size(); i++)
			{
				if (saving_e_valido(savings_atual[i]))
				{
					//adiciona_saving_na_rota(savings_atual[i], melhor_rota_encontrada);
					//incrementa_demandas_cobertas(melhor_rota_encontrada, demandas_cobertas);
				}
			}

			// Adiciona a rota da ultima cidade de destino retornando pra facilidade
			Cidade ultima_cidade_demanda = cidades_entrada[melhor_rota_encontrada.back().get_id_destino()];
			melhor_rota_encontrada.push_back(Rota(ultima_cidade_demanda.get_id(), facilidade.get_id(), ultima_cidade_demanda.get_distancia(facilidade)));
		}

		vector<vector<Rota>> ClarkeWright::encontra_roteamentos(std::vector<Cidade> & cidades)
		{
			cidades_entrada = cidades;

			vector<Cidade> facilidades = encontra_facilidades();

			vector<vector<Rota>> melhores_rotas_encontradas = vector<vector<Rota>>();

			todos_savings = vector<vector<Rota>>();

			for (unsigned int i = 0; i < facilidades.size(); i++)
			{
				vector<Rota> saving_atual = inicializa_savings(facilidades[i]);

				ordena_maior_pro_menor(saving_atual);

				todos_savings.push_back(saving_atual);
			}

			//for (unsigned int i = 0; i < todos_savings.size(); i ++)
			//{
			//	vector<Rota> melhor_rota_atual = vector<Rota>();

			//	melhor_rota_atual = encontra_rota_partindo_dos_savings(todos_savings[i], facilidades[i]);
			//
			//	melhores_rotas_encontradas.push_back(melhor_rota_atual);
			//}

			return todos_savings;
		}
	}
}<commit_msg>Versão capenga do clarke, tenho que corrigir a lógica.<commit_after>#include "algoritmos/clarke_wright.h"
#include "algoritmos/gillet_johnson.h"
#include "domain/rota.h"
#include <vector>
#include <algorithm>
#include <set>

using namespace std;
using namespace rotas::algoritmos;

namespace rotas {
	namespace algoritmos {

		static vector<Cidade> cidades_entrada;
		static vector<vector<Rota>> todos_savings;

		vector<Cidade> encontra_pontos_demandas(Cidade facilidade)
		{
			vector<Cidade> pontos_demanda = vector<Cidade>();
			for (unsigned int i = 0; i < cidades_entrada.size(); i++) {
				if (!cidades_entrada[i].is_mediana() &&
					cidades_entrada[i].get_id_mediana() == facilidade.get_id()) {
					pontos_demanda.push_back(cidades_entrada[i]);
				}
			}

			return pontos_demanda;
		}

		vector<Cidade> encontra_facilidades()
		{
			vector<Cidade> facilidades = vector<Cidade>();
			for (unsigned int i = 0; i < cidades_entrada.size(); i++) {
				if (cidades_entrada[i].is_mediana()) {
					facilidades.push_back(cidades_entrada[i]);
				}
			}

			return facilidades;
		}

		bool compara_rotas(Rota rota_a, Rota rota_b)
		{
			return rota_a.get_distancia() > rota_b.get_distancia();
		}

		void ordena_maior_pro_menor(vector<Rota> &savings)
		{
			sort(savings.begin(), savings.end(), compara_rotas);
		}

		vector<Rota> inicializa_savings(Cidade facilidade)
		{
			vector<Cidade> pontos_demanda = encontra_pontos_demandas(facilidade);

			vector<Rota> savings = vector<Rota>();

			ClarkeWright clarke = ClarkeWright();

			for (unsigned int i = 0; i < pontos_demanda.size(); i++)
			{
				int id_cidade_origem_atual = pontos_demanda[i].get_id();
				for (unsigned int j = i; j < pontos_demanda.size(); j++)
				{
					if (i != j)
					{
						int id_cidade_destino = pontos_demanda[j].get_id();
						double distancia_origem_facilidade = cidades_entrada[id_cidade_origem_atual].get_distancia(facilidade);
						double distancia_facilidade_destino = facilidade.get_distancia(cidades_entrada[id_cidade_destino]);
						double distancia_origem_destino = cidades_entrada[id_cidade_origem_atual].get_distancia(cidades_entrada[id_cidade_destino]);
						double distancia_saving_atual = distancia_origem_facilidade + distancia_facilidade_destino - distancia_origem_destino;

						savings.push_back(Rota(id_cidade_origem_atual,id_cidade_destino,distancia_saving_atual));
					}
				}
			}

			return savings;
		}

		bool saving_e_valido(Rota rota_saving)
		{
			if(rota_saving.get_distancia() < 0)
				return false;
			return true;
		}

		bool cidade_existe_na_rota(int id_cidade, vector<Rota> rotas_encontradas)
		{
			for each(Rota rota_atual in rotas_encontradas)
			{
				if(rota_atual.rota_contem_cidade(id_cidade))
					return true;
			}
			return false;
		}

		void adiciona_cidade_na_rota(int id_cidade, vector<Rota> &rotas_encontradas)
		{
			int id_origem = rotas_encontradas.back().get_id_destino();
			Cidade origem = cidades_entrada[id_origem];
			Cidade destino = cidades_entrada[id_cidade];

			rotas_encontradas.push_back(Rota(id_origem, id_cidade, origem.get_distancia(destino)));
		}

		int adiciona_saving_na_rota(Rota saving, vector<Rota> &rotas_encontradas)
		{
			int contador_demandas = 0;

			if (!cidade_existe_na_rota(saving.get_id_origem(), rotas_encontradas))
			{
				adiciona_cidade_na_rota(saving.get_id_origem(), rotas_encontradas);
				contador_demandas ++;
			}
			if (!cidade_existe_na_rota(saving.get_id_destino(), rotas_encontradas))
			{
				adiciona_cidade_na_rota(saving.get_id_destino(), rotas_encontradas);
				contador_demandas ++;
			}

			return contador_demandas;
		}

		vector<Rota> encontra_rota_partindo_dos_savings(vector<Rota> &savings_atual, Cidade facilidade)
		{
			vector<Rota> melhor_rota_encontrada = vector<Rota>();

			size_t total_demandas = encontra_pontos_demandas(facilidade).size();

			Cidade destino = cidades_entrada[savings_atual[0].get_id_origem()];

			// Adiciona a rota da origem pra primeira cidade do saving
			melhor_rota_encontrada.push_back(Rota(facilidade.get_id(),destino.get_id(),facilidade.get_distancia(destino)));

			int demandas_cobertas = 1;

			for (unsigned int i = 0; demandas_cobertas < total_demandas && i < savings_atual.size(); i++)
			{
				if (saving_e_valido(savings_atual[i]))
				{
					demandas_cobertas += adiciona_saving_na_rota(savings_atual[i], melhor_rota_encontrada);
				}
			}

			// Adiciona a rota da ultima cidade de destino retornando pra facilidade
			Cidade ultima_cidade_demanda = cidades_entrada[melhor_rota_encontrada.back().get_id_destino()];
			melhor_rota_encontrada.push_back(Rota(ultima_cidade_demanda.get_id(), facilidade.get_id(), ultima_cidade_demanda.get_distancia(facilidade)));

			return melhor_rota_encontrada;
		}

		vector<vector<Rota>> ClarkeWright::encontra_roteamentos(std::vector<Cidade> & cidades)
		{
			cidades_entrada = cidades;

			vector<Cidade> facilidades = encontra_facilidades();

			vector<vector<Rota>> melhores_rotas_encontradas = vector<vector<Rota>>();

			todos_savings = vector<vector<Rota>>();

			for (unsigned int i = 0; i < facilidades.size(); i++)
			{
				vector<Rota> saving_atual = inicializa_savings(facilidades[i]);

				ordena_maior_pro_menor(saving_atual);

				todos_savings.push_back(saving_atual);
			}

			for (unsigned int i = 0; i < todos_savings.size(); i ++)
			{
				vector<Rota> melhor_rota_atual = vector<Rota>();

				melhor_rota_atual = encontra_rota_partindo_dos_savings(todos_savings[i], facilidades[i]);

				melhores_rotas_encontradas.push_back(melhor_rota_atual);
			}

			return todos_savings;
		}
	}
}<|endoftext|>


<commit_before>//
// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
// LICENSE: Atomic Game Engine Editor and Tools EULA
// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
//

#include <Atomic/IO/MemoryBuffer.h>
#include <Atomic/IO/FileSystem.h>
#include <Atomic/IO/Log.h>

#include "../ToolEnvironment.h"
#include "../Subprocess/SubprocessSystem.h"
#include "../License/LicenseSystem.h"
#include "../Build/BuildAndroid.h"

#include "PlatformAndroid.h"

namespace ToolCore
{

PlatformAndroid::PlatformAndroid(Context* context) : Platform(context)
{

}

PlatformAndroid::~PlatformAndroid()
{

}

BuildBase* PlatformAndroid::NewBuild(Project *project)
{
    return new BuildAndroid(context_, project);
}

void PlatformAndroid::PrependAndroidCommandArgs(Vector<String> args)
{
#ifdef ATOMIC_PLATFORM_WINDOWS
    // android is a batch file on windows, so have to run with cmd /c
    args.Push("/c");
    args.Push("\"" + GetAndroidCommand() + "\"");
#endif

}

void PlatformAndroid::HandleRefreshAndroidTargetsEvent(StringHash eventType, VariantMap& eventData)
{
    if (eventType == E_SUBPROCESSOUTPUT)
    {
        targetOutput_ += eventData[SubprocessOutput::P_TEXT].GetString();
    }
    else if (eventType == E_SUBPROCESSCOMPLETE)
    {
        refreshAndroidTargetsProcess_ = 0;

        androidTargets_.Clear();

        MemoryBuffer reader(targetOutput_.CString(), targetOutput_.Length() + 1);

        while (!reader.IsEof())
        {
            String line = reader.ReadLine();
            if (line.StartsWith("id:"))
            {
                //id: 33 or "Google Inc.:Google APIs (x86 System Image):19"
                Vector<String> elements = line.Split('\"');
                if (elements.Size() == 2)
                {
                    String api = elements[1];

                    androidTargets_.Push(api);
                }
            }
        }

        SendEvent(E_ANDROIDTARGETSREFRESHED);
    }

}

void PlatformAndroid::RefreshAndroidTargets()
{
    if (refreshAndroidTargetsProcess_.NotNull())
        return;

    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();
    FileSystem* fileSystem = GetSubsystem<FileSystem>();

    String androidSDKPath = prefs->GetAndroidSDKPath();

    if (!fileSystem->DirExists(androidSDKPath))
    {
        LOGERRORF("Android path not exists");
        return;
    }

    SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();

    String androidCommand = GetAndroidCommand();

    Vector<String> args;
    PrependAndroidCommandArgs(args);
    args.Push("list");
    args.Push("targets");

    targetOutput_.Clear();
    refreshAndroidTargetsProcess_ = subs->Launch(androidCommand, args);

    if (refreshAndroidTargetsProcess_.NotNull())
    {

        SubscribeToEvent(refreshAndroidTargetsProcess_, E_SUBPROCESSCOMPLETE, HANDLER(PlatformAndroid, HandleRefreshAndroidTargetsEvent));
        SubscribeToEvent(refreshAndroidTargetsProcess_, E_SUBPROCESSOUTPUT, HANDLER(PlatformAndroid, HandleRefreshAndroidTargetsEvent));

    }

}

String PlatformAndroid::GetADBCommand() const
{
    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();

    String adbCommand = prefs->GetAndroidSDKPath();

#ifdef ATOMIC_PLATFORM_OSX
    adbCommand += "/platform-tools/adb";
#else
    adbCommand += "/platform-tools/adb.exe";
#endif

    return adbCommand;

}

String PlatformAndroid::GetAndroidCommand() const
{
    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();

    String androidCommand = GetNativePath(prefs->GetAndroidSDKPath());

    if (!androidCommand.Length())
        return String::EMPTY;

#ifdef ATOMIC_PLATFORM_OSX
    //Vector<String> args = String("list targets").Split(' ');
    androidCommand += "/tools/android";
#else

    // android is a batch file on windows, so have to run with cmd /c
    androidCommand += "\\tools\\android.bat";

    //androidCommand = "cmd";
#endif

    return androidCommand;

}

bool PlatformAndroid::GetLicense()
{
// BEGIN LICENSE MANAGEMENT
    return GetSubsystem<LicenseSystem>()->GetLicenseAndroid();
// END LICENSE MANAGEMENT
}

}
<commit_msg>Changed error message<commit_after>//
// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
// LICENSE: Atomic Game Engine Editor and Tools EULA
// Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
// license information: https://github.com/AtomicGameEngine/AtomicGameEngine
//

#include <Atomic/IO/MemoryBuffer.h>
#include <Atomic/IO/FileSystem.h>
#include <Atomic/IO/Log.h>

#include "../ToolEnvironment.h"
#include "../Subprocess/SubprocessSystem.h"
#include "../License/LicenseSystem.h"
#include "../Build/BuildAndroid.h"

#include "PlatformAndroid.h"

namespace ToolCore
{

PlatformAndroid::PlatformAndroid(Context* context) : Platform(context)
{

}

PlatformAndroid::~PlatformAndroid()
{

}

BuildBase* PlatformAndroid::NewBuild(Project *project)
{
    return new BuildAndroid(context_, project);
}

void PlatformAndroid::PrependAndroidCommandArgs(Vector<String> args)
{
#ifdef ATOMIC_PLATFORM_WINDOWS
    // android is a batch file on windows, so have to run with cmd /c
    args.Push("/c");
    args.Push("\"" + GetAndroidCommand() + "\"");
#endif

}

void PlatformAndroid::HandleRefreshAndroidTargetsEvent(StringHash eventType, VariantMap& eventData)
{
    if (eventType == E_SUBPROCESSOUTPUT)
    {
        targetOutput_ += eventData[SubprocessOutput::P_TEXT].GetString();
    }
    else if (eventType == E_SUBPROCESSCOMPLETE)
    {
        refreshAndroidTargetsProcess_ = 0;

        androidTargets_.Clear();

        MemoryBuffer reader(targetOutput_.CString(), targetOutput_.Length() + 1);

        while (!reader.IsEof())
        {
            String line = reader.ReadLine();
            if (line.StartsWith("id:"))
            {
                //id: 33 or "Google Inc.:Google APIs (x86 System Image):19"
                Vector<String> elements = line.Split('\"');
                if (elements.Size() == 2)
                {
                    String api = elements[1];

                    androidTargets_.Push(api);
                }
            }
        }

        SendEvent(E_ANDROIDTARGETSREFRESHED);
    }

}

void PlatformAndroid::RefreshAndroidTargets()
{
    if (refreshAndroidTargetsProcess_.NotNull())
        return;

    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();
    FileSystem* fileSystem = GetSubsystem<FileSystem>();

    String androidSDKPath = prefs->GetAndroidSDKPath();

    if (!fileSystem->DirExists(androidSDKPath))
    {
        LOGERRORF("The Android SDK path %s does not exist", androidSDKPath.CString());
        return;
    }

    SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();

    String androidCommand = GetAndroidCommand();

    Vector<String> args;
    PrependAndroidCommandArgs(args);
    args.Push("list");
    args.Push("targets");

    targetOutput_.Clear();
    refreshAndroidTargetsProcess_ = subs->Launch(androidCommand, args);

    if (refreshAndroidTargetsProcess_.NotNull())
    {

        SubscribeToEvent(refreshAndroidTargetsProcess_, E_SUBPROCESSCOMPLETE, HANDLER(PlatformAndroid, HandleRefreshAndroidTargetsEvent));
        SubscribeToEvent(refreshAndroidTargetsProcess_, E_SUBPROCESSOUTPUT, HANDLER(PlatformAndroid, HandleRefreshAndroidTargetsEvent));

    }

}

String PlatformAndroid::GetADBCommand() const
{
    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();

    String adbCommand = prefs->GetAndroidSDKPath();

#ifdef ATOMIC_PLATFORM_OSX
    adbCommand += "/platform-tools/adb";
#else
    adbCommand += "/platform-tools/adb.exe";
#endif

    return adbCommand;

}

String PlatformAndroid::GetAndroidCommand() const
{
    ToolPrefs* prefs = GetSubsystem<ToolEnvironment>()->GetToolPrefs();

    String androidCommand = GetNativePath(prefs->GetAndroidSDKPath());

    if (!androidCommand.Length())
        return String::EMPTY;

#ifdef ATOMIC_PLATFORM_OSX
    //Vector<String> args = String("list targets").Split(' ');
    androidCommand += "/tools/android";
#else

    // android is a batch file on windows, so have to run with cmd /c
    androidCommand += "\\tools\\android.bat";

    //androidCommand = "cmd";
#endif

    return androidCommand;

}

bool PlatformAndroid::GetLicense()
{
// BEGIN LICENSE MANAGEMENT
    return GetSubsystem<LicenseSystem>()->GetLicenseAndroid();
// END LICENSE MANAGEMENT
}

}
<|endoftext|>


<commit_before>#include "musiccryptographichash.h"

#define XXTEA_MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)
#define XXTEA_DELTA 0x9E3779B9

const std::string base64_chars =
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "abcdefghijklmnopqrstuvwxyz"
                    "0123456789+/";

MusicCryptographicHash::MusicCryptographicHash()
{

}

QString MusicCryptographicHash::encrypt(const QString &data, const QString &key, Priority p)
{
    QString d = data;
    for(int i=0; i<p; ++i)
    {
        d = xxteaEncrypt(d, key).toUtf8().toBase64();
    }
    return d;
}

QString MusicCryptographicHash::decrypt(const QString &data, const QString &key, Priority p)
{
    QString d = data;
    for(int i=0; i<p; ++i)
    {
        d = xxteaDecrypt(QByteArray::fromBase64(d.toUtf8()), key);
    }
    return d;
}

std::string MusicCryptographicHash::xxteaEncrypt(std::string data, std::string key)
{
    data = QString(data.c_str()).toUtf8().toStdString();
    unsigned char date_uchar[1024];
    strcpy((char*)date_uchar,(const char *)data.c_str());
    unsigned char key_uchar[1024];
    strcpy((char*)key_uchar,(const char *)key.c_str());
    xxtea_uint s[1];
    unsigned char * encrypt = xxteaEncrypt(date_uchar,strlen((const char *)date_uchar),key_uchar,strlen((const char *)key_uchar),s);
    std::string encoded = base64Encode(encrypt,s[0]);
    return encoded;
}

std::string MusicCryptographicHash::xxteaDecrypt(std::string data,  std::string key)
{
    std::string decoded = base64Decode(data);
    if(decoded.empty())
    {
        return std::string("");
    }
    unsigned char date_uchar[1024];
    memcpy(date_uchar, decoded.c_str(),decoded.length());
    date_uchar[decoded.length()] = '\0';
    unsigned char key_uchar[1024];
    strcpy((char*)key_uchar,(const char *)key.c_str());
    xxtea_uint s[1];
    unsigned char * encrypt = xxteaDecrypt(date_uchar,decoded.length(),key_uchar,strlen((const char *)key_uchar),s);
    if(!encrypt)
    {
        return std::string("false_false");
    }
    std::string result = (char *)encrypt;
    result = QString::fromUtf8(result.c_str()).toStdString();
    return result;
}

QString MusicCryptographicHash::xxteaEncrypt(const QString &data, const QString &key)
{
    return xxteaEncrypt(data.toStdString(), key.toStdString()).c_str();
}

QString MusicCryptographicHash::xxteaDecrypt(const QString &data, const QString &key)
{
    return xxteaDecrypt(data.toStdString(), key.toStdString()).c_str();
}

bool MusicCryptographicHash::isBase64(unsigned char c)
{
    return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string MusicCryptographicHash::base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
    std::string ret;
    int i = 0, j = 0;
    unsigned char char_array_3[3], char_array_4[4];

    while (in_len--)
    {
        char_array_3[i++] = *(bytes_to_encode++);
        if (i == 3)
        {
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;

            for(i = 0; (i <4) ; i++)
            {
                ret += base64_chars[char_array_4[i]];
            }
            i = 0;
        }
    }

    if (i)
    {
        for(j = i; j < 3; j++)
        {
            char_array_3[j] = '\0';
        }

        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
        char_array_4[3] = char_array_3[2] & 0x3f;

        for (j = 0; (j < i + 1); j++)
        {
            ret += base64_chars[char_array_4[j]];
        }

        while((i++ < 3))
        {
            ret += '=';
        }

    }
    return ret;
}

std::string MusicCryptographicHash::base64Decode(std::string const& encoded_string)
{
    int in_len = encoded_string.size();
    int i = 0, j = 0, in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;

    while (in_len-- && ( encoded_string[in_] != '=') && isBase64(encoded_string[in_]))
    {
        char_array_4[i++] = encoded_string[in_]; in_++;
        if (i ==4)
        {
            for (i = 0; i <4; i++)
            {
                char_array_4[i] = base64_chars.find(char_array_4[i]);
            }

            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
            {
                ret += char_array_3[i];
            }
            i = 0;
        }
    }

    if (i)
    {
        for (j = i; j <4; j++)
        {
            char_array_4[j] = 0;
        }

        for (j = 0; j <4; j++)
        {
            char_array_4[j] = base64_chars.find(char_array_4[j]);
        }

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++)
        {
            ret += char_array_3[j];
        }
    }

    return ret;
}

void MusicCryptographicHash::xxteaUintEncrypt(xxtea_uint *v, xxtea_uint len, xxtea_uint *k)
{
    xxtea_uint n = len - 1;
    xxtea_uint z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = 0, e;
    if (n < 1) {
        return;
    }
    while (0 < q--) {
        sum += XXTEA_DELTA;
        e = sum >> 2 & 3;
        for (p = 0; p < n; p++) {
            y = v[p + 1];
            z = v[p] += XXTEA_MX;
        }
        y = v[0];
        z = v[n] += XXTEA_MX;
    }
}

void MusicCryptographicHash::xxteaUintDecrypt(xxtea_uint *v, xxtea_uint len, xxtea_uint *k)
{
    xxtea_uint n = len - 1;
    xxtea_uint z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = q * XXTEA_DELTA, e;
    if (n < 1) {
        return;
    }
    while (sum != 0) {
        e = sum >> 2 & 3;
        for (p = n; p > 0; p--) {
            z = v[p - 1];
            y = v[p] -= XXTEA_MX;
        }
        z = v[n];
        y = v[0] -= XXTEA_MX;
        sum -= XXTEA_DELTA;
    }
}

unsigned char *MusicCryptographicHash::fixKeyLength(unsigned char *key, xxtea_uint key_len)
{
    unsigned char *tmp = (unsigned char *)malloc(16);
    memcpy(tmp, key, key_len);
    memset(tmp + key_len, '\0', 16 - key_len);
    return tmp;
}

xxtea_uint *MusicCryptographicHash::xxteaToUintArray(unsigned char *data, xxtea_uint len, int include_length, xxtea_uint *ret_len)
{
    xxtea_uint i, n, *result;

    n = len >> 2;
    n = (((len & 3) == 0) ? n : n + 1);
    if (include_length) {
        result = (xxtea_uint *)malloc((n + 1) << 2);
        result[n] = len;
        *ret_len = n + 1;
    } else {
        result = (xxtea_uint *)malloc(n << 2);
        *ret_len = n;
    }
    memset(result, 0, n << 2);
    for (i = 0; i < len; i++) {
        result[i >> 2] |= (xxtea_uint)data[i] << ((i & 3) << 3);
    }

    return result;
}

unsigned char *MusicCryptographicHash::xxteaToByteArray(xxtea_uint *data, xxtea_uint len, int include_length, xxtea_uint *ret_len)
{
    xxtea_uint i, n, m;
    unsigned char *result;

    n = len << 2;
    if (include_length) {
        m = data[len - 1];
        if ((m < n - 7) || (m > n - 4)) return NULL;
        n = m;
    }
    result = (unsigned char *)malloc(n + 1);
    for (i = 0; i < n; i++) {
        result[i] = (unsigned char)((data[i >> 2] >> ((i & 3) << 3)) & 0xff);
    }
    result[n] = '\0';
    *ret_len = n;

    return result;
}

unsigned char *MusicCryptographicHash::doXxteaEncrypt(unsigned char *data, xxtea_uint len, unsigned char *key, xxtea_uint *ret_len)
{
    unsigned char *result;
    xxtea_uint *v, *k, v_len, k_len;

    v = xxteaToUintArray(data, len, 1, &v_len);
    k = xxteaToUintArray(key, 16, 0, &k_len);
    xxteaUintEncrypt(v, v_len, k);
    result = xxteaToByteArray(v, v_len, 0, ret_len);
    free(v);
    free(k);

    return result;
}

unsigned char *MusicCryptographicHash::doXxteaDecrypt(unsigned char *data, xxtea_uint len, unsigned char *key, xxtea_uint *ret_len)
{
    unsigned char *result;
    xxtea_uint *v, *k, v_len, k_len;

    v = xxteaToUintArray(data, len, 0, &v_len);
    k = xxteaToUintArray(key, 16, 0, &k_len);
    xxteaUintDecrypt(v, v_len, k);
    result = xxteaToByteArray(v, v_len, 1, ret_len);
    free(v);
    free(k);

    return result;
}

unsigned char *MusicCryptographicHash::xxteaEncrypt(unsigned char *data, xxtea_uint data_len, unsigned char *key, xxtea_uint key_len, xxtea_uint *ret_length)
{
    unsigned char *result;

    *ret_length = 0;

    if (key_len < 16) {
        unsigned char *key2 = fixKeyLength(key, key_len);
        result = doXxteaEncrypt(data, data_len, key2, ret_length);
        free(key2);
    }
    else
    {
        result = doXxteaEncrypt(data, data_len, key, ret_length);
    }

    return result;
}

unsigned char *MusicCryptographicHash::xxteaDecrypt(unsigned char *data, xxtea_uint data_len, unsigned char *key, xxtea_uint key_len, xxtea_uint *ret_length)
{
    unsigned char *result;

    *ret_length = 0;

    if (key_len < 16) {
        unsigned char *key2 = fixKeyLength(key, key_len);
        result = doXxteaDecrypt(data, data_len, key2, ret_length);
        free(key2);
    }
    else
    {
        result = doXxteaDecrypt(data, data_len, key, ret_length);
    }

    return result;
}
<commit_msg>update cryptographics hash on qt4 [481523]<commit_after>#include "musiccryptographichash.h"

#define XXTEA_MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)
#define XXTEA_DELTA 0x9E3779B9

const std::string base64_chars =
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "abcdefghijklmnopqrstuvwxyz"
                    "0123456789+/";

MusicCryptographicHash::MusicCryptographicHash()
{

}

QString MusicCryptographicHash::encrypt(const QString &data, const QString &key, Priority p)
{
    QString d = data;
    for(int i=0; i<p; ++i)
    {
        d = xxteaEncrypt(d, key).toUtf8().toBase64();
    }
    return d;
}

QString MusicCryptographicHash::decrypt(const QString &data, const QString &key, Priority p)
{
    QString d = data;
    for(int i=0; i<p; ++i)
    {
        d = xxteaDecrypt(QByteArray::fromBase64(d.toUtf8()), key);
    }
    return d;
}

std::string MusicCryptographicHash::xxteaEncrypt(std::string data, std::string key)
{
    data = QString(QString(data.c_str()).toUtf8()).toStdString();
    unsigned char date_uchar[1024];
    strcpy((char*)date_uchar,(const char *)data.c_str());
    unsigned char key_uchar[1024];
    strcpy((char*)key_uchar,(const char *)key.c_str());
    xxtea_uint s[1];
    unsigned char * encrypt = xxteaEncrypt(date_uchar,strlen((const char *)date_uchar),key_uchar,strlen((const char *)key_uchar),s);
    std::string encoded = base64Encode(encrypt,s[0]);
    return encoded;
}

std::string MusicCryptographicHash::xxteaDecrypt(std::string data,  std::string key)
{
    std::string decoded = base64Decode(data);
    if(decoded.empty())
    {
        return std::string("");
    }
    unsigned char date_uchar[1024];
    memcpy(date_uchar, decoded.c_str(),decoded.length());
    date_uchar[decoded.length()] = '\0';
    unsigned char key_uchar[1024];
    strcpy((char*)key_uchar,(const char *)key.c_str());
    xxtea_uint s[1];
    unsigned char * encrypt = xxteaDecrypt(date_uchar,decoded.length(),key_uchar,strlen((const char *)key_uchar),s);
    if(!encrypt)
    {
        return std::string("false_false");
    }
    std::string result = (char *)encrypt;
    result = QString::fromUtf8(result.c_str()).toStdString();
    return result;
}

QString MusicCryptographicHash::xxteaEncrypt(const QString &data, const QString &key)
{
    return xxteaEncrypt(data.toStdString(), key.toStdString()).c_str();
}

QString MusicCryptographicHash::xxteaDecrypt(const QString &data, const QString &key)
{
    return xxteaDecrypt(data.toStdString(), key.toStdString()).c_str();
}

bool MusicCryptographicHash::isBase64(unsigned char c)
{
    return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string MusicCryptographicHash::base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
    std::string ret;
    int i = 0, j = 0;
    unsigned char char_array_3[3], char_array_4[4];

    while (in_len--)
    {
        char_array_3[i++] = *(bytes_to_encode++);
        if (i == 3)
        {
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;

            for(i = 0; (i <4) ; i++)
            {
                ret += base64_chars[char_array_4[i]];
            }
            i = 0;
        }
    }

    if (i)
    {
        for(j = i; j < 3; j++)
        {
            char_array_3[j] = '\0';
        }

        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
        char_array_4[3] = char_array_3[2] & 0x3f;

        for (j = 0; (j < i + 1); j++)
        {
            ret += base64_chars[char_array_4[j]];
        }

        while((i++ < 3))
        {
            ret += '=';
        }

    }
    return ret;
}

std::string MusicCryptographicHash::base64Decode(std::string const& encoded_string)
{
    int in_len = encoded_string.size();
    int i = 0, j = 0, in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;

    while (in_len-- && ( encoded_string[in_] != '=') && isBase64(encoded_string[in_]))
    {
        char_array_4[i++] = encoded_string[in_]; in_++;
        if (i ==4)
        {
            for (i = 0; i <4; i++)
            {
                char_array_4[i] = base64_chars.find(char_array_4[i]);
            }

            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
            {
                ret += char_array_3[i];
            }
            i = 0;
        }
    }

    if (i)
    {
        for (j = i; j <4; j++)
        {
            char_array_4[j] = 0;
        }

        for (j = 0; j <4; j++)
        {
            char_array_4[j] = base64_chars.find(char_array_4[j]);
        }

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++)
        {
            ret += char_array_3[j];
        }
    }

    return ret;
}

void MusicCryptographicHash::xxteaUintEncrypt(xxtea_uint *v, xxtea_uint len, xxtea_uint *k)
{
    xxtea_uint n = len - 1;
    xxtea_uint z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = 0, e;
    if (n < 1) {
        return;
    }
    while (0 < q--) {
        sum += XXTEA_DELTA;
        e = sum >> 2 & 3;
        for (p = 0; p < n; p++) {
            y = v[p + 1];
            z = v[p] += XXTEA_MX;
        }
        y = v[0];
        z = v[n] += XXTEA_MX;
    }
}

void MusicCryptographicHash::xxteaUintDecrypt(xxtea_uint *v, xxtea_uint len, xxtea_uint *k)
{
    xxtea_uint n = len - 1;
    xxtea_uint z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = q * XXTEA_DELTA, e;
    if (n < 1) {
        return;
    }
    while (sum != 0) {
        e = sum >> 2 & 3;
        for (p = n; p > 0; p--) {
            z = v[p - 1];
            y = v[p] -= XXTEA_MX;
        }
        z = v[n];
        y = v[0] -= XXTEA_MX;
        sum -= XXTEA_DELTA;
    }
}

unsigned char *MusicCryptographicHash::fixKeyLength(unsigned char *key, xxtea_uint key_len)
{
    unsigned char *tmp = (unsigned char *)malloc(16);
    memcpy(tmp, key, key_len);
    memset(tmp + key_len, '\0', 16 - key_len);
    return tmp;
}

xxtea_uint *MusicCryptographicHash::xxteaToUintArray(unsigned char *data, xxtea_uint len, int include_length, xxtea_uint *ret_len)
{
    xxtea_uint i, n, *result;

    n = len >> 2;
    n = (((len & 3) == 0) ? n : n + 1);
    if (include_length) {
        result = (xxtea_uint *)malloc((n + 1) << 2);
        result[n] = len;
        *ret_len = n + 1;
    } else {
        result = (xxtea_uint *)malloc(n << 2);
        *ret_len = n;
    }
    memset(result, 0, n << 2);
    for (i = 0; i < len; i++) {
        result[i >> 2] |= (xxtea_uint)data[i] << ((i & 3) << 3);
    }

    return result;
}

unsigned char *MusicCryptographicHash::xxteaToByteArray(xxtea_uint *data, xxtea_uint len, int include_length, xxtea_uint *ret_len)
{
    xxtea_uint i, n, m;
    unsigned char *result;

    n = len << 2;
    if (include_length) {
        m = data[len - 1];
        if ((m < n - 7) || (m > n - 4)) return NULL;
        n = m;
    }
    result = (unsigned char *)malloc(n + 1);
    for (i = 0; i < n; i++) {
        result[i] = (unsigned char)((data[i >> 2] >> ((i & 3) << 3)) & 0xff);
    }
    result[n] = '\0';
    *ret_len = n;

    return result;
}

unsigned char *MusicCryptographicHash::doXxteaEncrypt(unsigned char *data, xxtea_uint len, unsigned char *key, xxtea_uint *ret_len)
{
    unsigned char *result;
    xxtea_uint *v, *k, v_len, k_len;

    v = xxteaToUintArray(data, len, 1, &v_len);
    k = xxteaToUintArray(key, 16, 0, &k_len);
    xxteaUintEncrypt(v, v_len, k);
    result = xxteaToByteArray(v, v_len, 0, ret_len);
    free(v);
    free(k);

    return result;
}

unsigned char *MusicCryptographicHash::doXxteaDecrypt(unsigned char *data, xxtea_uint len, unsigned char *key, xxtea_uint *ret_len)
{
    unsigned char *result;
    xxtea_uint *v, *k, v_len, k_len;

    v = xxteaToUintArray(data, len, 0, &v_len);
    k = xxteaToUintArray(key, 16, 0, &k_len);
    xxteaUintDecrypt(v, v_len, k);
    result = xxteaToByteArray(v, v_len, 1, ret_len);
    free(v);
    free(k);

    return result;
}

unsigned char *MusicCryptographicHash::xxteaEncrypt(unsigned char *data, xxtea_uint data_len, unsigned char *key, xxtea_uint key_len, xxtea_uint *ret_length)
{
    unsigned char *result;

    *ret_length = 0;

    if (key_len < 16) {
        unsigned char *key2 = fixKeyLength(key, key_len);
        result = doXxteaEncrypt(data, data_len, key2, ret_length);
        free(key2);
    }
    else
    {
        result = doXxteaEncrypt(data, data_len, key, ret_length);
    }

    return result;
}

unsigned char *MusicCryptographicHash::xxteaDecrypt(unsigned char *data, xxtea_uint data_len, unsigned char *key, xxtea_uint key_len, xxtea_uint *ret_length)
{
    unsigned char *result;

    *ret_length = 0;

    if (key_len < 16) {
        unsigned char *key2 = fixKeyLength(key, key_len);
        result = doXxteaDecrypt(data, data_len, key2, ret_length);
        free(key2);
    }
    else
    {
        result = doXxteaDecrypt(data, data_len, key, ret_length);
    }

    return result;
}
<|endoftext|>