<commit_before>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const std::string &socket_path) :
    AbstractServerConnector(),
    socket_path(socket_path.substr(0, PATH_MAX)),
    running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
    if(!this->running)
    {
        //Create and bind socket here.
    	//Then launch the listenning loop.
    	this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
    }
    return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
    if(this->running)
    {
       	close(this->socket_fd);
       	unlink(this->socket_path.c_str());
        this->running = false;
    }
    return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	string temp = response;
	if(temp.find(DELIMITER_CHAR) == string::npos) {
		temp.append(1, DELIMITER_CHAR);
	}
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = temp.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		write(connection_fd, toSend.c_str(), toSend.size());
	}
	else {
		write(connection_fd, temp.c_str(), temp.size());
	}
	close(connection_fd);
	return true;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length;
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	int connection_fd = params->connection_fd;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	string request;
	do { //The client sends its json formatted request and a delimiter request.
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);

	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}
<commit_msg>Corrected bug: uninitialized address_lenght variable made accept fails.<commit_after>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const std::string &socket_path) :
    AbstractServerConnector(),
    socket_path(socket_path.substr(0, PATH_MAX)),
    running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
    if(!this->running)
    {
        //Create and bind socket here.
    	//Then launch the listenning loop.
    	this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
    }
    return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
    if(this->running)
    {
       	close(this->socket_fd);
       	unlink(this->socket_path.c_str());
        this->running = false;
    }
    return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	string temp = response;
	if(temp.find(DELIMITER_CHAR) == string::npos) {
		temp.append(1, DELIMITER_CHAR);
	}
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = temp.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		write(connection_fd, toSend.c_str(), toSend.size());
	}
	else {
		write(connection_fd, temp.c_str(), temp.size());
	}
	close(connection_fd);
	return true;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length = sizeof(this->address);
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	int connection_fd = params->connection_fd;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	string request;
	do { //The client sends its json formatted request and a delimiter request.
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);
	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"

#if CROWN_SOUND_OPENAL

#include "array.h"
#include "audio.h"
#include "log.h"
#include "matrix4x4.h"
#include "sound_resource.h"
#include "sound_world.h"
#include "temp_allocator.h"
#include "vector3.h"
#include <AL/al.h>
#include <AL/alc.h>

namespace crown
{
#if CROWN_DEBUG
	static const char* al_error_to_string(ALenum error)
	{
		switch (error)
		{
			case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
			case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
			case AL_INVALID_OPERATION: return "AL_INVALID_OPERATION";
			case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
			default: return "UNKNOWN_AL_ERROR";
		}
	}

	#define AL_CHECK(function)\
		function;\
		do { ALenum error; CE_ASSERT((error = alGetError()) == AL_NO_ERROR,\
				"OpenAL error: %s", al_error_to_string(error)); } while (0)
#else
	#define AL_CHECK(function) function;
#endif // CROWN_DEBUG

/// Global audio-related functions
namespace audio_globals
{
	static ALCdevice* s_al_device;
	static ALCcontext* s_al_context;

	void init()
	{
		s_al_device = alcOpenDevice(NULL);
		CE_ASSERT(s_al_device, "Cannot open OpenAL audio device");

		s_al_context = alcCreateContext(s_al_device, NULL);
		CE_ASSERT(s_al_context, "Cannot create OpenAL context");

		AL_CHECK(alcMakeContextCurrent(s_al_context));

		CE_LOGD("OpenAL Vendor   : %s", alGetString(AL_VENDOR));
		CE_LOGD("OpenAL Version  : %s", alGetString(AL_VERSION));
		CE_LOGD("OpenAL Renderer : %s", alGetString(AL_RENDERER));

		AL_CHECK(alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED));
		AL_CHECK(alDopplerFactor(1.0f));
		AL_CHECK(alDopplerVelocity(343.0f));
	}

	void shutdown()
	{
		alcDestroyContext(s_al_context);
	    alcCloseDevice(s_al_device);
	}
}

struct SoundInstance
{
	void create(const SoundResource& sr, const Vector3& pos)
	{
		using namespace sound_resource;

		AL_CHECK(alGenSources(1, &_source));
		CE_ASSERT(alIsSource(_source), "alGenSources: error");

		// AL_CHECK(alSourcef(_source, AL_PITCH, 1.0f));
		// AL_CHECK(alSourcef(_source, AL_REFERENCE_DISTANCE, 0.1f));
		// AL_CHECK(alSourcef(_source, AL_MAX_DISTANCE, 1000.0f));

		// Generates AL buffers
		AL_CHECK(alGenBuffers(1, &_buffer));
		CE_ASSERT(alIsBuffer(_buffer), "alGenBuffers: error");

		ALenum fmt;
		switch (sr.bits_ps)
		{
			case  8: fmt = sr.channels > 1 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8; break;
			case 16: fmt = sr.channels > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; break;
			default: CE_FATAL("Number of bits per sample not supported."); break;
		}
		AL_CHECK(alBufferData(_buffer, fmt, data(&sr), sr.size, sr.sample_rate));

		_resource = &sr;
		set_position(pos);
	}

	void destroy()
	{
		stop();
		AL_CHECK(alSourcei(_source, AL_BUFFER, 0));
		AL_CHECK(alDeleteBuffers(1, &_buffer));
		AL_CHECK(alDeleteSources(1, &_source));
	}

	void reload(const SoundResource& new_sr)
	{
		destroy();
		create(new_sr, position());
	}

	void play(bool loop, f32 volume)
	{
		set_volume(volume);
		AL_CHECK(alSourcei(_source, AL_LOOPING, (loop ? AL_TRUE : AL_FALSE)));
		AL_CHECK(alSourceQueueBuffers(_source, 1, &_buffer));
		AL_CHECK(alSourcePlay(_source));
	}

	void pause()
	{
		AL_CHECK(alSourcePause(_source));
	}

	void resume()
	{
		AL_CHECK(alSourcePlay(_source));
	}

	void stop()
	{
		AL_CHECK(alSourceStop(_source));
		AL_CHECK(alSourceRewind(_source)); // Workaround
		ALint processed;
		AL_CHECK(alGetSourcei(_source, AL_BUFFERS_PROCESSED, &processed));

		if (processed > 0)
		{
			ALuint removed;
			AL_CHECK(alSourceUnqueueBuffers(_source, 1, &removed));
		}
	}

	bool is_playing()
	{
		ALint state;
		AL_CHECK(alGetSourcei(_source, AL_SOURCE_STATE, &state));
		return state == AL_PLAYING;
	}

	bool finished()
	{
		ALint state;
		AL_CHECK(alGetSourcei(_source, AL_SOURCE_STATE, &state));
		return (state != AL_PLAYING && state != AL_PAUSED);
	}

	Vector3 position()
	{
		ALfloat pos[3];
		AL_CHECK(alGetSourcefv(_source, AL_POSITION, pos));
		return vector3(pos[0], pos[1], pos[2]);
	}

	void set_position(const Vector3& pos)
	{
		AL_CHECK(alSourcefv(_source, AL_POSITION, to_float_ptr(pos)));
	}

	void set_range(f32 range)
	{
		AL_CHECK(alSourcef(_source, AL_MAX_DISTANCE, range));
	}

	void set_volume(f32 volume)
	{
		AL_CHECK(alSourcef(_source, AL_GAIN, volume));
	}

	const SoundResource* resource()
	{
		return _resource;
	}

public:

	const SoundResource* _resource;
	SoundInstanceId _id;
	ALuint _buffer;
	ALuint _source;
};

#define MAX_OBJECTS       1024
#define INDEX_MASK        0xffff
#define NEW_OBJECT_ID_ADD 0x10000

class ALSoundWorld : public SoundWorld
{
	struct Index
	{
		SoundInstanceId id;
		u16 index;
		u16 next;
	};

	u32 _num_objects;
	SoundInstance _playing_sounds[MAX_OBJECTS];
	Index _indices[MAX_OBJECTS];
	u16 _freelist_enqueue;
	u16 _freelist_dequeue;
	Matrix4x4 _listener_pose;

	bool has(SoundInstanceId id)
	{
		Index& in = _indices[id & INDEX_MASK];
		return in.id == id && in.index != UINT16_MAX;
	}

	SoundInstance& lookup(SoundInstanceId id)
	{
		return _playing_sounds[_indices[id & INDEX_MASK].index];
	}

	SoundInstanceId add()
	{
		Index& in = _indices[_freelist_dequeue];
		_freelist_dequeue = in.next;
		in.id += NEW_OBJECT_ID_ADD;
		in.index = _num_objects++;
		SoundInstance& o = _playing_sounds[in.index];
		o._id = in.id;
		return o._id;
	}

	void remove(SoundInstanceId id)
	{
		Index& in = _indices[id & INDEX_MASK];

		SoundInstance& o = _playing_sounds[in.index];
		o = _playing_sounds[--_num_objects];
		_indices[o._id & INDEX_MASK].index = in.index;

		in.index = UINT16_MAX;
		_indices[_freelist_enqueue].next = id & INDEX_MASK;
		_freelist_enqueue = id & INDEX_MASK;
	}

public:

	ALSoundWorld()
	{
		_num_objects = 0;
		for (u32 i = 0; i < MAX_OBJECTS; ++i)
		{
			_indices[i].id = i;
			_indices[i].next = i + 1;
		}
		_freelist_dequeue = 0;
		_freelist_enqueue = MAX_OBJECTS - 1;

		set_listener_pose(MATRIX4X4_IDENTITY);
	}

	virtual ~ALSoundWorld()
	{
	}

	virtual SoundInstanceId play(const SoundResource& sr, bool loop, f32 volume, const Vector3& pos)
	{
		SoundInstanceId id = add();
		SoundInstance& si = lookup(id);
		si.create(sr, pos);
		si.play(loop, volume);
		return id;
	}

	virtual void stop(SoundInstanceId id)
	{
		SoundInstance& si = lookup(id);
		si.destroy();
		remove(id);
	}

	virtual bool is_playing(SoundInstanceId id)
	{
		return has(id) && lookup(id).is_playing();
	}

	virtual void stop_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].stop();
		}
	}

	virtual void pause_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].pause();
		}
	}

	virtual void resume_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].resume();
		}
	}

	virtual void set_sound_positions(u32 num, const SoundInstanceId* ids, const Vector3* positions)
	{
		for (u32 i = 0; i < num; ++i)
		{
			lookup(ids[i]).set_position(positions[i]);
		}
	}

	virtual void set_sound_ranges(u32 num, const SoundInstanceId* ids, const f32* ranges)
	{
		for (u32 i = 0; i < num; ++i)
		{
			lookup(ids[i]).set_range(ranges[i]);
		}
	}

	virtual void set_sound_volumes(u32 num, const SoundInstanceId* ids, const f32* volumes)
	{
		for (u32 i = 0; i < num; i++)
		{
			lookup(ids[i]).set_volume(volumes[i]);
		}
	}

	virtual void reload_sounds(const SoundResource& old_sr, const SoundResource& new_sr)
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			if (_playing_sounds[i].resource() == &old_sr)
			{
				_playing_sounds[i].reload(new_sr);
			}
		}
	}

	virtual void set_listener_pose(const Matrix4x4& pose)
	{
		const Vector3 pos = translation(pose);
		const Vector3 up = y(pose);
		const Vector3 at = z(pose);

		AL_CHECK(alListener3f(AL_POSITION, pos.x, pos.y, pos.z));
		//AL_CHECK(alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z));

		const ALfloat orientation[] = { up.x, up.y, up.z, at.x, at.y, at.z };
		AL_CHECK(alListenerfv(AL_ORIENTATION, orientation));
		_listener_pose = pose;
	}

	virtual void update()
	{
		TempAllocator256 alloc;
		Array<SoundInstanceId> to_delete(alloc);

		// Check what sounds finished playing
		for (u32 i = 0; i < _num_objects; ++i)
		{
			SoundInstance& instance = _playing_sounds[i];
			if (instance.finished())
			{
				array::push_back(to_delete, instance._id);
			}
		}

		// Destroy instances which finished playing
		for (u32 i = 0; i < array::size(to_delete); ++i)
		{
			stop(to_delete[i]);
		}
	}
};

namespace sound_world
{
	SoundWorld* create(Allocator& a)
	{
		return CE_NEW(a, ALSoundWorld)();
	}

	void destroy(Allocator& a, SoundWorld* sw)
	{
		CE_DELETE(a, sw);
	}
} // namespace sound_world

} // namespace crown

#endif // CROWN_SOUND_OPENAL
<commit_msg>Cleanup<commit_after>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"

#if CROWN_SOUND_OPENAL

#include "array.h"
#include "audio.h"
#include "log.h"
#include "matrix4x4.h"
#include "sound_resource.h"
#include "sound_world.h"
#include "temp_allocator.h"
#include "vector3.h"
#include <AL/al.h>
#include <AL/alc.h>

namespace crown
{
#if CROWN_DEBUG
	static const char* al_error_to_string(ALenum error)
	{
		switch (error)
		{
			case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
			case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
			case AL_INVALID_OPERATION: return "AL_INVALID_OPERATION";
			case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
			default: return "UNKNOWN_AL_ERROR";
		}
	}

	#define AL_CHECK(function)\
		function;\
		do { ALenum error; CE_ASSERT((error = alGetError()) == AL_NO_ERROR,\
				"OpenAL error: %s", al_error_to_string(error)); } while (0)
#else
	#define AL_CHECK(function) function
#endif // CROWN_DEBUG

/// Global audio-related functions
namespace audio_globals
{
	static ALCdevice* s_al_device;
	static ALCcontext* s_al_context;

	void init()
	{
		s_al_device = alcOpenDevice(NULL);
		CE_ASSERT(s_al_device, "Cannot open OpenAL audio device");

		s_al_context = alcCreateContext(s_al_device, NULL);
		CE_ASSERT(s_al_context, "Cannot create OpenAL context");

		AL_CHECK(alcMakeContextCurrent(s_al_context));

		CE_LOGD("OpenAL Vendor   : %s", alGetString(AL_VENDOR));
		CE_LOGD("OpenAL Version  : %s", alGetString(AL_VERSION));
		CE_LOGD("OpenAL Renderer : %s", alGetString(AL_RENDERER));

		AL_CHECK(alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED));
		AL_CHECK(alDopplerFactor(1.0f));
		AL_CHECK(alDopplerVelocity(343.0f));
	}

	void shutdown()
	{
		alcDestroyContext(s_al_context);
	    alcCloseDevice(s_al_device);
	}
}

struct SoundInstance
{
	void create(const SoundResource& sr, const Vector3& pos)
	{
		using namespace sound_resource;

		AL_CHECK(alGenSources(1, &_source));
		CE_ASSERT(alIsSource(_source), "alGenSources: error");

		// AL_CHECK(alSourcef(_source, AL_PITCH, 1.0f));
		// AL_CHECK(alSourcef(_source, AL_REFERENCE_DISTANCE, 0.1f));
		// AL_CHECK(alSourcef(_source, AL_MAX_DISTANCE, 1000.0f));

		// Generates AL buffers
		AL_CHECK(alGenBuffers(1, &_buffer));
		CE_ASSERT(alIsBuffer(_buffer), "alGenBuffers: error");

		ALenum fmt = AL_INVALID_ENUM;
		switch (sr.bits_ps)
		{
			case  8: fmt = sr.channels > 1 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8; break;
			case 16: fmt = sr.channels > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; break;
			default: CE_FATAL("Number of bits per sample not supported."); break;
		}
		AL_CHECK(alBufferData(_buffer, fmt, data(&sr), sr.size, sr.sample_rate));

		_resource = &sr;
		set_position(pos);
	}

	void destroy()
	{
		stop();
		AL_CHECK(alSourcei(_source, AL_BUFFER, 0));
		AL_CHECK(alDeleteBuffers(1, &_buffer));
		AL_CHECK(alDeleteSources(1, &_source));
	}

	void reload(const SoundResource& new_sr)
	{
		destroy();
		create(new_sr, position());
	}

	void play(bool loop, f32 volume)
	{
		set_volume(volume);
		AL_CHECK(alSourcei(_source, AL_LOOPING, (loop ? AL_TRUE : AL_FALSE)));
		AL_CHECK(alSourceQueueBuffers(_source, 1, &_buffer));
		AL_CHECK(alSourcePlay(_source));
	}

	void pause()
	{
		AL_CHECK(alSourcePause(_source));
	}

	void resume()
	{
		AL_CHECK(alSourcePlay(_source));
	}

	void stop()
	{
		AL_CHECK(alSourceStop(_source));
		AL_CHECK(alSourceRewind(_source)); // Workaround
		ALint processed;
		AL_CHECK(alGetSourcei(_source, AL_BUFFERS_PROCESSED, &processed));

		if (processed > 0)
		{
			ALuint removed;
			AL_CHECK(alSourceUnqueueBuffers(_source, 1, &removed));
		}
	}

	bool is_playing()
	{
		ALint state;
		AL_CHECK(alGetSourcei(_source, AL_SOURCE_STATE, &state));
		return state == AL_PLAYING;
	}

	bool finished()
	{
		ALint state;
		AL_CHECK(alGetSourcei(_source, AL_SOURCE_STATE, &state));
		return (state != AL_PLAYING && state != AL_PAUSED);
	}

	Vector3 position()
	{
		ALfloat pos[3];
		AL_CHECK(alGetSourcefv(_source, AL_POSITION, pos));
		return vector3(pos[0], pos[1], pos[2]);
	}

	void set_position(const Vector3& pos)
	{
		AL_CHECK(alSourcefv(_source, AL_POSITION, to_float_ptr(pos)));
	}

	void set_range(f32 range)
	{
		AL_CHECK(alSourcef(_source, AL_MAX_DISTANCE, range));
	}

	void set_volume(f32 volume)
	{
		AL_CHECK(alSourcef(_source, AL_GAIN, volume));
	}

	const SoundResource* resource()
	{
		return _resource;
	}

public:

	const SoundResource* _resource;
	SoundInstanceId _id;
	ALuint _buffer;
	ALuint _source;
};

#define MAX_OBJECTS       1024
#define INDEX_MASK        0xffff
#define NEW_OBJECT_ID_ADD 0x10000

class ALSoundWorld : public SoundWorld
{
	struct Index
	{
		SoundInstanceId id;
		u16 index;
		u16 next;
	};

	u32 _num_objects;
	SoundInstance _playing_sounds[MAX_OBJECTS];
	Index _indices[MAX_OBJECTS];
	u16 _freelist_enqueue;
	u16 _freelist_dequeue;
	Matrix4x4 _listener_pose;

	bool has(SoundInstanceId id)
	{
		Index& in = _indices[id & INDEX_MASK];
		return in.id == id && in.index != UINT16_MAX;
	}

	SoundInstance& lookup(SoundInstanceId id)
	{
		return _playing_sounds[_indices[id & INDEX_MASK].index];
	}

	SoundInstanceId add()
	{
		Index& in = _indices[_freelist_dequeue];
		_freelist_dequeue = in.next;
		in.id += NEW_OBJECT_ID_ADD;
		in.index = _num_objects++;
		SoundInstance& o = _playing_sounds[in.index];
		o._id = in.id;
		return o._id;
	}

	void remove(SoundInstanceId id)
	{
		Index& in = _indices[id & INDEX_MASK];

		SoundInstance& o = _playing_sounds[in.index];
		o = _playing_sounds[--_num_objects];
		_indices[o._id & INDEX_MASK].index = in.index;

		in.index = UINT16_MAX;
		_indices[_freelist_enqueue].next = id & INDEX_MASK;
		_freelist_enqueue = id & INDEX_MASK;
	}

public:

	ALSoundWorld()
	{
		_num_objects = 0;
		for (u32 i = 0; i < MAX_OBJECTS; ++i)
		{
			_indices[i].id = i;
			_indices[i].next = i + 1;
		}
		_freelist_dequeue = 0;
		_freelist_enqueue = MAX_OBJECTS - 1;

		set_listener_pose(MATRIX4X4_IDENTITY);
	}

	virtual ~ALSoundWorld()
	{
	}

	virtual SoundInstanceId play(const SoundResource& sr, bool loop, f32 volume, const Vector3& pos)
	{
		SoundInstanceId id = add();
		SoundInstance& si = lookup(id);
		si.create(sr, pos);
		si.play(loop, volume);
		return id;
	}

	virtual void stop(SoundInstanceId id)
	{
		SoundInstance& si = lookup(id);
		si.destroy();
		remove(id);
	}

	virtual bool is_playing(SoundInstanceId id)
	{
		return has(id) && lookup(id).is_playing();
	}

	virtual void stop_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].stop();
		}
	}

	virtual void pause_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].pause();
		}
	}

	virtual void resume_all()
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			_playing_sounds[i].resume();
		}
	}

	virtual void set_sound_positions(u32 num, const SoundInstanceId* ids, const Vector3* positions)
	{
		for (u32 i = 0; i < num; ++i)
		{
			lookup(ids[i]).set_position(positions[i]);
		}
	}

	virtual void set_sound_ranges(u32 num, const SoundInstanceId* ids, const f32* ranges)
	{
		for (u32 i = 0; i < num; ++i)
		{
			lookup(ids[i]).set_range(ranges[i]);
		}
	}

	virtual void set_sound_volumes(u32 num, const SoundInstanceId* ids, const f32* volumes)
	{
		for (u32 i = 0; i < num; i++)
		{
			lookup(ids[i]).set_volume(volumes[i]);
		}
	}

	virtual void reload_sounds(const SoundResource& old_sr, const SoundResource& new_sr)
	{
		for (u32 i = 0; i < _num_objects; ++i)
		{
			if (_playing_sounds[i].resource() == &old_sr)
			{
				_playing_sounds[i].reload(new_sr);
			}
		}
	}

	virtual void set_listener_pose(const Matrix4x4& pose)
	{
		const Vector3 pos = translation(pose);
		const Vector3 up = y(pose);
		const Vector3 at = z(pose);

		AL_CHECK(alListener3f(AL_POSITION, pos.x, pos.y, pos.z));
		//AL_CHECK(alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z));

		const ALfloat orientation[] = { up.x, up.y, up.z, at.x, at.y, at.z };
		AL_CHECK(alListenerfv(AL_ORIENTATION, orientation));
		_listener_pose = pose;
	}

	virtual void update()
	{
		TempAllocator256 alloc;
		Array<SoundInstanceId> to_delete(alloc);

		// Check what sounds finished playing
		for (u32 i = 0; i < _num_objects; ++i)
		{
			SoundInstance& instance = _playing_sounds[i];
			if (instance.finished())
			{
				array::push_back(to_delete, instance._id);
			}
		}

		// Destroy instances which finished playing
		for (u32 i = 0; i < array::size(to_delete); ++i)
		{
			stop(to_delete[i]);
		}
	}
};

namespace sound_world
{
	SoundWorld* create(Allocator& a)
	{
		return CE_NEW(a, ALSoundWorld)();
	}

	void destroy(Allocator& a, SoundWorld* sw)
	{
		CE_DELETE(a, sw);
	}
} // namespace sound_world

} // namespace crown

#endif // CROWN_SOUND_OPENAL
<|endoftext|>


<commit_before>/******************************************************************************
 *  Copyright (c) 2015 Jamis Hoo
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: sha2_512.cc
 *  Version: 1.0
 *  Author: Jamis Hoo
 *  E-mail: hoojamis@gmail.com
 *  Date: May 11, 2015
 *  Time: 22:13:27
 *  Description: SHA-2 (512 bit)
 *****************************************************************************/
#include <cstring>
#include <cinttypes>
#include <iostream>
#include <fstream>
#include <streambuf>

void sha2_iteration(const uint8_t* data, uint64_t hi[]) {
    // rotate function
    auto right_rotate = [](uint64_t x, const size_t i)->uint64_t {
        return x >> i | x << (sizeof(uint64_t) * 8 - i);
    };

    constexpr uint64_t k[80] = {
        0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
        0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
        0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
        0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
        0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
        0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
        0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
        0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
        0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
        0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
        0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
        0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
        0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
        0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
        0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
        0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
    };

    // extend 16 64-bit words to 80 64-bit words
    uint64_t word[80];
    for (size_t j = 0; j < 16; ++j)
        word[j] = uint64_t(data[8 * j + 0]) << 56 | uint64_t(data[8 * j + 1]) << 48 |
                  uint64_t(data[8 * j + 2]) << 40 | uint64_t(data[8 * j + 3]) << 32 |
                  uint64_t(data[8 * j + 4]) << 24 | uint64_t(data[8 * j + 5]) << 16 |
                  uint64_t(data[8 * j + 6]) <<  8 | uint64_t(data[8 * j + 7]) <<  0;

    for (size_t j = 16; j < 80; ++j) {
        uint64_t s0 = right_rotate(word[j - 15], 1) ^
                      right_rotate(word[j - 15], 8) ^
                      word[j - 15] >> 7;
        uint64_t s1 = right_rotate(word[j - 2], 19) ^
                      right_rotate(word[j - 2], 61) ^
                      word[j - 2] >> 6;
        word[j] = word[j - 16] + s0 + word[j - 7] + s1;
    }

    uint64_t a = hi[0], b = hi[1], c = hi[2], d = hi[3],
             e = hi[4], f = hi[5], g = hi[6], h = hi[7];

    // main loop
    for (size_t i = 0; i < 80; ++i) {
        uint64_t S1 = right_rotate(e, 14) ^
                      right_rotate(e, 18) ^
                      right_rotate(e, 41);
        uint64_t ch = (e & f) ^ (~e & g);
        uint64_t tmp1 = h + S1 + ch + k[i] + word[i];
        uint64_t S0 = right_rotate(a, 28) ^
                      right_rotate(a, 34) ^
                      right_rotate(a, 39);
        uint64_t maj = (a & b) ^ (a & c) ^ (b & c);
        uint64_t tmp2 = S0 + maj;

        h = g, g = f, f = e, e = d + tmp1, d = c, c = b, b = a, a = tmp1 + tmp2;
    }

    hi[0] += a, hi[1] += b, hi[2] += c, hi[3] += d,
    hi[4] += e, hi[5] += f, hi[6] += g, hi[7] += h;
}

// len: in bytes
// hash: at least 64 bytes available
void sha2(const void* data, size_t len, char* hash) {
    uint8_t* data_ = (uint8_t*)data;
    constexpr size_t block_size = 128;

    uint64_t h[8] = { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
                      0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
                      0x510e527fade682d1, 0x9b05688c2b3e6c1f,
                      0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 };

    size_t ml = len * 8;

    for (size_t i = 0; i < len / block_size; ++i)
        sha2_iteration(data_ + i * block_size, h);

    uint8_t buffer[block_size];

    memcpy(buffer, data_ + len / block_size * block_size, len % block_size);
    len %= block_size;

    // append bit '1'
    buffer[len++] = 0x80;

    if (len % block_size == 0) {
        sha2_iteration(buffer, h);
        len = 0;
    }

    // append until the resulting message length (in bits) is congruent to 896 (mod 1024)
    while (len % block_size != block_size - 16) {
        buffer[len++] = 0x00;
        if (len % block_size == 0) {
            sha2_iteration(buffer, h);
            len = 0;
        }
    }

    // append length

    while (len % block_size) {
        size_t shift_count = 120 - (len - block_size + 16) * 8;
        if (shift_count > sizeof(size_t) * 8)
            shift_count = sizeof(size_t) * 8;
        buffer[len] = ml >> shift_count;
        ++len;
    }

    // Code below may get a better performance on pipeline CPU than code above
    // because it has no branch instruction
    // But size_t is 64 bits long for now, so code below will lead to
    // undefined behavior.
    // When size_t is 128 bits long, replace code above with that below.

    // Plus, Please tell me if anybody knows how to concisely switch these
    // tow pieces of code according to width of size_t at compiling time.
    // Thanks.

    /*
    buffer[len++] = ml >> 120, buffer[len++] = ml >> 112,
    buffer[len++] = ml >> 104, buffer[len++] = ml >>  96,
    buffer[len++] = ml >>  88, buffer[len++] = ml >>  80,
    buffer[len++] = ml >>  72, buffer[len++] = ml >>  64,
    buffer[len++] = ml >>  56, buffer[len++] = ml >>  48,
    buffer[len++] = ml >>  40, buffer[len++] = ml >>  32,
    buffer[len++] = ml >>  24, buffer[len++] = ml >>  16,
    buffer[len++] = ml >>   8, buffer[len++] = ml;
    */

    sha2_iteration(buffer, h);

    /*
    for (size_t i = 0; i < 64; i += 8)
        hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16,
        hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4];
    */
    for (size_t i = 0; i < 64; i += 8)
        hash[i + 0] = h[i / 8] >> 56, hash[i + 1] = h[i / 8] >> 48,
        hash[i + 2] = h[i / 8] >> 40, hash[i + 3] = h[i / 8] >> 32,
        hash[i + 4] = h[i / 8] >> 24, hash[i + 5] = h[i / 8] >> 16,
        hash[i + 6] = h[i / 8] >>  8, hash[i + 7] = h[i / 8] >>  0;
}

int main(int argc, char** argv) {
    uint8_t hash[64];

    if (argc == 1) return 0;

    std::ifstream fin(argv[1]);

    fin.seekg(0, std::ios::end);
    std::string buffer;
    buffer.reserve(fin.tellg());
    fin.seekg(0, std::ios::beg);

    buffer.assign((std::istreambuf_iterator<char>(fin)),
                   std::istreambuf_iterator<char>());

    sha2(buffer.data(), buffer.length(), (char*)hash);

    for (int i = 0; i < 64; ++i)
        printf("%02x", int(hash[i]) & 0xff);
    printf("\n");

}
<commit_msg>fix bug<commit_after>/******************************************************************************
 *  Copyright (c) 2015 Jamis Hoo
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: sha2_512.cc
 *  Version: 1.0
 *  Author: Jamis Hoo
 *  E-mail: hoojamis@gmail.com
 *  Date: May 11, 2015
 *  Time: 22:13:27
 *  Description: SHA-2 (512 bit)
 *****************************************************************************/
#include <cstring>
#include <cinttypes>
#include <iostream>
#include <fstream>
#include <streambuf>

void sha2_iteration(const uint8_t* data, uint64_t hi[]) {
    // rotate function
    auto right_rotate = [](uint64_t x, const size_t i)->uint64_t {
        return x >> i | x << (sizeof(uint64_t) * 8 - i);
    };

    constexpr uint64_t k[80] = {
        0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
        0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
        0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
        0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
        0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
        0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
        0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
        0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
        0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
        0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
        0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
        0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
        0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
        0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
        0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
        0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
    };

    // extend 16 64-bit words to 80 64-bit words
    uint64_t word[80];
    for (size_t j = 0; j < 16; ++j)
        word[j] = uint64_t(data[8 * j + 0]) << 56 | uint64_t(data[8 * j + 1]) << 48 |
                  uint64_t(data[8 * j + 2]) << 40 | uint64_t(data[8 * j + 3]) << 32 |
                  uint64_t(data[8 * j + 4]) << 24 | uint64_t(data[8 * j + 5]) << 16 |
                  uint64_t(data[8 * j + 6]) <<  8 | uint64_t(data[8 * j + 7]) <<  0;

    for (size_t j = 16; j < 80; ++j) {
        uint64_t s0 = right_rotate(word[j - 15], 1) ^
                      right_rotate(word[j - 15], 8) ^
                      word[j - 15] >> 7;
        uint64_t s1 = right_rotate(word[j - 2], 19) ^
                      right_rotate(word[j - 2], 61) ^
                      word[j - 2] >> 6;
        word[j] = word[j - 16] + s0 + word[j - 7] + s1;
    }

    uint64_t a = hi[0], b = hi[1], c = hi[2], d = hi[3],
             e = hi[4], f = hi[5], g = hi[6], h = hi[7];

    // main loop
    for (size_t i = 0; i < 80; ++i) {
        uint64_t S1 = right_rotate(e, 14) ^
                      right_rotate(e, 18) ^
                      right_rotate(e, 41);
        uint64_t ch = (e & f) ^ (~e & g);
        uint64_t tmp1 = h + S1 + ch + k[i] + word[i];
        uint64_t S0 = right_rotate(a, 28) ^
                      right_rotate(a, 34) ^
                      right_rotate(a, 39);
        uint64_t maj = (a & b) ^ (a & c) ^ (b & c);
        uint64_t tmp2 = S0 + maj;

        h = g, g = f, f = e, e = d + tmp1, d = c, c = b, b = a, a = tmp1 + tmp2;
    }

    hi[0] += a, hi[1] += b, hi[2] += c, hi[3] += d,
    hi[4] += e, hi[5] += f, hi[6] += g, hi[7] += h;
}

// len: in bytes
// hash: at least 64 bytes available
void sha2(const void* data, size_t len, char* hash) {
    uint8_t* data_ = (uint8_t*)data;
    constexpr size_t block_size = 128;

    uint64_t h[8] = { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
                      0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
                      0x510e527fade682d1, 0x9b05688c2b3e6c1f,
                      0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 };

    size_t ml = len * 8;

    for (size_t i = 0; i < len / block_size; ++i)
        sha2_iteration(data_ + i * block_size, h);

    uint8_t buffer[block_size];

    memcpy(buffer, data_ + len / block_size * block_size, len % block_size);
    len %= block_size;

    // append bit '1'
    buffer[len++] = 0x80;

    if (len % block_size == 0) {
        sha2_iteration(buffer, h);
        len = 0;
    }

    // append until the resulting message length (in bits) is congruent to 896 (mod 1024)
    while (len % block_size != block_size - 16) {
        buffer[len++] = 0x00;
        if (len % block_size == 0) {
            sha2_iteration(buffer, h);
            len = 0;
        }
    }

    // append length

    while (len % block_size) {
        size_t shift_count = 120 - (len - block_size + 16) * 8;
        if (shift_count >= sizeof(size_t) * 8)
            buffer[len] = 0;
        else
            buffer[len] = ml >> shift_count;
        ++len;
    }

    // Code below may get a better performance on pipeline CPU than code above
    // because it has no branch instruction
    // But size_t is 64 bits long for now, so code below will lead to
    // undefined behavior.
    // When size_t is 128 bits long, replace code above with that below.

    // Plus, Please tell me if anybody knows how to concisely switch these
    // tow pieces of code according to width of size_t at compiling time.
    // Thanks.

    /*
    buffer[len++] = ml >> 120, buffer[len++] = ml >> 112,
    buffer[len++] = ml >> 104, buffer[len++] = ml >>  96,
    buffer[len++] = ml >>  88, buffer[len++] = ml >>  80,
    buffer[len++] = ml >>  72, buffer[len++] = ml >>  64,
    buffer[len++] = ml >>  56, buffer[len++] = ml >>  48,
    buffer[len++] = ml >>  40, buffer[len++] = ml >>  32,
    buffer[len++] = ml >>  24, buffer[len++] = ml >>  16,
    buffer[len++] = ml >>   8, buffer[len++] = ml;
    */

    sha2_iteration(buffer, h);

    /*
    for (size_t i = 0; i < 64; i += 8)
        hash[i] = h[i / 4] >> 24, hash[i + 1] = h[i / 4] >> 16,
        hash[i + 2] = h[i / 4] >> 8, hash[i + 3] = h[i / 4];
    */
    for (size_t i = 0; i < 64; i += 8)
        hash[i + 0] = h[i / 8] >> 56, hash[i + 1] = h[i / 8] >> 48,
        hash[i + 2] = h[i / 8] >> 40, hash[i + 3] = h[i / 8] >> 32,
        hash[i + 4] = h[i / 8] >> 24, hash[i + 5] = h[i / 8] >> 16,
        hash[i + 6] = h[i / 8] >>  8, hash[i + 7] = h[i / 8] >>  0;
}

int main(int argc, char** argv) {
    uint8_t hash[64];

    if (argc == 1) return 0;

    std::ifstream fin(argv[1]);

    fin.seekg(0, std::ios::end);
    std::string buffer;
    buffer.reserve(fin.tellg());
    fin.seekg(0, std::ios::beg);

    buffer.assign((std::istreambuf_iterator<char>(fin)),
                   std::istreambuf_iterator<char>());

    sha2(buffer.data(), buffer.length(), (char*)hash);

    for (int i = 0; i < 64; ++i)
        printf("%02x", int(hash[i]) & 0xff);
    printf("\n");

}
<|endoftext|>


<commit_before>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2015 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

// #include <xerus.h>
#include <xerus/algorithms/als.h>
#include <xerus/basic.h>
#include <xerus/indexedTensorList.h>
#include <xerus/tensorNetwork.h>
#include <xerus/indexedTensor_TN_operators.h>
#include <xerus/indexedTensor_tensor_operators.h>
#include <xerus/indexedTensor_tensor_factorisations.h>

namespace xerus {

    void ALSVariant::lapack_solver(const TensorNetwork &_A, Tensor &_x, const Tensor &_b) {
        const size_t d = _x.degree();
        FullTensor A(_A);
        Index i,j;
        _x(i^d) = _b(j^d) / A(j^d, i^d);
        REQUIRE(d <= 3, "dmrg not yet implemented in lapack_solver");// TODO split result into d-2 tensors -> choose correct tensor as core!
    }

    double ALSVariant::operator()(const TTOperator &_A, TTTensor &_x, const TTTensor &_b, value_t _convergenceEpsilon,  std::vector<value_t> *_perfData) const {
        LOG(ALS, "ALS("<< sites << ", " << minimumLocalResidual <<") called");
		#ifndef DISABLE_RUNTIME_CHECKS_
			REQUIRE(_x.degree() > 0, "");
			REQUIRE(_x.dimensions == _b.dimensions, "");
			REQUIRE(_A.dimensions.size() == _b.dimensions.size()*2, "");
			REQUIRE(sites == 1, "DMRG and n-site-dmrg not yet implemented!"); // TODO release critical?

			for (size_t i=0; i<_x.dimensions.size(); ++i) {
				REQUIRE(_A.dimensions[i] == _x.dimensions[i], "");
				REQUIRE(_A.dimensions[i+_A.degree()/2] == _x.dimensions[i], "");
			}
        #endif

        const size_t d = _x.degree();
        Index cr1, cr2, cr3, r1, r2, r3, n1, n2;

        std::vector<FullTensor> xAxL, xAxR;
        std::vector<FullTensor> bxL, bxR;

        _x.cannonicalize_left();

        // Create stack of contracted network-parts left part
		FullTensor tmpA;
		FullTensor tmpB;

        tmpA(r1, r2, r3) = (*_x.nodes[0].tensorObject)(r1) * (*_A.nodes[0].tensorObject)(r2) * (*_x.nodes[0].tensorObject)(r3);
		xAxL.emplace_back(tmpA);

		tmpB(r1, r2) = (*_b.nodes[0].tensorObject)(r1) * (*_x.nodes[0].tensorObject)(r2);
		bxL.emplace_back(tmpB);

        // Create stack of contracted network-parts right part
        tmpA(r1, r2, r3) = (*_x.nodes[d+1].tensorObject)(r1) * (*_A.nodes[d+1].tensorObject)(r2) * (*_x.nodes[d+1].tensorObject)(r3);
		xAxR.emplace_back(tmpA);

		tmpB(r1, r2) = (*_b.nodes[d+1].tensorObject)(r1) * (*_x.nodes[d+1].tensorObject)(r2);
		bxR.emplace_back(tmpB);

        for (size_t i = _x.degree()-1; i > sites-1; --i) {
			tmpA(r1, r2, r3) = tmpA(cr1, cr2, cr3) * _x.get_component(i)(r1, n1, cr1) * _A.get_component(i)(r2, n1, n2, cr2) * _x.get_component(i)(r3, n2, cr3);
			tmpB(r1, r2) = tmpB(cr1, cr2) * _b.get_component(i)(r1, n1, cr1) * _x.get_component(i)(r2, n1, cr2);
            xAxR.emplace_back(tmpA);
            bxR.emplace_back(tmpB);
        }

        // Calculate initial residual
        if (_perfData != nullptr) {
            _perfData->push_back(frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0)));
            LOG(ALS, "calculated residual for perfData: " << _perfData->back());
        }

        TensorNetwork ATilde;
        FullTensor BTilde;
        value_t lastEnergy2 = 1e102;
        value_t lastEnergy = 1e101;
        value_t energy = 1e100;
        bool walkingRight = true;
        bool changedSmth = false;
        size_t currIndex = 0;
        while (true) {
			LOG(ALS, "Starting to optimize index " << currIndex);

			// Move core into position
			_x.move_core(currIndex);

			// Calculate Atilde and Btilde
			ATilde(r1,n1,cr1, r3,n2,cr3) = xAxL.back()(r1,r2,r3) * _A.get_component(currIndex)(r2, n1, n2, cr2) * xAxR.back()(cr1, cr2, cr3);
			BTilde(r2,n1,cr2) = bxL.back()(r1,r2) * _b.get_component(currIndex)(r1, n1, cr1) * bxR.back()(cr1,cr2);

			// Change component tensor if the local residual is large enough
			if (minimumLocalResidual <= 0 || frob_norm(IndexedTensorMoveable<Tensor>(ATilde(r1^3, r2^3)*X(currIndex)(r2^3)) - BTilde(r1^3)) > minimumLocalResidual) {
				FullTensor tmpX;
				localSolver(ATilde, tmpX, BTilde);
				_x.set_component(currIndex, tmpX);
				changedSmth = true;
			}

            if (_perfData != nullptr) {
                _perfData->push_back(frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0)));
                LOG(ALS, "Calculated residual for perfData after tensor "<< currIndex <<": " << _perfData->back() << " ( " << std::abs(_perfData->back() - energy) << " vs " << _convergenceEpsilon << " ) ");
                if (printProgress) {
                    std::cout << "optimized tensor "<< currIndex << ": " << _perfData->back() << " ( \t" << std::abs(_perfData->back() - energy) << " vs \t" << _convergenceEpsilon << " ) \r" << std::flush;
                }
            }

            // Are we done with the sweep?
            if ((!walkingRight && currIndex==0) || (walkingRight && currIndex==d-sites)) {
                LOG(ALS, "Sweep Done");

                lastEnergy2 = lastEnergy;
                lastEnergy = energy;
                if (_perfData != nullptr) {
                    energy = _perfData->back(); // Energy already calculated
                } else {
                    LOG(ALS, "Calculating energy for loop condition");
                    energy = frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0));
                }

                LOG(ALS, "Stats: " << xAxL.size() << " " << xAxR.size() << " " << bxL.size() << " " << bxR.size() << " energy: " << energy << " deltas: " << (1-lastEnergy/energy) << " " << (1-lastEnergy2/energy));

                // Conditions for loop termination
                if (!changedSmth || std::abs(lastEnergy-energy) < _convergenceEpsilon || std::abs(lastEnergy2-energy) < _convergenceEpsilon || d<=sites) {
                    // we are done! yay
                    LOG(ALS, "ALS done, " << energy << " " << lastEnergy << " " << std::abs(lastEnergy2-energy) << " " << std::abs(lastEnergy-energy) << " < " << _convergenceEpsilon);
					_x.cannonicalize_left();
                    return energy;
                }

                walkingRight = !walkingRight;
                changedSmth = false;
                LOG(ALS, "Start sweep " << (walkingRight?"right":"left"));
            }

            if (walkingRight) {
                // Move one site to the right
                xAxR.pop_back();
                bxR.pop_back();

                LOG(ALS, "Calc xAxL");
				tmpA(r1,r2,r3) = xAxL.back()(cr1,cr2,cr3) * _x.get_component(currIndex)(cr1,n1,r1) * _A.get_component(currIndex)(cr2, n1, n2, r2) * _x.get_component(currIndex)(cr3,n2,r3);
                xAxL.emplace_back(std::move(tmpA));

                LOG(ALS, "Calc BxL");
				tmpB(r1,r2) = bxL.back()(cr1,cr2) * _b.get_component(currIndex)(cr1, n1, r1) * _x.get_component(currIndex)(cr2, n1, r2);
                bxL.emplace_back(std::move(tmpB));
                currIndex++;;
            } else {
                // move one site to the left
                xAxL.pop_back();
                bxL.pop_back();

                LOG(ALS, "Calc xAxR");
				tmpA(r1,r2,r3) = xAxR.back()(cr1,cr2,cr3) * _x.get_component(currIndex)(r1,n1,cr1) * _A.get_component(currIndex)(r2, n1, n2, cr2) * _x.get_component(currIndex)(r3,n2,cr3);
                xAxR.emplace_back(std::move(tmpA));

                LOG(ALS, "Calc bxR");
				tmpB(r1,r2) = bxR.back()(cr1,cr2) * _b.get_component(currIndex)(r1, n1, cr1) * _x.get_component(currIndex)(r2, n1, cr2);
                bxR.emplace_back(std::move(tmpB));
                currIndex--;
            }
        }
    }
}
<commit_msg>Minor als fix<commit_after>// Xerus - A General Purpose Tensor Library
// Copyright (C) 2014-2015 Benjamin Huber and Sebastian Wolf.
//
// Xerus is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// Xerus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Xerus. If not, see <http://www.gnu.org/licenses/>.
//
// For further information on Xerus visit https://libXerus.org
// or contact us at contact@libXerus.org.

// #include <xerus.h>
#include <xerus/algorithms/als.h>
#include <xerus/basic.h>
#include <xerus/indexedTensorList.h>
#include <xerus/tensorNetwork.h>
#include <xerus/indexedTensor_TN_operators.h>
#include <xerus/indexedTensor_tensor_operators.h>
#include <xerus/indexedTensor_tensor_factorisations.h>

namespace xerus {

    void ALSVariant::lapack_solver(const TensorNetwork &_A, Tensor &_x, const Tensor &_b) {
        const size_t d = _x.degree();
        FullTensor A(_A);
        Index i,j;
        _x(i^d) = _b(j^d) / A(j^d, i^d);
        REQUIRE(d <= 3, "dmrg not yet implemented in lapack_solver");// TODO split result into d-2 tensors -> choose correct tensor as core!
    }

    double ALSVariant::operator()(const TTOperator &_A, TTTensor &_x, const TTTensor &_b, value_t _convergenceEpsilon,  std::vector<value_t> *_perfData) const {
        LOG(ALS, "ALS("<< sites << ", " << minimumLocalResidual <<") called");
		#ifndef DISABLE_RUNTIME_CHECKS_
			REQUIRE(_x.degree() > 0, "");
			REQUIRE(_x.dimensions == _b.dimensions, "");
			REQUIRE(_A.dimensions.size() == _b.dimensions.size()*2, "");
			REQUIRE(sites == 1, "DMRG and n-site-dmrg not yet implemented!"); // TODO release critical?

			for (size_t i=0; i<_x.dimensions.size(); ++i) {
				REQUIRE(_A.dimensions[i] == _x.dimensions[i], "");
				REQUIRE(_A.dimensions[i+_A.degree()/2] == _x.dimensions[i], "");
			}
        #endif

        const size_t d = _x.degree();
        Index cr1, cr2, cr3, r1, r2, r3, n1, n2;

        std::vector<FullTensor> xAxL, xAxR;
        std::vector<FullTensor> bxL, bxR;

        _x.cannonicalize_left();

        // Create stack of contracted network-parts left part
		FullTensor tmpA;
		FullTensor tmpB;

        tmpA(r1, r2, r3) = (*_x.nodes[0].tensorObject)(r1) * (*_A.nodes[0].tensorObject)(r2) * (*_x.nodes[0].tensorObject)(r3);
		xAxL.emplace_back(tmpA);

		tmpB(r1, r2) = (*_b.nodes[0].tensorObject)(r1) * (*_x.nodes[0].tensorObject)(r2);
		bxL.emplace_back(tmpB);

        // Create stack of contracted network-parts right part
        tmpA(r1, r2, r3) = (*_x.nodes[d+1].tensorObject)(r1) * (*_A.nodes[d+1].tensorObject)(r2) * (*_x.nodes[d+1].tensorObject)(r3);
		xAxR.emplace_back(tmpA);

		tmpB(r1, r2) = (*_b.nodes[d+1].tensorObject)(r1) * (*_x.nodes[d+1].tensorObject)(r2);
		bxR.emplace_back(tmpB);

        for (size_t i = _x.degree()-1; i > sites-1; --i) {
			tmpA(r1, r2, r3) = tmpA(cr1, cr2, cr3) * _x.get_component(i)(r1, n1, cr1) * _A.get_component(i)(r2, n1, n2, cr2) * _x.get_component(i)(r3, n2, cr3);
			tmpB(r1, r2) = tmpB(cr1, cr2) * _b.get_component(i)(r1, n1, cr1) * _x.get_component(i)(r2, n1, cr2);
            xAxR.emplace_back(tmpA);
            bxR.emplace_back(tmpB);
        }

        // Calculate initial residual
        if (_perfData != nullptr) {
            _perfData->push_back(frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0)));
            LOG(ALS, "calculated residual for perfData: " << _perfData->back());
        }

        TensorNetwork ATilde;
        FullTensor BTilde;
        value_t lastEnergy2 = 1e102;
        value_t lastEnergy = 1e101;
        value_t energy = 1e100;
        bool walkingRight = true;
        bool changedSmth = false;
        size_t currIndex = 0;
        while (true) {
			LOG(ALS, "Starting to optimize index " << currIndex);

			// Move core into position
			_x.move_core(currIndex);

			// Calculate Atilde and Btilde
			ATilde(r1,n1,cr1, r3,n2,cr3) = xAxL.back()(r1,r2,r3) * _A.get_component(currIndex)(r2, n1, n2, cr2) * xAxR.back()(cr1, cr2, cr3);
			BTilde(r2,n1,cr2) = bxL.back()(r1,r2) * _b.get_component(currIndex)(r1, n1, cr1) * bxR.back()(cr1,cr2);

			// Change component tensor if the local residual is large enough
			if (minimumLocalResidual <= 0 || frob_norm(IndexedTensorMoveable<Tensor>(ATilde(r1^3, r2^3)*_x.get_component(currIndex)(r2^3)) - BTilde(r1^3)) > minimumLocalResidual) {
				FullTensor tmpX;
				localSolver(ATilde, tmpX, BTilde);
				_x.set_component(currIndex, tmpX);
				changedSmth = true;
			}

            if (_perfData != nullptr) {
                _perfData->push_back(frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0)));
                LOG(ALS, "Calculated residual for perfData after tensor "<< currIndex <<": " << _perfData->back() << " ( " << std::abs(_perfData->back() - energy) << " vs " << _convergenceEpsilon << " ) ");
                if (printProgress) {
                    std::cout << "optimized tensor "<< currIndex << ": " << _perfData->back() << " ( \t" << std::abs(_perfData->back() - energy) << " vs \t" << _convergenceEpsilon << " ) \r" << std::flush;
                }
            }

            // Are we done with the sweep?
            if ((!walkingRight && currIndex==0) || (walkingRight && currIndex==d-sites)) {
                LOG(ALS, "Sweep Done");

                lastEnergy2 = lastEnergy;
                lastEnergy = energy;
                if (_perfData != nullptr) {
                    energy = _perfData->back(); // Energy already calculated
                } else {
                    LOG(ALS, "Calculating energy for loop condition");
                    energy = frob_norm(_A(n1/2,n2/2)*_x(n2&0) - _b(n1&0));
                }

                LOG(ALS, "Stats: " << xAxL.size() << " " << xAxR.size() << " " << bxL.size() << " " << bxR.size() << " energy: " << energy << " deltas: " << (1-lastEnergy/energy) << " " << (1-lastEnergy2/energy));

                // Conditions for loop termination
                if (!changedSmth || std::abs(lastEnergy-energy) < _convergenceEpsilon || std::abs(lastEnergy2-energy) < _convergenceEpsilon || d<=sites) {
                    // we are done! yay
                    LOG(ALS, "ALS done, " << energy << " " << lastEnergy << " " << std::abs(lastEnergy2-energy) << " " << std::abs(lastEnergy-energy) << " < " << _convergenceEpsilon);
					_x.cannonicalize_left();
                    return energy;
                }

                walkingRight = !walkingRight;
                changedSmth = false;
                LOG(ALS, "Start sweep " << (walkingRight?"right":"left"));
            }

            if (walkingRight) {
                // Move one site to the right
                xAxR.pop_back();
                bxR.pop_back();

                LOG(ALS, "Calc xAxL");
				tmpA(r1,r2,r3) = xAxL.back()(cr1,cr2,cr3) * _x.get_component(currIndex)(cr1,n1,r1) * _A.get_component(currIndex)(cr2, n1, n2, r2) * _x.get_component(currIndex)(cr3,n2,r3);
                xAxL.emplace_back(std::move(tmpA));

                LOG(ALS, "Calc BxL");
				tmpB(r1,r2) = bxL.back()(cr1,cr2) * _b.get_component(currIndex)(cr1, n1, r1) * _x.get_component(currIndex)(cr2, n1, r2);
                bxL.emplace_back(std::move(tmpB));
                currIndex++;;
            } else {
                // move one site to the left
                xAxL.pop_back();
                bxL.pop_back();

                LOG(ALS, "Calc xAxR");
				tmpA(r1,r2,r3) = xAxR.back()(cr1,cr2,cr3) * _x.get_component(currIndex)(r1,n1,cr1) * _A.get_component(currIndex)(r2, n1, n2, cr2) * _x.get_component(currIndex)(r3,n2,cr3);
                xAxR.emplace_back(std::move(tmpA));

                LOG(ALS, "Calc bxR");
				tmpB(r1,r2) = bxR.back()(cr1,cr2) * _b.get_component(currIndex)(r1, n1, cr1) * _x.get_component(currIndex)(r2, n1, cr2);
                bxR.emplace_back(std::move(tmpB));
                currIndex--;
            }
        }
    }
}
<|endoftext|>


<commit_before>#include "Globals.h"
#include "Engine.h"
#include "ModuleRender.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "SDL/include/SDL.h"
#include <windows.h>
#include "GL/glew.h"
#include <gl/GL.h>
#include <gl/GLU.h>
#include "Cube.h"
#include "Sphere.h"
#include "Cylinder.h"
#include "Plane.h"
#include "ModuleEditorCamera.h"
#include "CoordinateArrows.h"
#include "IL/ilut_config.h"
#include "IL/il.h"
#include "IL/ilut.h"
#include "IL/ilu.h"

ModuleRender::ModuleRender()
{
}

// Destructor
ModuleRender::~ModuleRender()
{}

// Called before render is available
bool ModuleRender::Init()
{
	return true;
}

bool ModuleRender::Start()
{
	LOG("Creating Renderer context");
	bool ret = true;
	context = SDL_GL_CreateContext(App->window->window);

	if (context == nullptr)
	{
		LOG("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}
	else
	{
		GLenum err = glewInit();

		if (err != GLEW_OK)
		{
			LOG("Error initialising GLEW: %s", glewGetErrorString(err));
			return false;
		}

		LOG("Using Glew %s", glewGetString(GLEW_VERSION));
		LOG("Vendor: %s", glGetString(GL_VENDOR));
		LOG("Renderer: %s", glGetString(GL_RENDERER));
		LOG("OpenGL version supported %s", glGetString(GL_VERSION));
		LOG("GLSL: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		glClearDepth(1.0f);
		glClearColor(0, 0, 0, 1.f);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);
		glEnable(GL_LIGHTING);
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);

		int w, h;
		SDL_GetWindowSize(App->window->window, &w, &h);
		App->editorCamera->SetAspectRatio(float(w) / float(h));

		GLubyte checkImage[CHECKERS_WIDTH][CHECKERS_HEIGHT][4];

		//Check Image
		for (int i = 0; i < CHECKERS_WIDTH; i++) {
			for (int j = 0; j < CHECKERS_HEIGHT; j++) {
				int c = ((((i & 0x8) == 0) ^ (((j & 0x8)) == 0))) * 255;
				checkImage[i][j][0] = GLubyte(c);
				checkImage[i][j][1] = GLubyte(c);
				checkImage[i][j][2] = GLubyte(c);
				checkImage[i][j][3] = GLubyte(255);
			}
		}

		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		glGenTextures(1, &ImageName);
		glBindTexture(GL_TEXTURE_2D, ImageName);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CHECKERS_WIDTH, CHECKERS_HEIGHT,
			0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);

		// Activate DevIL (Move to TextureManager)
		ilInit();
		iluInit();
		ilutInit();

		// Enable OpenGL access to DevIL
		ilutRenderer(ILUT_OPENGL);
		ilutEnable(ILUT_OPENGL_CONV);

		lenaImage = ilutGLLoadImage("Lenna.png");

		Quat rotation_plane = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		Quat rotation_cube = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		//Quat rotation_sphere = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		Quat rotation_cylinder = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));

		objects.push_back(new Cube(float3(0.f, 0.f, -5.f), rotation_cube, ImageName));
		objects.push_back(new ::Plane(float3(0, 0.f, -5.f), rotation_plane, 60));
		objects.push_back(new Cube(float3(5.f, 0.f, -5.f), rotation_cube, lenaImage));
		objects.push_back(new ::Cylinder(float3(-2.f, 3.f, -5.f), rotation_cylinder, float3(0.f, 0.f, 25.f), 0.3f, 1.5));
		objects.push_back(new CoordinateArrows());

		//::Sphere sphere(float3(2, 2, -5.f), rotation_sphere, float3(25.f, 21.75f, 0), 1, 12, 24);
	}
	return ret;
}

update_status ModuleRender::PreUpdate()
{
	ModuleEditorCamera* camera = App->editorCamera;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glLoadMatrixf(camera->GetProjectionMatrix());

	if (App->input->GetWindowEvent(WE_RESIZE))
	{
		int w, h;
		SDL_GetWindowSize(App->window->window, &w, &h);
		camera->SetAspectRatio(float(w) / float(h));
		glViewport(0, 0, w, h);
	}

	glClearColor(0, 0, 0, 1.f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glLoadMatrixf(camera->GetViewMatrix());

	return UPDATE_CONTINUE;
}

// Called every draw update
update_status ModuleRender::Update()
{
	bool ret = true;

	for (std::list<Primitive*>::iterator it = objects.begin(); it != objects.end(); ++it)
		(*it)->Draw();

	return ret ? UPDATE_CONTINUE : UPDATE_ERROR;
}

update_status ModuleRender::PostUpdate()
{
	SDL_GL_SwapWindow(App->window->window);

	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleRender::CleanUp()
{
	LOG("Destroying renderer");

	//Destroy window
	if (context != nullptr)
	{
		SDL_GL_DeleteContext(context);
	}

	for (std::list<Primitive*>::iterator it = objects.begin(); it != objects.end(); ++it)
		RELEASE(*it);

	return true;
}

<commit_msg>Add Sphere again to the scene<commit_after>#include "Globals.h"
#include "Engine.h"
#include "ModuleRender.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "SDL/include/SDL.h"
#include <windows.h>
#include "GL/glew.h"
#include <gl/GL.h>
#include <gl/GLU.h>
#include "Cube.h"
#include "Sphere.h"
#include "Cylinder.h"
#include "Plane.h"
#include "ModuleEditorCamera.h"
#include "CoordinateArrows.h"
#include "IL/ilut_config.h"
#include "IL/il.h"
#include "IL/ilut.h"
#include "IL/ilu.h"

ModuleRender::ModuleRender()
{
}

// Destructor
ModuleRender::~ModuleRender()
{}

// Called before render is available
bool ModuleRender::Init()
{
	return true;
}

bool ModuleRender::Start()
{
	LOG("Creating Renderer context");
	bool ret = true;
	context = SDL_GL_CreateContext(App->window->window);

	if (context == nullptr)
	{
		LOG("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}
	else
	{
		GLenum err = glewInit();

		if (err != GLEW_OK)
		{
			LOG("Error initialising GLEW: %s", glewGetErrorString(err));
			return false;
		}

		LOG("Using Glew %s", glewGetString(GLEW_VERSION));
		LOG("Vendor: %s", glGetString(GL_VENDOR));
		LOG("Renderer: %s", glGetString(GL_RENDERER));
		LOG("OpenGL version supported %s", glGetString(GL_VERSION));
		LOG("GLSL: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		glClearDepth(1.0f);
		glClearColor(0, 0, 0, 1.f);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);
		glEnable(GL_LIGHTING);
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);

		int w, h;
		SDL_GetWindowSize(App->window->window, &w, &h);
		App->editorCamera->SetAspectRatio(float(w) / float(h));

		GLubyte checkImage[CHECKERS_WIDTH][CHECKERS_HEIGHT][4];

		//Check Image
		for (int i = 0; i < CHECKERS_WIDTH; i++) {
			for (int j = 0; j < CHECKERS_HEIGHT; j++) {
				int c = ((((i & 0x8) == 0) ^ (((j & 0x8)) == 0))) * 255;
				checkImage[i][j][0] = GLubyte(c);
				checkImage[i][j][1] = GLubyte(c);
				checkImage[i][j][2] = GLubyte(c);
				checkImage[i][j][3] = GLubyte(255);
			}
		}

		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		glGenTextures(1, &ImageName);
		glBindTexture(GL_TEXTURE_2D, ImageName);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CHECKERS_WIDTH, CHECKERS_HEIGHT,
			0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);

		// Activate DevIL (Move to TextureManager)
		ilInit();
		iluInit();
		ilutInit();

		// Enable OpenGL access to DevIL
		ilutRenderer(ILUT_OPENGL);
		ilutEnable(ILUT_OPENGL_CONV);

		lenaImage = ilutGLLoadImage("Lenna.png");

		Quat rotation_plane = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		Quat rotation_cube = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		Quat rotation_sphere = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));
		Quat rotation_cylinder = Quat::FromEulerXYZ(DEG2RAD(0.f), DEG2RAD(0.f), DEG2RAD(0.f));

		objects.push_back(new Cube(float3(0.f, 0.f, -5.f), rotation_cube, ImageName));
		objects.push_back(new ::Plane(float3(0, 0.f, -5.f), rotation_plane, 60));
		objects.push_back(new Cube(float3(5.f, 0.f, -5.f), rotation_cube, lenaImage));
		objects.push_back(new ::Cylinder(float3(-2.f, 3.f, -5.f), rotation_cylinder, float3(0.f, 0.f, 25.f), 0.3f, 1.5));
		objects.push_back(new ::Sphere(float3(2, 2, -5.f), rotation_sphere, float3(25.f, 21.75f, 0), 1, 12, 24));
		objects.push_back(new CoordinateArrows());
	}
	return ret;
}

update_status ModuleRender::PreUpdate()
{
	ModuleEditorCamera* camera = App->editorCamera;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glLoadMatrixf(camera->GetProjectionMatrix());

	if (App->input->GetWindowEvent(WE_RESIZE))
	{
		int w, h;
		SDL_GetWindowSize(App->window->window, &w, &h);
		camera->SetAspectRatio(float(w) / float(h));
		glViewport(0, 0, w, h);
	}

	glClearColor(0, 0, 0, 1.f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glLoadMatrixf(camera->GetViewMatrix());

	return UPDATE_CONTINUE;
}

// Called every draw update
update_status ModuleRender::Update()
{
	bool ret = true;

	for (std::list<Primitive*>::iterator it = objects.begin(); it != objects.end(); ++it)
		(*it)->Draw();

	return ret ? UPDATE_CONTINUE : UPDATE_ERROR;
}

update_status ModuleRender::PostUpdate()
{
	SDL_GL_SwapWindow(App->window->window);

	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleRender::CleanUp()
{
	LOG("Destroying renderer");

	//Destroy window
	if (context != nullptr)
	{
		SDL_GL_DeleteContext(context);
	}

	for (std::list<Primitive*>::iterator it = objects.begin(); it != objects.end(); ++it)
		RELEASE(*it);

	return true;
}

<|endoftext|>


<commit_before>#include "networkAudioStream.h"
#include "logging.h"

#include <array>
#include <opus.h>

NetworkAudioStream::NetworkAudioStream()
{
    sample_rate = 48000;

    //Reserve 10 seconds of playback in our buffers.
    samples.reserve(sample_rate * 10);
    playing_samples.reserve(sample_rate * 10);

    initialize(1, sample_rate);  //initialize the sound stream on 1 channel with 48000Hz. This needs to match the data in NetworkAudioRecorder

    int error = 0;
    decoder = opus_decoder_create(48000, 1, &error);
}

bool NetworkAudioStream::onGetData(sf::SoundStream::Chunk& data)
{
    sf::Lock lock(samples_lock);    //Get exclusive access to the samples vector.
    //Copy all new samples to the playback buffer. And clear our sample buffer.
    playing_samples = std::move(samples);
    samples.clear();

    data.samples = playing_samples.data();
    data.sampleCount = playing_samples.size();

    //Stop playback if the buffer is empty.
    return data.sampleCount > 0;
}

void NetworkAudioStream::onSeek(sf::Time timeOffset)
{
    //We cannot seek in the network audio stream.
}

void NetworkAudioStream::receivedPacketFromNetwork(const unsigned char* packet, int packet_size)
{
    std::array<int16_t, 2880> samples_buffer;
    int sample_count = opus_decode(decoder, packet, packet_size, samples_buffer.data(), samples_buffer.size(), 0);
    if (sample_count > 0)
    {
        sf::Lock lock(samples_lock);
        this->samples.insert(this->samples.end(), samples_buffer.begin(), samples_buffer.begin() + sample_count);
    }
    if (this->samples.size() > sample_rate / 10 && getStatus() == sf::SoundSource::Stopped) //Start playback when there is 0.1 second of data
    {
        play();
    }
}

void NetworkAudioStream::finalize()
{
    if (this->samples.size() > 0 && getStatus() == sf::SoundSource::Stopped)
    {
        play();
    }
}

bool NetworkAudioStream::isFinished()
{
    return getStatus() == sf::SoundSource::Stopped && this->samples.size() == 0;
}

void NetworkAudioStreamManager::start(int32_t id)
{
    streams[id] = std::unique_ptr<NetworkAudioStream>(new NetworkAudioStream());
}

void NetworkAudioStreamManager::receivedPacketFromNetwork(int32_t id, const unsigned char* packet, int packet_size)
{
    auto it = streams.find(id);
    if (it == streams.end())
        return;
    it->second->receivedPacketFromNetwork(packet, packet_size);
}

void NetworkAudioStreamManager::stop(int32_t id)
{
    auto it = streams.find(id);
    it->second->finalize();
}
<commit_msg>Prevent a crash if we only see a network stream stop, but no start<commit_after>#include "networkAudioStream.h"
#include "logging.h"

#include <array>
#include <opus.h>

NetworkAudioStream::NetworkAudioStream()
{
    sample_rate = 48000;

    //Reserve 10 seconds of playback in our buffers.
    samples.reserve(sample_rate * 10);
    playing_samples.reserve(sample_rate * 10);

    initialize(1, sample_rate);  //initialize the sound stream on 1 channel with 48000Hz. This needs to match the data in NetworkAudioRecorder

    int error = 0;
    decoder = opus_decoder_create(48000, 1, &error);
}

bool NetworkAudioStream::onGetData(sf::SoundStream::Chunk& data)
{
    sf::Lock lock(samples_lock);    //Get exclusive access to the samples vector.
    //Copy all new samples to the playback buffer. And clear our sample buffer.
    playing_samples = std::move(samples);
    samples.clear();

    data.samples = playing_samples.data();
    data.sampleCount = playing_samples.size();

    //Stop playback if the buffer is empty.
    return data.sampleCount > 0;
}

void NetworkAudioStream::onSeek(sf::Time timeOffset)
{
    //We cannot seek in the network audio stream.
}

void NetworkAudioStream::receivedPacketFromNetwork(const unsigned char* packet, int packet_size)
{
    std::array<int16_t, 2880> samples_buffer;
    int sample_count = opus_decode(decoder, packet, packet_size, samples_buffer.data(), samples_buffer.size(), 0);
    if (sample_count > 0)
    {
        sf::Lock lock(samples_lock);
        this->samples.insert(this->samples.end(), samples_buffer.begin(), samples_buffer.begin() + sample_count);
    }
    if (this->samples.size() > sample_rate / 10 && getStatus() == sf::SoundSource::Stopped) //Start playback when there is 0.1 second of data
    {
        play();
    }
}

void NetworkAudioStream::finalize()
{
    if (this->samples.size() > 0 && getStatus() == sf::SoundSource::Stopped)
    {
        play();
    }
}

bool NetworkAudioStream::isFinished()
{
    return getStatus() == sf::SoundSource::Stopped && this->samples.size() == 0;
}

void NetworkAudioStreamManager::start(int32_t id)
{
    streams[id] = std::unique_ptr<NetworkAudioStream>(new NetworkAudioStream());
}

void NetworkAudioStreamManager::receivedPacketFromNetwork(int32_t id, const unsigned char* packet, int packet_size)
{
    auto it = streams.find(id);
    if (it == streams.end())
        return;
    it->second->receivedPacketFromNetwork(packet, packet_size);
}

void NetworkAudioStreamManager::stop(int32_t id)
{
    auto it = streams.find(id);
    if (it == streams.end())
        return;
    it->second->finalize();
}
<|endoftext|>


<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2015 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "exiftoolwrapper.h"

#include <QByteArray>
#include <QProcess>
#include <QRegExp>
#include <QString>
#include <QDebug>
#include <QPair>
#include "externaltoolsprovider.h"
#include "../Models/artworkmetadata.h"
#include "../Models/exportinfo.h"
#include "tempmetadatadb.h"

// returns NULL if patching wasn't successfull
ExportPair writeArtworkMetadata(ExportPair pair) {
    Models::ArtworkMetadata *metadata = pair.first;
    Models::ExportInfo *exportInfo = pair.second;

    QString author = QString(metadata->getAuthor()).simplified();
    QString title = QString(metadata->getTitle()).simplified();
    QString description = QString(metadata->getDescription()).simplified();
    const QString &keywords = metadata->getKeywordsString();

    if (title.isEmpty()) {
        title = description;
    }

    const QString exiftoolPath = Helpers::ExternalToolsProvider::getExifToolPath();

    QStringList arguments;
    arguments << exiftoolPath;
    arguments << "-quiet" << "-ignoreMinorErrors";
    arguments << QString("-EXIF:Artist=\"%1\"").arg(author);
    arguments << QString("-IPTC:By-line=\"%1\"").arg(author);
    arguments << QString("-XMP:Author=\"%1\"").arg(author);
    arguments << QString("-XMP:Creator=\"%1\"").arg(author);
    arguments << QString("-IPTC:ObjectName=\"%1\"").arg(title);
    arguments << QString("-XMP:Title=\"%1\"").arg(title);
    arguments << QString("-EXIF:ImageDescription=\"%1\"").arg(description);
    arguments << QString("-IPTC:LocalCaption=\"%1\"").arg(description);
    arguments << QString("-IPTC:Caption-Abstract=\"%1\"").arg(description);
    arguments << QString("-XMP:Caption=\"%1\"").arg(description);
    arguments << QString("-XMP:Description=\"%1\"").arg(description);
    arguments << QString("-IPTC:Keywords=\"%1\"").arg(keywords);
    arguments << QString("-XMP:Keywords=\"%1\"").arg(keywords);
    arguments << QString("-XMP:Subject=\"%1\"").arg(keywords);

    if (!exportInfo->getMustSaveOriginal()) {
        arguments << "-overwrite_original";
    }

    arguments << QString("\"%1\"").arg(metadata->getFilepath());

    Models::ArtworkMetadata *resultMetadata = NULL;

    QProcess process;
    QString command = arguments.join(' ');

    process.start(command);
    bool finished = process.waitForFinished();

    if (!finished || process.exitStatus() != QProcess::NormalExit) {
        QByteArray stdoutByteArray = process.readAll();
        QString stdoutText(stdoutByteArray);
        if (!stdoutText.isEmpty()) {
            qDebug() << "Error:" << exiftoolPath << stdoutText;
        }

        qDebug() << "Error:" << exiftoolPath << process.errorString();
        return qMakePair(resultMetadata, exportInfo);
    } else {
        return qMakePair(resultMetadata, exportInfo);
    }
}

void grabMetadata(const QStringList &items, Models::ImportDataResult *importData,
                  QRegExp authorRegExp,
                  QRegExp titleRegExp,
                  QRegExp descriptionRegExp,
                  QRegExp keywordsRegExp);

ImportPair readArtworkMetadata(ImportPair pair) {
    const QString exiftoolPath = Helpers::ExternalToolsProvider::getExifToolPath();

    Models::ImportDataResult *importData = pair.second;
    Models::ArtworkMetadata *metadata = pair.first;

    QStringList arguments;
    arguments << "-s" << "-e" << "-n" << "-EXIF:all" << "-IPTC:all" << "-XMP:all";
    arguments << metadata->getFilepath();

    QProcess process;
    process.start(exiftoolPath, arguments);
    bool finished = process.waitForFinished();

    QByteArray stdoutByteArray = process.readAll();
    QString stdoutText(stdoutByteArray);

    if (!finished || process.exitStatus() != QProcess::NormalExit) {
        if (!stdoutText.isEmpty()) {
            qDebug() << "Error:" << exiftoolPath << stdoutText;
        }
        qDebug() << "Error:" << exiftoolPath << process.errorString();
        return ImportPair(NULL, NULL);
    }

    QStringList items = stdoutText.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);

    QRegExp authorRegExp("^Artist\\s|^By-line\\s|^Creator\\s");
    QRegExp titleRegExp("^ObjectName\\s|^Title\\s");
    QRegExp descriptionRegExp("^ImageDescription\\s|^Caption-Abstract\\s|^Description\\s");
    QRegExp keywordsRegExp("^Keywords\\s|^Subject\\s");

    grabMetadata(items, importData, authorRegExp, titleRegExp, descriptionRegExp, keywordsRegExp);

    return pair;
}

void grabMetadata(const QStringList &items, Models::ImportDataResult *importData,
                  QRegExp authorRegExp,
                  QRegExp titleRegExp,
                  QRegExp descriptionRegExp,
                  QRegExp keywordsRegExp) {
    bool authorSet = false, titleSet = false, descriptionSet = false, keywordsSet = false;

    foreach (const QString &item, items) {
        QStringList parts = item.split(':', QString::SkipEmptyParts);
        if (parts.empty()) {
            continue;
        }

        const QString &first = parts.first();

        if (!authorSet && first.contains(authorRegExp)) {
            importData->Author = parts.at(1).trimmed();
            authorSet = true;
        }
        else if (!titleSet && first.contains(titleRegExp)) {
            importData->Title = parts.at(1).trimmed();
            titleSet = true;
        }
        else if (!descriptionSet && first.contains(descriptionRegExp)) {
            importData->Description = parts.at(1).trimmed();
            descriptionSet = true;
        }
        else if (!keywordsSet && first.contains(keywordsRegExp)) {
            importData->Keywords = parts.at(1).trimmed();
            keywordsSet = true;
        }
    }
}
<commit_msg>Fix for exiftool wrapper refactoring<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2015 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "exiftoolwrapper.h"

#include <QByteArray>
#include <QProcess>
#include <QRegExp>
#include <QString>
#include <QDebug>
#include <QPair>
#include "externaltoolsprovider.h"
#include "../Models/artworkmetadata.h"
#include "../Models/exportinfo.h"
#include "tempmetadatadb.h"

// returns NULL if patching wasn't successfull
ExportPair writeArtworkMetadata(ExportPair pair) {
    Models::ArtworkMetadata *metadata = pair.first;
    Models::ExportInfo *exportInfo = pair.second;

    QString author = QString(metadata->getAuthor()).simplified();
    QString title = QString(metadata->getTitle()).simplified();
    QString description = QString(metadata->getDescription()).simplified();
    const QString &keywords = metadata->getKeywordsString();

    if (title.isEmpty()) {
        title = description;
    }

    const QString exiftoolPath = Helpers::ExternalToolsProvider::getExifToolPath();

    QStringList arguments;
    arguments << exiftoolPath;
    arguments << "-quiet" << "-ignoreMinorErrors";
    arguments << QString("-EXIF:Artist=\"%1\"").arg(author);
    arguments << QString("-IPTC:By-line=\"%1\"").arg(author);
    arguments << QString("-XMP:Author=\"%1\"").arg(author);
    arguments << QString("-XMP:Creator=\"%1\"").arg(author);
    arguments << QString("-IPTC:ObjectName=\"%1\"").arg(title);
    arguments << QString("-XMP:Title=\"%1\"").arg(title);
    arguments << QString("-EXIF:ImageDescription=\"%1\"").arg(description);
    arguments << QString("-IPTC:LocalCaption=\"%1\"").arg(description);
    arguments << QString("-IPTC:Caption-Abstract=\"%1\"").arg(description);
    arguments << QString("-XMP:Caption=\"%1\"").arg(description);
    arguments << QString("-XMP:Description=\"%1\"").arg(description);
    arguments << QString("-IPTC:Keywords=\"%1\"").arg(keywords);
    arguments << QString("-XMP:Keywords=\"%1\"").arg(keywords);
    arguments << QString("-XMP:Subject=\"%1\"").arg(keywords);

    if (!exportInfo->getMustSaveOriginal()) {
        arguments << "-overwrite_original";
    }

    arguments << QString("\"%1\"").arg(metadata->getFilepath());

    Models::ArtworkMetadata *resultMetadata = NULL;

    QProcess process;
    QString command = arguments.join(' ');

    process.start(command);
    bool finished = process.waitForFinished();

    if (!finished || process.exitStatus() != QProcess::NormalExit) {
        QByteArray stdoutByteArray = process.readAll();
        QString stdoutText(stdoutByteArray);
        if (!stdoutText.isEmpty()) {
            qDebug() << "Error:" << exiftoolPath << stdoutText;
        }

        qDebug() << "Error:" << exiftoolPath << process.errorString();
        return qMakePair(resultMetadata, exportInfo);
    } else {
        resultMetadata = metadata;
        return qMakePair(resultMetadata, exportInfo);
    }
}

void grabMetadata(const QStringList &items, Models::ImportDataResult *importData,
                  QRegExp authorRegExp,
                  QRegExp titleRegExp,
                  QRegExp descriptionRegExp,
                  QRegExp keywordsRegExp);

ImportPair readArtworkMetadata(ImportPair pair) {
    const QString exiftoolPath = Helpers::ExternalToolsProvider::getExifToolPath();

    Models::ImportDataResult *importData = pair.second;
    Models::ArtworkMetadata *metadata = pair.first;

    QStringList arguments;
    arguments << "-s" << "-e" << "-n" << "-EXIF:all" << "-IPTC:all" << "-XMP:all";
    arguments << metadata->getFilepath();

    QProcess process;
    process.start(exiftoolPath, arguments);
    bool finished = process.waitForFinished();

    QByteArray stdoutByteArray = process.readAll();
    QString stdoutText(stdoutByteArray);

    if (!finished || process.exitStatus() != QProcess::NormalExit) {
        if (!stdoutText.isEmpty()) {
            qDebug() << "Error:" << exiftoolPath << stdoutText;
        }
        qDebug() << "Error:" << exiftoolPath << process.errorString();
        return ImportPair(NULL, NULL);
    }

    QStringList items = stdoutText.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);

    QRegExp authorRegExp("^Artist\\s|^By-line\\s|^Creator\\s");
    QRegExp titleRegExp("^ObjectName\\s|^Title\\s");
    QRegExp descriptionRegExp("^ImageDescription\\s|^Caption-Abstract\\s|^Description\\s");
    QRegExp keywordsRegExp("^Keywords\\s|^Subject\\s");

    grabMetadata(items, importData, authorRegExp, titleRegExp, descriptionRegExp, keywordsRegExp);

    return pair;
}

void grabMetadata(const QStringList &items, Models::ImportDataResult *importData,
                  QRegExp authorRegExp,
                  QRegExp titleRegExp,
                  QRegExp descriptionRegExp,
                  QRegExp keywordsRegExp) {
    bool authorSet = false, titleSet = false, descriptionSet = false, keywordsSet = false;

    foreach (const QString &item, items) {
        QStringList parts = item.split(':', QString::SkipEmptyParts);
        if (parts.empty()) {
            continue;
        }

        const QString &first = parts.first();

        if (!authorSet && first.contains(authorRegExp)) {
            importData->Author = parts.at(1).trimmed();
            authorSet = true;
        }
        else if (!titleSet && first.contains(titleRegExp)) {
            importData->Title = parts.at(1).trimmed();
            titleSet = true;
        }
        else if (!descriptionSet && first.contains(descriptionRegExp)) {
            importData->Description = parts.at(1).trimmed();
            descriptionSet = true;
        }
        else if (!keywordsSet && first.contains(keywordsRegExp)) {
            importData->Keywords = parts.at(1).trimmed();
            keywordsSet = true;
        }
    }
}
<|endoftext|>