<commit_before>#include "GLBlaat/GL.h"

#include "NQVTKWidget.h"
#include "NQVTKWidget.moc"

#include "Math/Vector3.h"

#include "Rendering/Renderer.h"
#include "Rendering/Camera.h"
#include "Rendering/PolyData.h"
#include "Rendering/ImageDataTexture3D.h"

#include "Styles/DepthPeeling.h"
#include "Styles/IBIS.h"
#include "Styles/DistanceFields.h"

#include <vtkSmartPointer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLImageDataReader.h>

#include <QKeyEvent>
#include <QMouseEvent>
#include <QApplication>
#include <QStringList>
#include <QGLFormat>
#include <QDateTime>

#include <algorithm>

// ----------------------------------------------------------------------------
NQVTKWidget::NQVTKWidget(QWidget *parent /* = 0 */)
: QGLWidget(QGLFormat(QGL::AlphaChannel), parent), renderer(0), initialized(false)
{
	setMouseTracking(true);
}

// ----------------------------------------------------------------------------
NQVTKWidget::~NQVTKWidget()
{
	if (renderer) delete renderer;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::initializeGL()
{
	if (glewInit() != GLEW_OK)
	{
		qDebug("Failed to initialize GLEW!");
		return;
	}

	qDebug("Initializing renderer...");
	if (!renderer) renderer = new NQVTK::Renderer();
	NQVTK::Styles::DistanceFields *style = new NQVTK::Styles::DistanceFields();
	this->distfieldstyle = style;
	renderer->SetStyle(style);
	initialized = renderer->Initialize();

	if (!initialized)
	{
		qDebug("Failed to initialize renderer...");
	}

	qDebug("Creating and adding renderables...");
	QStringList args = qApp->arguments();
	if (args.size() < 2)
	{
		qDebug("No arguments supplied, using default data...");
		// Set default testing data (on Vliet)
		//* - msdata
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_07_08-T2-textured.vtp");
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_08_02-T2-textured.vtp");
		//*/
		/*  Cartilage
		args.append("D:/Data/Cartilage/Lorena/femoral2.vtp");
		args.append("D:/Data/Cartilage/Lorena/femoral1.vtp");
		//*/
	}
	// Load the polydata
	NQVTK::Vector3 colors[] = {
		NQVTK::Vector3(1.0, 0.9, 0.4),
		NQVTK::Vector3(0.3, 0.6, 1.0)
	};
	int i = 0;
	for (QStringList::const_iterator it = args.begin() + 1; it != args.end(); ++it)
	{
		qDebug("Loading #%d...", i);
		vtkSmartPointer<vtkXMLPolyDataReader> reader =
			vtkSmartPointer<vtkXMLPolyDataReader>::New();
		reader->SetFileName(it->toUtf8());
		reader->Update();
		NQVTK::Renderable *renderable = new NQVTK::PolyData(reader->GetOutput());
		renderable->color = colors[std::min(i, 1)];
		renderable->opacity = 0.3;
		renderer->AddRenderable(renderable);
		++i;
	}

	//* For testing purposes: load and set the distance fields
	// NOTE: assingments are flipped because object 1 should use distfield 0
	{
		qDebug("Loading distance field 0...");
		vtkSmartPointer<vtkXMLImageDataReader> reader =
			vtkSmartPointer<vtkXMLImageDataReader>::New();
		reader->SetFileName(
			"D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_07_08-T2-dist256.vti");
		reader->Update();
		GLTexture *tex = NQVTK::ImageDataTexture3D::New(reader->GetOutput());
		assert(tex);
		style->SetDistanceField(1, tex);
	}
	{
		qDebug("Loading distance field 1...");
		vtkSmartPointer<vtkXMLImageDataReader> reader =
			vtkSmartPointer<vtkXMLImageDataReader>::New();
		reader->SetFileName(
			"D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_08_02-T2-dist256.vti");
		reader->Update();
		GLTexture *tex = NQVTK::ImageDataTexture3D::New(reader->GetOutput());
		assert(tex);
		style->SetDistanceField(0, tex);
	}
	//*/

	// Render-on-idle timer
	startTimer(0);
	// FPS display timer
	fpsTimerId = startTimer(1000);
	frames = 0;

	qDebug("Init done!");
}

// ----------------------------------------------------------------------------
void NQVTKWidget::resizeGL(int w, int h)
{
	renderer->Resize(w, h);
}

// ----------------------------------------------------------------------------
void NQVTKWidget::paintGL()
{
	if (initialized)
	{
		renderer->Draw();
	}
	else
	{
		renderer->Clear();
	}
	++frames;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == fpsTimerId)
	{
		// Update FPS display
		emit fpsChanged(frames);
		frames = 0;
	}
	else
	{
		// Update on idle
		updateGL();
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::keyPressEvent(QKeyEvent *event)
{
	// Quit on Escape
	switch (event->key())
	{
	case Qt::Key_Escape:
		qApp->quit();
		break;
	case Qt::Key_C:
		{
			QDateTime now = QDateTime::currentDateTime();
			QImage screenshot = this->grabFrameBuffer(true);
			// Fix alpha values
			screenshot.invertPixels(QImage::InvertRgba);
			screenshot.invertPixels(QImage::InvertRgb);
			// Save it
			screenshot.save(QString("NQVTK-%1.png").arg(
				now.toString("yyMMdd-hhmmss")), "PNG");
			break;
		}
	case Qt::Key_R:
		renderer->ResetRenderables();
		break;
	case Qt::Key_1:
		{
			NQVTK::Renderable *ren = renderer->GetRenderable(0);
			if (ren) ren->visible = !ren->visible;
		}
		break;
	case Qt::Key_2:
		{
			NQVTK::Renderable *ren = renderer->GetRenderable(1);
			if (ren) ren->visible = !ren->visible;
		}
		break;
	case Qt::Key_F1:
		initialized = renderer->SetStyle(new NQVTK::Styles::DepthPeeling());
		break;
	case Qt::Key_F2:
		initialized = renderer->SetStyle(new NQVTK::Styles::IBIS());
		break;
	case Qt::Key_F3:
		distfieldstyle = new NQVTK::Styles::DistanceFields();
		initialized = renderer->SetStyle(distfieldstyle);
		break;
	default:
		event->ignore();
		return;
	}
	event->accept();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseMoveEvent(QMouseEvent *event)
{
	if (event->modifiers() & Qt::ControlModifier)
	{
		NQVTK::Renderable *renderable = renderer->GetRenderable(0);
		// Mouse controls object 0
		if (renderable && event->buttons() & Qt::LeftButton)
		{
			// Rotate
			renderable->rotateY += event->x() - lastX;
			renderable->rotateX -= event->y() - lastY;

			if (renderable->rotateX > 80.0)
			{
				renderable->rotateX = 80.0;
			}
			if (renderable->rotateX < -80.0)
			{
				renderable->rotateX = -80.0;
			}
		}
		if (renderable && event->buttons() & Qt::MidButton)
		{
			// TODO: make translation relative to window
			NQVTK::Vector3 right = NQVTK::Vector3(1.0, 0.0, 0.0);
			NQVTK::Vector3 up = NQVTK::Vector3(0.0, 1.0, 0.0);
			double factor = 0.6;
			// Translate
			renderable->position +=
				(lastX - event->x()) * factor * right +
				(lastY - event->y()) * factor * up;
		}
	}
	else
	{
		// Mouse controls camera
		if (event->buttons() & Qt::LeftButton)
		{
			// Rotate
			renderer->GetCamera()->rotateY += event->x() - lastX;
			renderer->GetCamera()->rotateX -= event->y() - lastY;

			if (renderer->GetCamera()->rotateX > 80.0)
			{
				renderer->GetCamera()->rotateX = 80.0;
			}
			if (renderer->GetCamera()->rotateX < -80.0)
			{
				renderer->GetCamera()->rotateX = -80.0;
			}
		}

		if (event->buttons() & Qt::RightButton)
		{
			// Zoom
			renderer->GetCamera()->zoom += (event->y() - lastY) * 0.01f;
			if (renderer->GetCamera()->zoom < 0.05)
			{
				renderer->GetCamera()->zoom = 0.05;
			}
			if (renderer->GetCamera()->zoom > 20.0)
			{
				renderer->GetCamera()->zoom = 20.0;
			}
		}
	}

	lastX = event->x();
	lastY = event->y();

	event->accept();
}
<commit_msg>Added command line parsing for distance fields.<commit_after>#include "GLBlaat/GL.h"

#include "NQVTKWidget.h"
#include "NQVTKWidget.moc"

#include "Math/Vector3.h"

#include "Rendering/Renderer.h"
#include "Rendering/Camera.h"
#include "Rendering/PolyData.h"
#include "Rendering/ImageDataTexture3D.h"

#include "Styles/DepthPeeling.h"
#include "Styles/IBIS.h"
#include "Styles/DistanceFields.h"

#include <vtkSmartPointer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLImageDataReader.h>

#include <QKeyEvent>
#include <QMouseEvent>
#include <QApplication>
#include <QStringList>
#include <QGLFormat>
#include <QDateTime>

#include <algorithm>

// ----------------------------------------------------------------------------
NQVTKWidget::NQVTKWidget(QWidget *parent /* = 0 */)
: QGLWidget(QGLFormat(QGL::AlphaChannel), parent), renderer(0), initialized(false)
{
	setMouseTracking(true);
}

// ----------------------------------------------------------------------------
NQVTKWidget::~NQVTKWidget()
{
	if (renderer) delete renderer;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::initializeGL()
{
	if (glewInit() != GLEW_OK)
	{
		qDebug("Failed to initialize GLEW!");
		return;
	}

	qDebug("Initializing renderer...");
	if (!renderer) renderer = new NQVTK::Renderer();
	NQVTK::Styles::DistanceFields *style = new NQVTK::Styles::DistanceFields();
	this->distfieldstyle = style;
	renderer->SetStyle(style);
	initialized = renderer->Initialize();

	if (!initialized)
	{
		qDebug("Failed to initialize renderer...");
	}

	qDebug("Creating and adding renderables...");
	QStringList args = qApp->arguments();
	if (args.size() < 2)
	{
		qDebug("No arguments supplied, using default data...");
		// Set default testing data (on Vliet)
		//* - msdata
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_07_08-T2-textured.vtp");
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_08_02-T2-textured.vtp");
		args.append("-"); // distance field marker
		// NOTE: fields are flipped because object 1 should use distfield 0
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_08_02-T2-dist256.vti");
		args.append("D:/Data/msdata/T2W/T2W_images_normalized/T2W_normalized_GM/Gwn0200-TP_2004_07_08-T2-dist256.vti");
		//*/
		/*  Cartilage
		args.append("D:/Data/Cartilage/Lorena/femoral2.vtp");
		args.append("D:/Data/Cartilage/Lorena/femoral1.vtp");
		//*/
	}
	// Load the polydata
	NQVTK::Vector3 colors[] = {
		NQVTK::Vector3(1.0, 0.9, 0.4),
		NQVTK::Vector3(0.3, 0.6, 1.0)
	};
	int i = 0;
	bool distFields = false;
	for (QStringList::const_iterator it = args.begin() + 1; it != args.end(); ++it)
	{
		qDebug("Loading %s #%d...", (distFields ? "distance field" : "surface"), i);
		if (QString("-") == *it)
		{
			distFields = true;
			i = 0;
			continue;
		}
		if (!distFields)
		{
			// Load surface
			vtkSmartPointer<vtkXMLPolyDataReader> reader =
				vtkSmartPointer<vtkXMLPolyDataReader>::New();
			reader->SetFileName(it->toUtf8());
			reader->Update();
			NQVTK::Renderable *renderable = new NQVTK::PolyData(reader->GetOutput());
			renderable->color = colors[std::min(i, 1)];
			renderable->opacity = 0.3;
			renderer->AddRenderable(renderable);
		}
		else
		{
			// Load distance field
			vtkSmartPointer<vtkXMLImageDataReader> reader =
				vtkSmartPointer<vtkXMLImageDataReader>::New();
			reader->SetFileName(it->toUtf8());
			reader->Update();
			GLTexture *tex = NQVTK::ImageDataTexture3D::New(reader->GetOutput());
			assert(tex);
			distfieldstyle->SetDistanceField(i, tex);
		}
		++i;
	}

	// Render-on-idle timer
	startTimer(0);
	// FPS display timer
	fpsTimerId = startTimer(1000);
	frames = 0;

	qDebug("Init done!");
}

// ----------------------------------------------------------------------------
void NQVTKWidget::resizeGL(int w, int h)
{
	renderer->Resize(w, h);
}

// ----------------------------------------------------------------------------
void NQVTKWidget::paintGL()
{
	if (initialized)
	{
		renderer->Draw();
	}
	else
	{
		renderer->Clear();
	}
	++frames;
}

// ----------------------------------------------------------------------------
void NQVTKWidget::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == fpsTimerId)
	{
		// Update FPS display
		emit fpsChanged(frames);
		frames = 0;
	}
	else
	{
		// Update on idle
		updateGL();
	}
}

// ----------------------------------------------------------------------------
void NQVTKWidget::keyPressEvent(QKeyEvent *event)
{
	// Quit on Escape
	switch (event->key())
	{
	case Qt::Key_Escape:
		qApp->quit();
		break;
	case Qt::Key_C:
		{
			QDateTime now = QDateTime::currentDateTime();
			QImage screenshot = this->grabFrameBuffer(true);
			// Fix alpha values
			screenshot.invertPixels(QImage::InvertRgba);
			screenshot.invertPixels(QImage::InvertRgb);
			// Save it
			screenshot.save(QString("NQVTK-%1.png").arg(
				now.toString("yyMMdd-hhmmss")), "PNG");
			break;
		}
	case Qt::Key_R:
		renderer->ResetRenderables();
		break;
	case Qt::Key_1:
		{
			NQVTK::Renderable *ren = renderer->GetRenderable(0);
			if (ren) ren->visible = !ren->visible;
		}
		break;
	case Qt::Key_2:
		{
			NQVTK::Renderable *ren = renderer->GetRenderable(1);
			if (ren) ren->visible = !ren->visible;
		}
		break;
	case Qt::Key_F1:
		initialized = renderer->SetStyle(new NQVTK::Styles::DepthPeeling());
		break;
	case Qt::Key_F2:
		initialized = renderer->SetStyle(new NQVTK::Styles::IBIS());
		break;
	case Qt::Key_F3:
		distfieldstyle = new NQVTK::Styles::DistanceFields();
		initialized = renderer->SetStyle(distfieldstyle);
		break;
	default:
		event->ignore();
		return;
	}
	event->accept();
}

// ----------------------------------------------------------------------------
void NQVTKWidget::mouseMoveEvent(QMouseEvent *event)
{
	if (event->modifiers() & Qt::ControlModifier)
	{
		NQVTK::Renderable *renderable = renderer->GetRenderable(0);
		// Mouse controls object 0
		if (renderable && event->buttons() & Qt::LeftButton)
		{
			// Rotate
			renderable->rotateY += event->x() - lastX;
			renderable->rotateX -= event->y() - lastY;

			if (renderable->rotateX > 80.0)
			{
				renderable->rotateX = 80.0;
			}
			if (renderable->rotateX < -80.0)
			{
				renderable->rotateX = -80.0;
			}
		}
		if (renderable && event->buttons() & Qt::MidButton)
		{
			// TODO: make translation relative to window
			NQVTK::Vector3 right = NQVTK::Vector3(1.0, 0.0, 0.0);
			NQVTK::Vector3 up = NQVTK::Vector3(0.0, 1.0, 0.0);
			double factor = 0.6;
			// Translate
			renderable->position +=
				(lastX - event->x()) * factor * right +
				(lastY - event->y()) * factor * up;
		}
	}
	else
	{
		// Mouse controls camera
		if (event->buttons() & Qt::LeftButton)
		{
			// Rotate
			renderer->GetCamera()->rotateY += event->x() - lastX;
			renderer->GetCamera()->rotateX -= event->y() - lastY;

			if (renderer->GetCamera()->rotateX > 80.0)
			{
				renderer->GetCamera()->rotateX = 80.0;
			}
			if (renderer->GetCamera()->rotateX < -80.0)
			{
				renderer->GetCamera()->rotateX = -80.0;
			}
		}

		if (event->buttons() & Qt::RightButton)
		{
			// Zoom
			renderer->GetCamera()->zoom += (event->y() - lastY) * 0.01f;
			if (renderer->GetCamera()->zoom < 0.05)
			{
				renderer->GetCamera()->zoom = 0.05;
			}
			if (renderer->GetCamera()->zoom > 20.0)
			{
				renderer->GetCamera()->zoom = 20.0;
			}
		}
	}

	lastX = event->x();
	lastY = event->y();

	event->accept();
}
<|endoftext|>


<commit_before>/*  Sirikata Network Utilities
 *  ASIOStreamBuilder.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sirikata/core/util/Platform.hpp>
#include <sirikata/core/network/Asio.hpp>
#include "TCPStream.hpp"
#include "ASIOSocketWrapper.hpp"
#include "MultiplexedSocket.hpp"
#include "TCPSetCallbacks.hpp"
#include "TCPStreamListener.hpp"
#include "ASIOReadBuffer.hpp"

#include <boost/lexical_cast.hpp>
#include <openssl/md5.h>

namespace Sirikata {
namespace Network {
namespace ASIOStreamBuilder{

typedef Array<uint8,TCPStream::MaxWebSocketHeaderSize> TcpSstHeaderArray;

class IncompleteStreamState {
public:
    int mNumSockets;
    std::vector<TCPSocket*>mSockets;
    std::map<TCPSocket*, std::string> mWebSocketResponses;
};

namespace {
typedef std::map<UUID,IncompleteStreamState> IncompleteStreamMap;
std::deque<UUID> sStaleUUIDs;
IncompleteStreamMap sIncompleteStreams;

int64 getObscuredNumber(const std::string& key) {
    std::string filtered;
    for(int32 i = 0; i < (int)key.size(); i++)
        if (key[i] >= '0' && key[i] <= '9')
            filtered.push_back(key[i]);
    return boost::lexical_cast<int64>(filtered);
}

int64 getNumSpaces(const std::string& key) {
    int32 result = 0;
    for(int32 i = 0; i < (int)key.size(); i++)
        if (key[i] == ' ') result++;
    return result;
}

std::string getWebSocketSecReply(const std::string& key1, const std::string& key2, const std::string key3) {
    char magic_concat[16];
    int32* magic_1 = (int32*)magic_concat;
    int32* magic_2 = (int32*)(magic_concat + 4);
    char* magic_bytes = magic_concat + 8;

    *magic_1 = htonl(getObscuredNumber(key1) / getNumSpaces(key1));
    *magic_2 = htonl(getObscuredNumber(key2) / getNumSpaces(key2));
    assert(key3.size() == 8);
    memcpy(magic_bytes, &(key3[0]), 8);

    // FIXME md5 hash
    unsigned char result[MD5_DIGEST_LENGTH];
    MD5((unsigned char*) magic_concat, 16, result);

    return std::string((const char*)result, MD5_DIGEST_LENGTH);
}

}

///gets called when a complete 24 byte header is actually received: uses the UUID within to match up appropriate sockets
void buildStream(TcpSstHeaderArray *buffer,
                 TCPSocket *socket,
                 std::tr1::shared_ptr<TCPStreamListener::Data> data,
                 const boost::system::error_code &error,
                 std::size_t bytes_transferred)
{
    // Buffer always needs to be cleaned up when we get out of this method
    std::auto_ptr<TcpSstHeaderArray> buffer_ptr(buffer);

    // Sanity check start
    if (error || bytes_transferred < 5 || std::string((const char*)buffer->begin(), 5) != std::string("GET /")) {
        SILOG(tcpsst,warning,"Connection received with truncated header: "<<error);
        delete socket;
        return;
    }

    // Sanity check end: 8 bytes from WebSocket spec after headers, then
    // \r\n\r\n before that.
    std::string buffer_str((const char*)buffer->begin(), bytes_transferred);
    if (buffer_str[ bytes_transferred - 12] != '\r' ||
        buffer_str[ bytes_transferred - 11] != '\n' ||
        buffer_str[ bytes_transferred - 10] != '\r' ||
        buffer_str[ bytes_transferred - 9] != '\n')
    {
        SILOG(tcpsst,warning,"Request doesn't end properly:\n" << buffer_str << "\n");
        delete socket;
        return;
    }

    std::string headers_str = buffer_str.substr(0, bytes_transferred - 10);
    // Parse headers
    UUID context;
    std::map<std::string, std::string> headers;
    std::string::size_type offset = 0;
    while(offset < headers_str.size()) {
        std::string::size_type last_offset = offset;
        offset = headers_str.find("\r\n", offset);
        if (offset == std::string::npos) {
            SILOG(tcpsst,warning,"Error parsing headers.");
            delete socket;
            return;
        }

        std::string line = headers_str.substr(last_offset, offset - last_offset);

        // Special case the initial GET line
        if (line.substr(0, 5) == "GET /") {
            std::string::size_type uuid_end = line.find(' ', 5);
            if (uuid_end == std::string::npos) {
                SILOG(tcpsst,warning,"Error parsing headers: invalid get line.");
                delete socket;
                return;
            }
            std::string uuid_str = line.substr(5, uuid_end - 5);
            try {
                context = UUID(uuid_str,UUID::HumanReadable());
            } catch(...) {
                SILOG(tcpsst,warning,"Error parsing headers: invalid get uuid.");
                delete socket;
                return;
            }

            offset += 2;
            continue;
        }

        std::string::size_type colon = line.find(":");
        if (colon == std::string::npos) {
            SILOG(tcpsst,warning,"Error parsing headers: missing colon.");
            delete socket;
            return;
        }
        std::string head = line.substr(0, colon);
        std::string val = line.substr(colon+2);

        headers[head] = val;

        // Advance to get past the \r\n
        offset += 2;
    }

    if (headers.find("Host") == headers.end() ||
        headers.find("Origin") == headers.end() ||
        headers.find("Sec-WebSocket-Key1") == headers.end() ||
        headers.find("Sec-WebSocket-Key2") == headers.end())
    {
        SILOG(tcpsst,warning,"Connection request didn't specify all required fields.");
        delete socket;
        return;
    }

    std::string host = headers["Host"];
    std::string origin = headers["Origin"];
    std::string protocol = "wssst1";
    if (headers.find("Sec-WebSocket-Protocol") != headers.end())
        protocol = headers["Sec-WebSocket-Protocol"];
    std::string key1 = headers["Sec-WebSocket-Key1"];
    std::string key2 = headers["Sec-WebSocket-Key2"];
    std::string key3 = buffer_str.substr(bytes_transferred - 8);
    assert(key3.size() == 8);

    std::string reply_str = getWebSocketSecReply(key1, key2, key3);

    bool binaryStream=protocol.find("sst")==0;
    bool base64Stream=!binaryStream;
    boost::asio::ip::tcp::no_delay option(data->mNoDelay);
    socket->set_option(option);
    IncompleteStreamMap::iterator where=sIncompleteStreams.find(context);

    unsigned int numConnections=1;

    for (std::string::iterator i=protocol.begin(),ie=protocol.end();i!=ie;++i) {
        if (*i>='0'&&*i<='9') {
            char* endptr=NULL;
            const char *start=protocol.c_str();
            size_t offset=(i-protocol.begin());
            start+=offset;
            numConnections=strtol(start,&endptr,10);
            size_t numberlen=endptr-start;
            if (numConnections>data->mMaxSimultaneousSockets) {
                numConnections=data->mMaxSimultaneousSockets;
                char numcon[256];
                sprintf(numcon,"%d",numConnections);
                protocol=protocol.substr(0,offset)+numcon+protocol.substr(offset+numberlen);
            }
            break;
        }
    }

    if (where==sIncompleteStreams.end()){
        sIncompleteStreams[context].mNumSockets=numConnections;
        where=sIncompleteStreams.find(context);
        assert(where!=sIncompleteStreams.end());
    }
    if ((int)numConnections!=where->second.mNumSockets) {
        SILOG(tcpsst,warning,"Single client disagrees on number of connections to establish: "<<numConnections<<" != "<<where->second.mNumSockets);
        sIncompleteStreams.erase(where);
    }else {
        where->second.mSockets.push_back(socket);
        where->second.mWebSocketResponses[socket] = reply_str;
        if (numConnections==(unsigned int)where->second.mSockets.size()) {
            MultiplexedSocketPtr shared_socket(
                MultiplexedSocket::construct<MultiplexedSocket>(data->strand,context,data->cb,base64Stream));
            shared_socket->initFromSockets(where->second.mSockets,data->mSendBufferSize);
            std::string port=shared_socket->getASIOSocketWrapper(0).getLocalEndpoint().getService();
            std::string resource_name='/'+context.toString();
            MultiplexedSocket::sendAllProtocolHeaders(shared_socket,origin,host,port,resource_name,protocol, where->second.mWebSocketResponses);
            sIncompleteStreams.erase(where);

            Stream::StreamID newID=Stream::StreamID(1);
            TCPStream * strm=new TCPStream(shared_socket,newID);

            TCPSetCallbacks setCallbackFunctor(&*shared_socket,strm);
            data->cb(strm,setCallbackFunctor);
            if (setCallbackFunctor.mCallbacks==NULL) {
                SILOG(tcpsst,error,"Client code for stream "<<newID.read()<<" did not set listener on socket");
                shared_socket->closeStream(shared_socket,newID);
            }
        }else{
            sStaleUUIDs.push_back(context);
        }
    }
}

namespace {
class CheckWebSocketRequest {
    const Array<uint8,TCPStream::MaxWebSocketHeaderSize> *mArray;
    typedef boost::system::error_code ErrorCode;
    uint32 mTotal;
public:
    CheckWebSocketRequest(const Array<uint8,TCPStream::MaxWebSocketHeaderSize>*array) {
        mArray=array;
        mTotal = 0;
    }
    size_t operator() (const ErrorCode& error, size_t bytes_transferred) {
        if (error) return 0;

        mTotal += bytes_transferred;

        if (mTotal >= 12 &&
            (*mArray)[mTotal - 12] == '\r' &&
            (*mArray)[mTotal - 11] == '\n' &&
            (*mArray)[mTotal - 10] == '\r' &&
            (*mArray)[mTotal - 9] == '\n')
        {
            return 0;
        }
        return 65536;
    }
};
} // namespace

void beginNewStream(TCPSocket*socket, std::tr1::shared_ptr<TCPStreamListener::Data> data) {

    TcpSstHeaderArray *buffer = new TcpSstHeaderArray;

    boost::asio::async_read(*socket,
                            boost::asio::buffer(buffer->begin(),(int)TCPStream::MaxWebSocketHeaderSize>(int)ASIOReadBuffer::sBufferLength?(int)ASIOReadBuffer::sBufferLength:(int)TCPStream::MaxWebSocketHeaderSize),
                            CheckWebSocketRequest (buffer),
                            std::tr1::bind(&ASIOStreamBuilder::buildStream,buffer,socket,data,_1,_2));
}

} // namespace ASIOStreamBuilder
} // namespace Network
} // namespace Sirikata
<commit_msg>Add missing strand wrapping in TCPSST to fix crash triggered when two read callbacks from sockets for the same TCPSST connection were invoked at the same time.<commit_after>/*  Sirikata Network Utilities
 *  ASIOStreamBuilder.cpp
 *
 *  Copyright (c) 2009, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sirikata/core/util/Platform.hpp>
#include <sirikata/core/network/Asio.hpp>
#include <sirikata/core/network/IOStrandImpl.hpp>
#include "TCPStream.hpp"
#include "ASIOSocketWrapper.hpp"
#include "MultiplexedSocket.hpp"
#include "TCPSetCallbacks.hpp"
#include "TCPStreamListener.hpp"
#include "ASIOReadBuffer.hpp"

#include <boost/lexical_cast.hpp>
#include <openssl/md5.h>

namespace Sirikata {
namespace Network {
namespace ASIOStreamBuilder{

typedef Array<uint8,TCPStream::MaxWebSocketHeaderSize> TcpSstHeaderArray;

class IncompleteStreamState {
public:
    int mNumSockets;
    std::vector<TCPSocket*>mSockets;
    std::map<TCPSocket*, std::string> mWebSocketResponses;
};

namespace {
typedef std::map<UUID,IncompleteStreamState> IncompleteStreamMap;
std::deque<UUID> sStaleUUIDs;
IncompleteStreamMap sIncompleteStreams;

int64 getObscuredNumber(const std::string& key) {
    std::string filtered;
    for(int32 i = 0; i < (int)key.size(); i++)
        if (key[i] >= '0' && key[i] <= '9')
            filtered.push_back(key[i]);
    return boost::lexical_cast<int64>(filtered);
}

int64 getNumSpaces(const std::string& key) {
    int32 result = 0;
    for(int32 i = 0; i < (int)key.size(); i++)
        if (key[i] == ' ') result++;
    return result;
}

std::string getWebSocketSecReply(const std::string& key1, const std::string& key2, const std::string key3) {
    char magic_concat[16];
    int32* magic_1 = (int32*)magic_concat;
    int32* magic_2 = (int32*)(magic_concat + 4);
    char* magic_bytes = magic_concat + 8;

    *magic_1 = htonl(getObscuredNumber(key1) / getNumSpaces(key1));
    *magic_2 = htonl(getObscuredNumber(key2) / getNumSpaces(key2));
    assert(key3.size() == 8);
    memcpy(magic_bytes, &(key3[0]), 8);

    // FIXME md5 hash
    unsigned char result[MD5_DIGEST_LENGTH];
    MD5((unsigned char*) magic_concat, 16, result);

    return std::string((const char*)result, MD5_DIGEST_LENGTH);
}

}

///gets called when a complete 24 byte header is actually received: uses the UUID within to match up appropriate sockets
void buildStream(TcpSstHeaderArray *buffer,
                 TCPSocket *socket,
                 std::tr1::shared_ptr<TCPStreamListener::Data> data,
                 const boost::system::error_code &error,
                 std::size_t bytes_transferred)
{
    // Buffer always needs to be cleaned up when we get out of this method
    std::auto_ptr<TcpSstHeaderArray> buffer_ptr(buffer);

    // Sanity check start
    if (error || bytes_transferred < 5 || std::string((const char*)buffer->begin(), 5) != std::string("GET /")) {
        SILOG(tcpsst,warning,"Connection received with truncated header: "<<error);
        delete socket;
        return;
    }

    // Sanity check end: 8 bytes from WebSocket spec after headers, then
    // \r\n\r\n before that.
    std::string buffer_str((const char*)buffer->begin(), bytes_transferred);
    if (buffer_str[ bytes_transferred - 12] != '\r' ||
        buffer_str[ bytes_transferred - 11] != '\n' ||
        buffer_str[ bytes_transferred - 10] != '\r' ||
        buffer_str[ bytes_transferred - 9] != '\n')
    {
        SILOG(tcpsst,warning,"Request doesn't end properly:\n" << buffer_str << "\n");
        delete socket;
        return;
    }

    std::string headers_str = buffer_str.substr(0, bytes_transferred - 10);
    // Parse headers
    UUID context;
    std::map<std::string, std::string> headers;
    std::string::size_type offset = 0;
    while(offset < headers_str.size()) {
        std::string::size_type last_offset = offset;
        offset = headers_str.find("\r\n", offset);
        if (offset == std::string::npos) {
            SILOG(tcpsst,warning,"Error parsing headers.");
            delete socket;
            return;
        }

        std::string line = headers_str.substr(last_offset, offset - last_offset);

        // Special case the initial GET line
        if (line.substr(0, 5) == "GET /") {
            std::string::size_type uuid_end = line.find(' ', 5);
            if (uuid_end == std::string::npos) {
                SILOG(tcpsst,warning,"Error parsing headers: invalid get line.");
                delete socket;
                return;
            }
            std::string uuid_str = line.substr(5, uuid_end - 5);
            try {
                context = UUID(uuid_str,UUID::HumanReadable());
            } catch(...) {
                SILOG(tcpsst,warning,"Error parsing headers: invalid get uuid.");
                delete socket;
                return;
            }

            offset += 2;
            continue;
        }

        std::string::size_type colon = line.find(":");
        if (colon == std::string::npos) {
            SILOG(tcpsst,warning,"Error parsing headers: missing colon.");
            delete socket;
            return;
        }
        std::string head = line.substr(0, colon);
        std::string val = line.substr(colon+2);

        headers[head] = val;

        // Advance to get past the \r\n
        offset += 2;
    }

    if (headers.find("Host") == headers.end() ||
        headers.find("Origin") == headers.end() ||
        headers.find("Sec-WebSocket-Key1") == headers.end() ||
        headers.find("Sec-WebSocket-Key2") == headers.end())
    {
        SILOG(tcpsst,warning,"Connection request didn't specify all required fields.");
        delete socket;
        return;
    }

    std::string host = headers["Host"];
    std::string origin = headers["Origin"];
    std::string protocol = "wssst1";
    if (headers.find("Sec-WebSocket-Protocol") != headers.end())
        protocol = headers["Sec-WebSocket-Protocol"];
    std::string key1 = headers["Sec-WebSocket-Key1"];
    std::string key2 = headers["Sec-WebSocket-Key2"];
    std::string key3 = buffer_str.substr(bytes_transferred - 8);
    assert(key3.size() == 8);

    std::string reply_str = getWebSocketSecReply(key1, key2, key3);

    bool binaryStream=protocol.find("sst")==0;
    bool base64Stream=!binaryStream;
    boost::asio::ip::tcp::no_delay option(data->mNoDelay);
    socket->set_option(option);
    IncompleteStreamMap::iterator where=sIncompleteStreams.find(context);

    unsigned int numConnections=1;

    for (std::string::iterator i=protocol.begin(),ie=protocol.end();i!=ie;++i) {
        if (*i>='0'&&*i<='9') {
            char* endptr=NULL;
            const char *start=protocol.c_str();
            size_t offset=(i-protocol.begin());
            start+=offset;
            numConnections=strtol(start,&endptr,10);
            size_t numberlen=endptr-start;
            if (numConnections>data->mMaxSimultaneousSockets) {
                numConnections=data->mMaxSimultaneousSockets;
                char numcon[256];
                sprintf(numcon,"%d",numConnections);
                protocol=protocol.substr(0,offset)+numcon+protocol.substr(offset+numberlen);
            }
            break;
        }
    }

    if (where==sIncompleteStreams.end()){
        sIncompleteStreams[context].mNumSockets=numConnections;
        where=sIncompleteStreams.find(context);
        assert(where!=sIncompleteStreams.end());
    }
    if ((int)numConnections!=where->second.mNumSockets) {
        SILOG(tcpsst,warning,"Single client disagrees on number of connections to establish: "<<numConnections<<" != "<<where->second.mNumSockets);
        sIncompleteStreams.erase(where);
    }else {
        where->second.mSockets.push_back(socket);
        where->second.mWebSocketResponses[socket] = reply_str;
        if (numConnections==(unsigned int)where->second.mSockets.size()) {
            MultiplexedSocketPtr shared_socket(
                MultiplexedSocket::construct<MultiplexedSocket>(data->strand,context,data->cb,base64Stream));
            shared_socket->initFromSockets(where->second.mSockets,data->mSendBufferSize);
            std::string port=shared_socket->getASIOSocketWrapper(0).getLocalEndpoint().getService();
            std::string resource_name='/'+context.toString();
            MultiplexedSocket::sendAllProtocolHeaders(shared_socket,origin,host,port,resource_name,protocol, where->second.mWebSocketResponses);
            sIncompleteStreams.erase(where);

            Stream::StreamID newID=Stream::StreamID(1);
            TCPStream * strm=new TCPStream(shared_socket,newID);

            TCPSetCallbacks setCallbackFunctor(&*shared_socket,strm);
            data->cb(strm,setCallbackFunctor);
            if (setCallbackFunctor.mCallbacks==NULL) {
                SILOG(tcpsst,error,"Client code for stream "<<newID.read()<<" did not set listener on socket");
                shared_socket->closeStream(shared_socket,newID);
            }
        }else{
            sStaleUUIDs.push_back(context);
        }
    }
}

namespace {
class CheckWebSocketRequest {
    const Array<uint8,TCPStream::MaxWebSocketHeaderSize> *mArray;
    typedef boost::system::error_code ErrorCode;
    uint32 mTotal;
public:
    CheckWebSocketRequest(const Array<uint8,TCPStream::MaxWebSocketHeaderSize>*array) {
        mArray=array;
        mTotal = 0;
    }
    size_t operator() (const ErrorCode& error, size_t bytes_transferred) {
        if (error) return 0;

        mTotal += bytes_transferred;

        if (mTotal >= 12 &&
            (*mArray)[mTotal - 12] == '\r' &&
            (*mArray)[mTotal - 11] == '\n' &&
            (*mArray)[mTotal - 10] == '\r' &&
            (*mArray)[mTotal - 9] == '\n')
        {
            return 0;
        }
        return 65536;
    }
};
} // namespace

void beginNewStream(TCPSocket*socket, std::tr1::shared_ptr<TCPStreamListener::Data> data) {

    TcpSstHeaderArray *buffer = new TcpSstHeaderArray;

    boost::asio::async_read(*socket,
                            boost::asio::buffer(buffer->begin(),(int)TCPStream::MaxWebSocketHeaderSize>(int)ASIOReadBuffer::sBufferLength?(int)ASIOReadBuffer::sBufferLength:(int)TCPStream::MaxWebSocketHeaderSize),
                            CheckWebSocketRequest (buffer),
        data->strand->wrap( std::tr1::bind(&ASIOStreamBuilder::buildStream,buffer,socket,data,_1,_2) )
        );
}

} // namespace ASIOStreamBuilder
} // namespace Network
} // namespace Sirikata
<|endoftext|>


<commit_before>AliFemtoK0Analysis *AddTaskK0Femto(bool SignDep = kFALSE, bool FieldPositive = kTRUE, bool OnlineCase = kTRUE, bool MeritCase = kTRUE, float MinDL = 0.0, int MeritCutChoice = 4, float MinSep = 5.0, TString nameSpec = "NoSpec"){

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskBF", "No analysis manager to connect to.");
    return NULL;
  }

  AliFemtoK0Analysis *K0Task = new AliFemtoK0Analysis("K0Task", SignDep, FieldPositive, OnlineCase, MeritCase, MinDL, MeritCutChoice, MinSep);
  if(!K0Task) exit(-1);
  mgr->AddTask(K0Task);

  TString outputFileName = AliAnalysisManager::GetCommonFileName();
  outputFileName += ":PWGCF.outputK0Analysis_";
  outputFileName += nameSpec;
  if(SignDep){
   if(FieldPositive) outputFileName += "_FieldPos.root";
   else outputFileName += "_FieldNeg.root";
  }
  AliAnalysisDataContainer *coutputK0 = mgr->CreateContainer("MyList", TList::Class(), AliAnalysisManager::kOutputContainer, outputFileName.Data());

  mgr->ConnectInput(K0Task, 0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(K0Task, 1, coutputK0);

  return K0Task;
}

<commit_msg>K0s code update (Matt Steinpreis)<commit_after>AliFemtoK0Analysis *AddTaskK0Femto(bool SignDep = kFALSE, bool FieldPositive = kTRUE, bool OnlineCase = kTRUE, bool MeritCase = kTRUE, bool Case3D = kFALSE, float MinDL = 0.0, int MeritCutChoice = 4, float MinSep = 5.0, TString nameSpec = "NoSpec"){

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskBF", "No analysis manager to connect to.");
    return NULL;
  }

  AliFemtoK0Analysis *K0Task = new AliFemtoK0Analysis("K0Task", SignDep, FieldPositive, OnlineCase, MeritCase, Case3D, MinDL, MeritCutChoice, MinSep);
  if(!K0Task) exit(-1);
  mgr->AddTask(K0Task);

  TString outputFileName = AliAnalysisManager::GetCommonFileName();
  outputFileName += ":PWGCF.outputK0Analysis_";
  outputFileName += nameSpec;
  if(SignDep){
   if(FieldPositive) outputFileName += "_FieldPos.root";
   else outputFileName += "_FieldNeg.root";
  }
  AliAnalysisDataContainer *coutputK0 = mgr->CreateContainer("MyList", TList::Class(), AliAnalysisManager::kOutputContainer, outputFileName.Data());

  mgr->ConnectInput(K0Task, 0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(K0Task, 1, coutputK0);

  return K0Task;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm 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.
 *
 * glosm 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 glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef ORTHOVIEWER_HH
#define ORTHOVIEWER_HH

#include <glosm/Viewer.hh>
#include <glosm/BBox.hh>

/**
 * Viewer describing orthographic projection.
 *
 * This viewer is useful for tile rendering.
 */
class OrthoViewer : public Viewer {
public:
	OrthoViewer();

	virtual void SetupViewerMatrix(const Projection& projection) const;
	virtual Vector3i GetPos(const Projection& projection) const;

	/**
	 * Sets bounding box of a viewport in global coordinades
	 */
	void SetBBox(const BBoxi& pos);

	/**
	 * Sets bounding box for specific tile in mapnik format.
	 *
	 * @param nx X coordinate of a desired tile
	 * @param ny Y coordinate of a desired tile
	 * @param zoom zoom level of a desired tile
	 */
	void SetBBoxForTile(int nx, int ny, int zoom);

	/**
	 * Sets skew for pseudo-3D effect.
	 *
	 * To retain tile proportions, we can't do proper 3D by
	 * changing viewing angle, but we can 'skew' objects that
	 * have height so their sides appear on a top-down view.
	 * Skew factor may be described as a tangent of desired
	 * viewing angle, 1.0 is equal to 45 degrees.
	 *
	 * @param skew skew ratio
	 */
	void SetSkew(float skew);

protected:
	BBoxi bbox_;
	float skew_;
};

#endif
<commit_msg>Remove unneeded OrthoViewer method<commit_after>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm 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.
 *
 * glosm 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 glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef ORTHOVIEWER_HH
#define ORTHOVIEWER_HH

#include <glosm/Viewer.hh>
#include <glosm/BBox.hh>

/**
 * Viewer describing orthographic projection.
 *
 * This viewer is useful for tile rendering.
 */
class OrthoViewer : public Viewer {
public:
	OrthoViewer();

	virtual void SetupViewerMatrix(const Projection& projection) const;
	virtual Vector3i GetPos(const Projection& projection) const;

	/**
	 * Sets bounding box of a viewport in global coordinades
	 */
	void SetBBox(const BBoxi& pos);

	/**
	 * Sets skew for pseudo-3D effect.
	 *
	 * To retain tile proportions, we can't do proper 3D by
	 * changing viewing angle, but we can 'skew' objects that
	 * have height so their sides appear on a top-down view.
	 * Skew factor may be described as a tangent of desired
	 * viewing angle, 1.0 is equal to 45 degrees.
	 *
	 * @param skew skew ratio
	 */
	void SetSkew(float skew);

protected:
	BBoxi bbox_;
	float skew_;
};

#endif
<|endoftext|>


<commit_before>#pragma once
#include <string>
#include <fc/reflect/reflect.hpp>
#include <fc/exception/exception.hpp>
#include <eosio/chain/exceptions.hpp>
#include <iosfwd>

namespace eosio::chain {
  struct name;
}
namespace fc {
  class variant;
  void to_variant(const eosio::chain::name& c, fc::variant& v);
  void from_variant(const fc::variant& v, eosio::chain::name& check);
} // fc

namespace eosio::chain {
   static constexpr uint64_t char_to_symbol( char c ) {
      if( c >= 'a' && c <= 'z' )
         return (c - 'a') + 6;
      if( c >= '1' && c <= '5' )
         return (c - '1') + 1;
      else if( c == '.')
         return 0;

      EOS_ASSERT(0, name_type_exception, "Name contains invalid character: (${c}) ", ("c", std::string(1, c)));

      //unreachable
      return 0;
   }

   static constexpr uint64_t string_to_uint64_t( std::string_view str ) {
      EOS_ASSERT(str.size() <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", std::string(str)));

      uint64_t n = 0;
      int i = 0;
      for ( ; str[i] && i < 12; ++i) {
         // NOTE: char_to_symbol() returns char type, and without this explicit
         // expansion to uint64 type, the compilation fails at the point of usage
         // of string_to_name(), where the usage requires constant (compile time) expression.
         n |= char_to_symbol(str[i]) << (64 - 5 * (i + 1));
      }

      // The for-loop encoded up to 60 high bits into uint64 'name' variable,
      // if (strlen(str) > 12) then encode str[12] into the low (remaining)
      // 4 bits of 'name'
      if (i == 12 && str[12])
      {
         uint64_t cur_v = char_to_symbol(str[12]);
         EOS_ASSERT(cur_v <= 0x0Full, name_type_exception, "invalid 13th character: (${c})", ("c", std::string(1, str[12])));
         n |= cur_v;
      }
      return n;
   }

   /// Immutable except for fc::from_variant.
   struct name {
   private:
      uint64_t value = 0;

      friend struct fc::reflector<name>;
      friend void fc::from_variant(const fc::variant& v, eosio::chain::name& check);

      void set( std::string_view str );

   public:
      constexpr bool empty()const { return 0 == value; }
      constexpr bool good()const  { return !empty();   }

      explicit name( std::string_view str ) { set( str ); }
      constexpr explicit name( uint64_t v ) : value(v) {}
      constexpr name() = default;

      std::string to_string()const;
      constexpr uint64_t to_uint64_t()const { return value; }

      friend std::ostream& operator << ( std::ostream& out, const name& n ) {
         return out << n.to_string();
      }

      friend constexpr bool operator < ( const name& a, const name& b ) { return a.value < b.value; }
      friend constexpr bool operator > ( const name& a, const name& b ) { return a.value > b.value; }
      friend constexpr bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; }
      friend constexpr bool operator >= ( const name& a, const name& b ) { return a.value >= b.value; }
      friend constexpr bool operator == ( const name& a, const name& b ) { return a.value == b.value; }
      friend constexpr bool operator != ( const name& a, const name& b ) { return a.value != b.value; }

      friend constexpr bool operator == ( const name& a, uint64_t b ) { return a.value == b; }
      friend constexpr bool operator != ( const name& a, uint64_t b ) { return a.value != b; }

      constexpr explicit operator bool()const { return value != 0; }
   };

   // Each char of the string is encoded into 5-bit chunk and left-shifted
   // to its 5-bit slot starting with the highest slot for the first char.
   // The 13th char, if str is long enough, is encoded into 4-bit chunk
   // and placed in the lowest 4 bits. 64 = 12 * 5 + 4
   static constexpr name string_to_name( std::string_view str )
   {
      return name( string_to_uint64_t( str ) );
   }

#define N(X) eosio::chain::string_to_name(#X)

} // eosio::chain

namespace std {
   template<> struct hash<eosio::chain::name> : private hash<uint64_t> {
      typedef eosio::chain::name argument_type;
      size_t operator()(const argument_type& name) const noexcept
      {
         return hash<uint64_t>::operator()(name.to_uint64_t());
      }
   };
};

FC_REFLECT( eosio::chain::name, (value) )
<commit_msg>fix compatability with gcc 8.3.1<commit_after>#pragma once
#include <string>
#include <fc/reflect/reflect.hpp>
#include <fc/exception/exception.hpp>
#include <eosio/chain/exceptions.hpp>
#include <iosfwd>

namespace eosio::chain {
  struct name;
}
namespace fc {
  class variant;
  void to_variant(const eosio::chain::name& c, fc::variant& v);
  void from_variant(const fc::variant& v, eosio::chain::name& check);
} // fc

namespace eosio::chain {
   static constexpr uint64_t char_to_symbol( char c ) {
      if( c >= 'a' && c <= 'z' )
         return (c - 'a') + 6;
      if( c >= '1' && c <= '5' )
         return (c - '1') + 1;
      else if( c == '.')
         return 0;
      else
         FC_THROW_EXCEPTION(name_type_exception, "Name contains invalid character: (${c}) ", ("c", std::string(1, c)));

      //unreachable
      return 0;
   }

   static constexpr uint64_t string_to_uint64_t( std::string_view str ) {
      EOS_ASSERT(str.size() <= 13, name_type_exception, "Name is longer than 13 characters (${name}) ", ("name", std::string(str)));

      uint64_t n = 0;
      int i = 0;
      for ( ; str[i] && i < 12; ++i) {
         // NOTE: char_to_symbol() returns char type, and without this explicit
         // expansion to uint64 type, the compilation fails at the point of usage
         // of string_to_name(), where the usage requires constant (compile time) expression.
         n |= char_to_symbol(str[i]) << (64 - 5 * (i + 1));
      }

      // The for-loop encoded up to 60 high bits into uint64 'name' variable,
      // if (strlen(str) > 12) then encode str[12] into the low (remaining)
      // 4 bits of 'name'
      if (i == 12 && str[12])
      {
         uint64_t cur_v = char_to_symbol(str[12]);
         EOS_ASSERT(cur_v <= 0x0Full, name_type_exception, "invalid 13th character: (${c})", ("c", std::string(1, str[12])));
         n |= cur_v;
      }
      return n;
   }

   /// Immutable except for fc::from_variant.
   struct name {
   private:
      uint64_t value = 0;

      friend struct fc::reflector<name>;
      friend void fc::from_variant(const fc::variant& v, eosio::chain::name& check);

      void set( std::string_view str );

   public:
      constexpr bool empty()const { return 0 == value; }
      constexpr bool good()const  { return !empty();   }

      explicit name( std::string_view str ) { set( str ); }
      constexpr explicit name( uint64_t v ) : value(v) {}
      constexpr name() = default;

      std::string to_string()const;
      constexpr uint64_t to_uint64_t()const { return value; }

      friend std::ostream& operator << ( std::ostream& out, const name& n ) {
         return out << n.to_string();
      }

      friend constexpr bool operator < ( const name& a, const name& b ) { return a.value < b.value; }
      friend constexpr bool operator > ( const name& a, const name& b ) { return a.value > b.value; }
      friend constexpr bool operator <= ( const name& a, const name& b ) { return a.value <= b.value; }
      friend constexpr bool operator >= ( const name& a, const name& b ) { return a.value >= b.value; }
      friend constexpr bool operator == ( const name& a, const name& b ) { return a.value == b.value; }
      friend constexpr bool operator != ( const name& a, const name& b ) { return a.value != b.value; }

      friend constexpr bool operator == ( const name& a, uint64_t b ) { return a.value == b; }
      friend constexpr bool operator != ( const name& a, uint64_t b ) { return a.value != b; }

      constexpr explicit operator bool()const { return value != 0; }
   };

   // Each char of the string is encoded into 5-bit chunk and left-shifted
   // to its 5-bit slot starting with the highest slot for the first char.
   // The 13th char, if str is long enough, is encoded into 4-bit chunk
   // and placed in the lowest 4 bits. 64 = 12 * 5 + 4
   static constexpr name string_to_name( std::string_view str )
   {
      return name( string_to_uint64_t( str ) );
   }

#define N(X) eosio::chain::string_to_name(#X)

} // eosio::chain

namespace std {
   template<> struct hash<eosio::chain::name> : private hash<uint64_t> {
      typedef eosio::chain::name argument_type;
      size_t operator()(const argument_type& name) const noexcept
      {
         return hash<uint64_t>::operator()(name.to_uint64_t());
      }
   };
};

FC_REFLECT( eosio::chain::name, (value) )
<|endoftext|>


<commit_before>/*
  Template of calibration/filtering macro using ESD:
  - requires AliESDs.root and AliESDfriend.root
  - requires OCDB access (default set to "raw://")
  - requires run number as argument to init OCDB
  - calls LoadLibraries.C, ConfigCalibTrain.C and AddTaskTPCCalib.C macros
  - output AliESDfriends_v1.root with TPC and TRD calibration objects are created

  Example:
  .L $ALICE_ROOT/ANALYSIS/macros/runCalibTrain.C
  runCalibTrain("104892");
*/

void runCalibTrain(Int_t runNumber, const char *inFileName = "AliESDs.root", const char *ocdb="raw://")
{
  //
  // macro to run TPC calibration train
  //
  AliSysInfo::SetVerbose(kTRUE);
  AliLog::SetGlobalLogLevel(AliLog::kError);
  gROOT->Macro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/LoadLibraries.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/ConfigCalibTrain.C");
  gSystem->SetIncludePath("-I$ALICE_PHYSICS/include -I$ALICE_ROOT/include");
  /*
  if (gSystem->Exec("cp $ALICE_PHYSICS/PWGPP/CalibMacros/commonMacros/CleanGeom.C ./") ||
      gROOT->LoadMacro("CleanGeom.C++")) { // comple local copy only
    printf("Failed to load/compile CleanGeom, exit\n");
    return;
  }
  */
  // detector tasks
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskTPCCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskTRDCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTOFAnalysisTaskCalibPass0.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTOFAnalysisTaskCalibTree.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskT0Calib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskT0Analysis.C");
  //  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskMeanVertexCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskSDDCalib.C");

  // switch off debug
  AliLog::SetClassDebugLevel("AliESDEvent",0);

  // steering input chain
  TChain *chain = new TChain("esdTree");
  chain->Add(inFileName);

  // config calibration train
  // setting geometry and B-field from GRP
  printf("runNumber from runCalibTrain = %d\n",runNumber);
  printf("ocdb from runCalibTrain = %s\n",ocdb);
  AliSysInfo::AddStamp("BeforeConfiguringCalibTrain");
  ConfigCalibTrain(runNumber, ocdb);
  AliSysInfo::AddStamp("AfterConfiguringCalibTrain");

  if (gROOT->LoadMacro("localOCDBaccessConfig.C")==0) {
    localOCDBaccessConfig();
  }

  //
  // check the presence of the detectors
  AliCDBEntry* entry = AliCDBManager::Instance()->Get("GRP/GRP/Data");
  AliGRPObject* grpData = dynamic_cast<AliGRPObject*>(entry->GetObject());
  if (!grpData) {printf("Failed to get GRP data for run",runNumber); return;}
  Int_t activeDetectors = grpData->GetDetectorMask();
  TString detStr = AliDAQ::ListOfTriggeredDetectors(activeDetectors);
  printf("Detectors in the data:\n%s\n",detStr.Data());

  // setup analysis
  //
  AliAnalysisManager *mgr  = new AliAnalysisManager("ESD to ESD", "Analysis Manager");
  // mgr->SetDebugLevel(3);
  mgr->SetNSysInfo(50);
  mgr->SetCacheSize(0);

  // Input
  AliESDInputHandler* inpHandler = new AliESDInputHandler();
  inpHandler->SetReadFriends(1);
  mgr->SetInputEventHandler(inpHandler);

  // Output
  const char *outFile = "AliESDfriends_v1.root";
  AliESDHandler* esdHandler   = new AliESDHandler();
  mgr->SetOutputEventHandler(esdHandler);
  esdHandler->SetOutputFileName(outFile);
  mgr->SetCommonFileName(outFile);
  //
  // Detector Tasks
  //
  AliSysInfo::AddStamp("BeforeTPC");
  if ( detStr.Contains("TPC"))  AddTaskTPCCalib(runNumber);

  AliSysInfo::AddStamp("BeforeTRD");
  if ( detStr.Contains("TRD") && detStr.Contains("TPC"))  AddTaskTRDCalib(runNumber);

  AliSysInfo::AddStamp("BeforeTOF");
  if ( detStr.Contains("TOF") && detStr.Contains("TPC"))  {
    AddTOFAnalysisTaskCalibPass0();
    AddTOFAnalysisTaskCalibTree();
  }

  AliSysInfo::AddStamp("BeforeT0");
  if ( detStr.Contains("T0"))   {
    AddTaskT0Calib(runNumber);
    AddTaskT0Analysis();
  }

  //if ( detStr.Contains("ITSSPD")) tMeanVtx = AddTaskMeanVertexCalib();
  //
  Bool_t okTPC = detStr.Contains("TPC");
  Bool_t useTPCcrv=kFALSE;
  Bool_t writeITSTP = kFALSE;
  if (!okTPC) useTPCcrv = kFALSE;
  AliSysInfo::AddStamp("BeforeSDD");
  AliAnalysisTaskITSAlignQA *itsAlign = AddTaskSDDCalib(0,writeITSTP,useTPCcrv,detStr.Contains("TOF") ? 10.0:-1);
  if (!okTPC) itsAlign->SetUseITSstandaloneTracks(kTRUE);
  if (grpData->GetL3Current()[0] < 300) itsAlign->SetMinPt(0.001);
  //
  // dummy task to clean geometry in Terminate >>>>
  //CleanGeom* clgmTask = new CleanGeom("cleanGeom");
  //mgr->AddTask(clgmTask);
  //  AliAnalysisDataContainer *dummyInp = mgr->GetCommonInputContainer();
  //   if (dummyInp) mgr->ConnectInput(clgmTask,0,dummyInp);

  // Run the analysis
  AliSysInfo::AddStamp("BeforeInitAnalysis");
  if (!mgr->InitAnalysis()) {
    printf("Analysis cannot be started, returning\n");
    return;
  }

  mgr->PrintStatus();
  AliSysInfo::AddStamp("BeforeStartAnalysis");
  mgr->StartAnalysis("local", chain);

  return;
}
<commit_msg>Restoring use of CleanGeom task<commit_after>/*
  Template of calibration/filtering macro using ESD:
  - requires AliESDs.root and AliESDfriend.root
  - requires OCDB access (default set to "raw://")
  - requires run number as argument to init OCDB
  - calls LoadLibraries.C, ConfigCalibTrain.C and AddTaskTPCCalib.C macros
  - output AliESDfriends_v1.root with TPC and TRD calibration objects are created

  Example:
  .L $ALICE_ROOT/ANALYSIS/macros/runCalibTrain.C
  runCalibTrain("104892");
*/

void runCalibTrain(Int_t runNumber, const char *inFileName = "AliESDs.root", const char *ocdb="raw://")
{
  //
  // macro to run TPC calibration train
  //
  AliSysInfo::SetVerbose(kTRUE);
  AliLog::SetGlobalLogLevel(AliLog::kError);
  gROOT->Macro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/LoadLibraries.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/ConfigCalibTrain.C");
  gSystem->SetIncludePath("-I$ALICE_PHYSICS/include -I$ALICE_ROOT/include");
  if (gSystem->Exec("cp $ALICE_PHYSICS/PWGPP/CalibMacros/commonMacros/CleanGeom.C ./") ||
      gROOT->LoadMacro("CleanGeom.C++")) { // comple local copy only
    printf("Failed to load/compile CleanGeom, exit\n");
    return;
  }
  // detector tasks
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskTPCCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskTRDCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTOFAnalysisTaskCalibPass0.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTOFAnalysisTaskCalibTree.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskT0Calib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskT0Analysis.C");
  //  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskMeanVertexCalib.C");
  gROOT->LoadMacro("$ALICE_PHYSICS/PWGPP/CalibMacros/CPass1/AddTaskSDDCalib.C");

  // switch off debug
  AliLog::SetClassDebugLevel("AliESDEvent",0);

  // steering input chain
  TChain *chain = new TChain("esdTree");
  chain->Add(inFileName);

  // config calibration train
  // setting geometry and B-field from GRP
  printf("runNumber from runCalibTrain = %d\n",runNumber);
  printf("ocdb from runCalibTrain = %s\n",ocdb);
  AliSysInfo::AddStamp("BeforeConfiguringCalibTrain");
  ConfigCalibTrain(runNumber, ocdb);
  AliSysInfo::AddStamp("AfterConfiguringCalibTrain");

  if (gROOT->LoadMacro("localOCDBaccessConfig.C")==0) {
    localOCDBaccessConfig();
  }

  //
  // check the presence of the detectors
  AliCDBEntry* entry = AliCDBManager::Instance()->Get("GRP/GRP/Data");
  AliGRPObject* grpData = dynamic_cast<AliGRPObject*>(entry->GetObject());
  if (!grpData) {printf("Failed to get GRP data for run",runNumber); return;}
  Int_t activeDetectors = grpData->GetDetectorMask();
  TString detStr = AliDAQ::ListOfTriggeredDetectors(activeDetectors);
  printf("Detectors in the data:\n%s\n",detStr.Data());

  // setup analysis
  //
  AliAnalysisManager *mgr  = new AliAnalysisManager("ESD to ESD", "Analysis Manager");
  // mgr->SetDebugLevel(3);
  mgr->SetNSysInfo(50);
  mgr->SetCacheSize(0);

  // Input
  AliESDInputHandler* inpHandler = new AliESDInputHandler();
  inpHandler->SetReadFriends(1);
  mgr->SetInputEventHandler(inpHandler);

  // Output
  const char *outFile = "AliESDfriends_v1.root";
  AliESDHandler* esdHandler   = new AliESDHandler();
  mgr->SetOutputEventHandler(esdHandler);
  esdHandler->SetOutputFileName(outFile);
  mgr->SetCommonFileName(outFile);
  //
  // Detector Tasks
  //
  AliSysInfo::AddStamp("BeforeTPC");
  if ( detStr.Contains("TPC"))  AddTaskTPCCalib(runNumber);

  AliSysInfo::AddStamp("BeforeTRD");
  if ( detStr.Contains("TRD") && detStr.Contains("TPC"))  AddTaskTRDCalib(runNumber);

  AliSysInfo::AddStamp("BeforeTOF");
  if ( detStr.Contains("TOF") && detStr.Contains("TPC"))  {
    AddTOFAnalysisTaskCalibPass0();
    AddTOFAnalysisTaskCalibTree();
  }

  AliSysInfo::AddStamp("BeforeT0");
  if ( detStr.Contains("T0"))   {
    AddTaskT0Calib(runNumber);
    AddTaskT0Analysis();
  }

  //if ( detStr.Contains("ITSSPD")) tMeanVtx = AddTaskMeanVertexCalib();
  //
  Bool_t okTPC = detStr.Contains("TPC");
  Bool_t useTPCcrv=kFALSE;
  Bool_t writeITSTP = kFALSE;
  if (!okTPC) useTPCcrv = kFALSE;
  AliSysInfo::AddStamp("BeforeSDD");
  AliAnalysisTaskITSAlignQA *itsAlign = AddTaskSDDCalib(0,writeITSTP,useTPCcrv,detStr.Contains("TOF") ? 10.0:-1);
  if (!okTPC) itsAlign->SetUseITSstandaloneTracks(kTRUE);
  if (grpData->GetL3Current()[0] < 300) itsAlign->SetMinPt(0.001);
  //
  // dummy task to clean geometry in Terminate >>>>
  CleanGeom* clgmTask = new CleanGeom("cleanGeom");
  mgr->AddTask(clgmTask);
  AliAnalysisDataContainer *dummyInp = mgr->GetCommonInputContainer();
  if (dummyInp) mgr->ConnectInput(clgmTask,0,dummyInp);

  // Run the analysis
  AliSysInfo::AddStamp("BeforeInitAnalysis");
  if (!mgr->InitAnalysis()) {
    printf("Analysis cannot be started, returning\n");
    return;
  }

  mgr->PrintStatus();
  AliSysInfo::AddStamp("BeforeStartAnalysis");
  mgr->StartAnalysis("local", chain);

  return;
}
<|endoftext|>


<commit_before>// Qt includes
#include <QUrl>
#include <QRegExp>
#include <QStringRef>

#include <xbmcvideochecker/XBMCVideoChecker.h>

// Request player example:
// {"jsonrpc":"2.0","method":"Player.GetActivePlayers", "id":666}
// {"id":666,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}

// Request playing item example:
// {"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":1,"properties":["file"]}}
// {"id":667,"jsonrpc":"2.0","result":{"item":{"file":"smb://xbmc:xbmc@192.168.53.12/video/Movies/Avatar (2009)/Avatar.mkv","label":"Avatar","type":"unknown"}}}

// Request if screensaver is on
// {"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}}
// {"id":668,"jsonrpc":"2.0","result":{"System.ScreenSaverActive":false}}

// Request stereoscopicmode example:
// {"jsonrpc":"2.0","method":"GUI.GetProperties","params":{"properties":["stereoscopicmode"]},"id":669}
// {"id":669,"jsonrpc":"2.0","result":{"stereoscopicmode":{"label":"Nebeneinander","mode":"split_vertical"}}}

XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection) :
	QObject(),
	_address(QString::fromStdString(address)),
	_port(port),
	_activePlayerRequest(R"({"jsonrpc":"2.0","method":"Player.GetActivePlayers", "id":666})"),
	_currentPlayingItemRequest(R"({"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":%1,"properties":["file"]}})"),
	_checkScreensaverRequest(R"({"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}})"),
	_getStereoscopicMode(R"({"jsonrpc":"2.0","method":"GUI.GetProperties","params":{"properties":["stereoscopicmode"]},"id":669})"),
	_getXbmcVersion(R"({"jsonrpc":"2.0","method":"Application.GetProperties","params":{"properties":["version"]},"id":670})"),
	_socket(),
	_grabVideo(grabVideo),
	_grabPhoto(grabPhoto),
	_grabAudio(grabAudio),
	_grabMenu(grabMenu),
	_grabScreensaver(grabScreensaver),
	_enable3DDetection(enable3DDetection),
	_previousScreensaverMode(false),
	_previousGrabbingMode(GRABBINGMODE_INVALID),
	_previousVideoMode(VIDEO_2D),
	_xbmcVersion(0)
{
	// setup socket
	connect(&_socket, SIGNAL(readyRead()), this, SLOT(receiveReply()));
	connect(&_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
	connect(&_socket, SIGNAL(connected()), this, SLOT(connected()));
	connect(&_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));
}

void XBMCVideoChecker::start()
{
	reconnect();
}

void XBMCVideoChecker::receiveReply()
{
	// expect that the reply is received as a single message. Probably oke considering the size of the expected reply
	QString reply(_socket.readAll());

	std::cout << "KODICHECK INFO: Kodi Message: " << reply.toStdString() << std::endl;

	if (reply.contains("\"method\":\"Player.OnPlay\"") || reply.contains("\"method\":\"Playlist.OnAdd\""))
	{
		// send a request for the current player state
		_socket.write(_activePlayerRequest.toUtf8());
		return;
	}
	else if (reply.contains("\"method\":\"Player.OnStop\""))
	{
		// the player has stopped
		setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
		setVideoMode(VIDEO_2D);
	}
	else if (reply.contains("\"method\":\"GUI.OnScreensaverActivated\""))
	{
		setScreensaverMode(!_grabScreensaver);
	}
	else if (reply.contains("\"method\":\"GUI.OnScreensaverDeactivated\""))
	{
		setScreensaverMode(false);
	}
	else if (reply.contains("\"id\":666"))
	{
		// Result of Player.GetActivePlayers

		// always start a new video in 2D mode
		emit videoMode(VIDEO_2D);

		if (reply.contains("video"))
		{
			// video is playing
			setGrabbingMode(_grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF);

			// we need to get the filename
			// first retrieve the playerid
			QString key = "\"playerid\":";
			QRegExp regex(key + "(\\d+)");
			int pos = regex.indexIn(reply);
			if (pos > 0)
			{
				// now request info of the playing item
				QStringRef idText(&reply, pos + key.length(), regex.matchedLength() - key.length());
				_socket.write(_currentPlayingItemRequest.arg(idText.toString()).toUtf8());
			}
		}
		else if (reply.contains("picture"))
		{
			// picture viewer is playing
			setGrabbingMode(_grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF);
		}
		else if (reply.contains("audio"))
		{
			// audio is playing
			setGrabbingMode(_grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF);
		}
		else
		{
			// Nothing is playing.
			setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
		}
	}
	else if (reply.contains("\"id\":667"))
	{
		if (_xbmcVersion >= 13)
		{
			// check of active stereoscopicmode
			_socket.write(_getStereoscopicMode.toUtf8());
		}
		else
		{
			// result of Player.GetItem
			// TODO: what if the filename contains a '"'. In Json this should have been escaped
			QRegExp regex("\"file\":\"((?!\").)*\"");
			int pos = regex.indexIn(reply);
			if (pos > 0)
			{
				QStringRef filename = QStringRef(&reply, pos+8, regex.matchedLength()-9);
				if (filename.contains("3DSBS", Qt::CaseInsensitive) || filename.contains("HSBS", Qt::CaseInsensitive))
				{
					setVideoMode(VIDEO_3DSBS);
				}
				else if (filename.contains("3DTAB", Qt::CaseInsensitive) || filename.contains("HTAB", Qt::CaseInsensitive))
				{
					setVideoMode(VIDEO_3DTAB);
				}
				else
				{
					setVideoMode(VIDEO_2D);
				}
			}
		}
	}
	else if (reply.contains("\"id\":668"))
	{
		// result of System.ScreenSaverActive
		bool active = reply.contains("\"System.ScreenSaverActive\":true");
		setScreensaverMode(!_grabScreensaver && active);

		// check here xbmc version
		if (_socket.state() == QTcpSocket::ConnectedState)
		{
			if (_xbmcVersion == 0)
			{
				_socket.write(_getXbmcVersion.toUtf8());
			}
		}
	}
	else if (reply.contains("\"id\":669"))
	{
		QRegExp regex("\"mode\":\"(split_vertical|split_horizontal)\"");
		int pos = regex.indexIn(reply);
		if (pos > 0)
		{
			QString sMode = regex.cap(1);
			if (sMode == "split_vertical")
			{
				setVideoMode(VIDEO_3DSBS);
			}
			else if (sMode == "split_horizontal")
			{
				setVideoMode(VIDEO_3DTAB);
			}
		}
	}
	else if (reply.contains("\"id\":670"))
	{
		QRegExp regex("\"major\":(\\d+)");
		int pos = regex.indexIn(reply);
		if (pos > 0)
		{
			_xbmcVersion = regex.cap(1).toInt();
		}
	}
}

void XBMCVideoChecker::connected()
{
	std::cout << "KODICHECK INFO: Kodi Connected" << std::endl;

	// send a request for the current player state
	_socket.write(_activePlayerRequest.toUtf8());
	_socket.write(_checkScreensaverRequest.toUtf8());
}

void XBMCVideoChecker::disconnected()
{
	std::cout << "KODICHECK INFO: Kodi Disconnected" << std::endl;
	reconnect();
}

void XBMCVideoChecker::reconnect()
{
	if (_socket.state() == QTcpSocket::ConnectedState)
	{
		return;
	}

	// try to connect
	switch (_socket.state())
	{
	case QTcpSocket::ConnectingState:
		// Somehow when XBMC restarts we get stuck in connecting state
		// If we get here we tried to connect already for 5 seconds. abort and try again in 1 second.
		_socket.reset();
		_socket.waitForDisconnected(50);
		QTimer::singleShot(1000, this, SLOT(reconnect()));
		break;
	case QTcpSocket::UnconnectedState:
		_socket.connectToHost(_address, _port);
		QTimer::singleShot(10000, this, SLOT(reconnect()));
		break;
	default:
		QTimer::singleShot(10000, this, SLOT(reconnect()));
		break;
	}
}

void XBMCVideoChecker::connectionError(QAbstractSocket::SocketError error)
{
	std::cout << "KODICHECK ERROR: Kodi Connection error (" << error << ")" << std::endl;

	// close the socket
	_socket.close();
}

void XBMCVideoChecker::setGrabbingMode(GrabbingMode newGrabbingMode)
{
	if (newGrabbingMode == _previousGrabbingMode)
	{
		// no change
		return;
	}

	switch (newGrabbingMode)
	{
	case GRABBINGMODE_VIDEO:
		std::cout << "KODICHECK INFO: switching to VIDEO mode" << std::endl;
		break;
	case GRABBINGMODE_PHOTO:
		std::cout << "KODICHECK INFO: switching to PHOTO mode" << std::endl;
		break;
	case GRABBINGMODE_AUDIO:
		std::cout << "KODICHECK INFO: switching to AUDIO mode" << std::endl;
		break;
	case GRABBINGMODE_MENU:
		std::cout << "KODICHECK INFO: switching to MENU mode" << std::endl;
		break;
	case GRABBINGMODE_OFF:
		std::cout << "KODICHECK INFO: switching to OFF mode" << std::endl;
		break;
	case GRABBINGMODE_INVALID:
		std::cout << "KODICHECK INFO: switching to INVALID mode" << std::endl;
		break;
	}

	// only emit the new state when we want to grab in screensaver mode or when the screensaver is deactivated
	if (!_previousScreensaverMode)
	{
		emit grabbingMode(newGrabbingMode);
	}
	_previousGrabbingMode = newGrabbingMode;
}

void XBMCVideoChecker::setScreensaverMode(bool isOnScreensaver)
{
	if (isOnScreensaver == _previousScreensaverMode)
	{
		// no change
		return;
	}

	emit grabbingMode(isOnScreensaver ? GRABBINGMODE_OFF : _previousGrabbingMode);
	_previousScreensaverMode = isOnScreensaver;
}

void XBMCVideoChecker::setVideoMode(VideoMode newVideoMode)
{
	if (newVideoMode == _previousVideoMode)
	{
		// no change
		return;
	}

	switch (newVideoMode)
	{
	case VIDEO_2D:
		std::cout << "KODICHECK INFO: switching to 2D mode" << std::endl;
		break;
	case VIDEO_3DSBS:
		std::cout << "KODICHECK INFO: switching to 3D SBS mode" << std::endl;
		break;
	case VIDEO_3DTAB:
		std::cout << "KODICHECK INFO: switching to 3D TAB mode" << std::endl;
		break;
	}

	emit videoMode(newVideoMode);
	_previousVideoMode = newVideoMode;
}
<commit_msg>xbmc checker fix (3)<commit_after>// Qt includes
#include <QUrl>
#include <QRegExp>
#include <QStringRef>

#include <xbmcvideochecker/XBMCVideoChecker.h>

// Request player example:
// {"jsonrpc":"2.0","method":"Player.GetActivePlayers", "id":666}
// {"id":666,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}

// Request playing item example:
// {"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":1,"properties":["file"]}}
// {"id":667,"jsonrpc":"2.0","result":{"item":{"file":"smb://xbmc:xbmc@192.168.53.12/video/Movies/Avatar (2009)/Avatar.mkv","label":"Avatar","type":"unknown"}}}

// Request if screensaver is on
// {"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}}
// {"id":668,"jsonrpc":"2.0","result":{"System.ScreenSaverActive":false}}

// Request stereoscopicmode example:
// {"jsonrpc":"2.0","method":"GUI.GetProperties","params":{"properties":["stereoscopicmode"]},"id":669}
// {"id":669,"jsonrpc":"2.0","result":{"stereoscopicmode":{"label":"Nebeneinander","mode":"split_vertical"}}}

XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection) :
	QObject(),
	_address(QString::fromStdString(address)),
	_port(port),
	_activePlayerRequest(R"({"jsonrpc":"2.0","method":"Player.GetActivePlayers", "id":666})"),
	_currentPlayingItemRequest(R"({"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":%1,"properties":["file"]}})"),
	_checkScreensaverRequest(R"({"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}})"),
	_getStereoscopicMode(R"({"jsonrpc":"2.0","method":"GUI.GetProperties","params":{"properties":["stereoscopicmode"]},"id":669})"),
	_getXbmcVersion(R"({"jsonrpc":"2.0","method":"Application.GetProperties","params":{"properties":["version"]},"id":670})"),
	_socket(),
	_grabVideo(grabVideo),
	_grabPhoto(grabPhoto),
	_grabAudio(grabAudio),
	_grabMenu(grabMenu),
	_grabScreensaver(grabScreensaver),
	_enable3DDetection(enable3DDetection),
	_previousScreensaverMode(false),
	_previousGrabbingMode(GRABBINGMODE_INVALID),
	_previousVideoMode(VIDEO_2D),
	_xbmcVersion(0)
{
	// setup socket
	connect(&_socket, SIGNAL(readyRead()), this, SLOT(receiveReply()));
	connect(&_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
	connect(&_socket, SIGNAL(connected()), this, SLOT(connected()));
	connect(&_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));
}

void XBMCVideoChecker::start()
{
	reconnect();
}

void XBMCVideoChecker::receiveReply()
{
	// expect that the reply is received as a single message. Probably oke considering the size of the expected reply
	QString reply(_socket.readAll());

	std::cout << "KODICHECK INFO: Kodi Message: " << reply.toStdString() << std::endl;

	if (reply.contains("\"method\":\"Player.OnPlay\""))
	{
		// send a request for the current player state
		_socket.write(_activePlayerRequest.toUtf8());
		return;
	}
	else if (reply.contains("\"method\":\"Player.OnStop\""))
	{
		// the player has stopped
		setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
		setVideoMode(VIDEO_2D);
	}
	else if (reply.contains("\"method\":\"GUI.OnScreensaverActivated\""))
	{
		setScreensaverMode(!_grabScreensaver);
	}
	else if (reply.contains("\"method\":\"GUI.OnScreensaverDeactivated\""))
	{
		setScreensaverMode(false);
	}
	else if (reply.contains("\"id\":666"))
	{
		// Result of Player.GetActivePlayers

		// always start a new video in 2D mode
		emit videoMode(VIDEO_2D);

		if (reply.contains("video"))
		{
			// video is playing
			setGrabbingMode(_grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF);

			// we need to get the filename
			// first retrieve the playerid
			QString key = "\"playerid\":";
			QRegExp regex(key + "(\\d+)");
			int pos = regex.indexIn(reply);
			if (pos > 0)
			{
				// now request info of the playing item
				QStringRef idText(&reply, pos + key.length(), regex.matchedLength() - key.length());
				_socket.write(_currentPlayingItemRequest.arg(idText.toString()).toUtf8());
			}
		}
		else if (reply.contains("picture"))
		{
			// picture viewer is playing
			setGrabbingMode(_grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF);
		}
		else if (reply.contains("audio"))
		{
			// audio is playing
			setGrabbingMode(_grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF);
		}
		else
		{
			// Nothing is playing.
			setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
		}
	}
	else if (reply.contains("\"id\":667"))
	{
		if (_xbmcVersion >= 13)
		{
			// check of active stereoscopicmode
			_socket.write(_getStereoscopicMode.toUtf8());
		}
		else
		{
			// result of Player.GetItem
			// TODO: what if the filename contains a '"'. In Json this should have been escaped
			QRegExp regex("\"file\":\"((?!\").)*\"");
			int pos = regex.indexIn(reply);
			if (pos > 0)
			{
				QStringRef filename = QStringRef(&reply, pos+8, regex.matchedLength()-9);
				if (filename.contains("3DSBS", Qt::CaseInsensitive) || filename.contains("HSBS", Qt::CaseInsensitive))
				{
					setVideoMode(VIDEO_3DSBS);
				}
				else if (filename.contains("3DTAB", Qt::CaseInsensitive) || filename.contains("HTAB", Qt::CaseInsensitive))
				{
					setVideoMode(VIDEO_3DTAB);
				}
				else
				{
					setVideoMode(VIDEO_2D);
				}
			}
		}
	}
	else if (reply.contains("\"id\":668"))
	{
		// result of System.ScreenSaverActive
		bool active = reply.contains("\"System.ScreenSaverActive\":true");
		setScreensaverMode(!_grabScreensaver && active);

		// check here xbmc version
		if (_socket.state() == QTcpSocket::ConnectedState)
		{
			if (_xbmcVersion == 0)
			{
				_socket.write(_getXbmcVersion.toUtf8());
			}
		}
	}
	else if (reply.contains("\"id\":669"))
	{
		QRegExp regex("\"mode\":\"(split_vertical|split_horizontal)\"");
		int pos = regex.indexIn(reply);
		if (pos > 0)
		{
			QString sMode = regex.cap(1);
			if (sMode == "split_vertical")
			{
				setVideoMode(VIDEO_3DSBS);
			}
			else if (sMode == "split_horizontal")
			{
				setVideoMode(VIDEO_3DTAB);
			}
		}
	}
	else if (reply.contains("\"id\":670"))
	{
		QRegExp regex("\"major\":(\\d+)");
		int pos = regex.indexIn(reply);
		if (pos > 0)
		{
			_xbmcVersion = regex.cap(1).toInt();
		}
	}
	else if (reply.contains("picture") && reply.contains("\"method\":\"Playlist.OnAdd\""))
	{
		// picture viewer is playing
		setGrabbingMode(_grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF);
	}
}

void XBMCVideoChecker::connected()
{
	std::cout << "KODICHECK INFO: Kodi Connected" << std::endl;

	// send a request for the current player state
	_socket.write(_activePlayerRequest.toUtf8());
	_socket.write(_checkScreensaverRequest.toUtf8());
}

void XBMCVideoChecker::disconnected()
{
	std::cout << "KODICHECK INFO: Kodi Disconnected" << std::endl;
	reconnect();
}

void XBMCVideoChecker::reconnect()
{
	if (_socket.state() == QTcpSocket::ConnectedState)
	{
		return;
	}

	// try to connect
	switch (_socket.state())
	{
	case QTcpSocket::ConnectingState:
		// Somehow when XBMC restarts we get stuck in connecting state
		// If we get here we tried to connect already for 5 seconds. abort and try again in 1 second.
		_socket.reset();
		_socket.waitForDisconnected(50);
		QTimer::singleShot(1000, this, SLOT(reconnect()));
		break;
	case QTcpSocket::UnconnectedState:
		_socket.connectToHost(_address, _port);
		QTimer::singleShot(10000, this, SLOT(reconnect()));
		break;
	default:
		QTimer::singleShot(10000, this, SLOT(reconnect()));
		break;
	}
}

void XBMCVideoChecker::connectionError(QAbstractSocket::SocketError error)
{
	std::cout << "KODICHECK ERROR: Kodi Connection error (" << error << ")" << std::endl;

	// close the socket
	_socket.close();
}

void XBMCVideoChecker::setGrabbingMode(GrabbingMode newGrabbingMode)
{
	if (newGrabbingMode == _previousGrabbingMode)
	{
		// no change
		return;
	}

	switch (newGrabbingMode)
	{
	case GRABBINGMODE_VIDEO:
		std::cout << "KODICHECK INFO: switching to VIDEO mode" << std::endl;
		break;
	case GRABBINGMODE_PHOTO:
		std::cout << "KODICHECK INFO: switching to PHOTO mode" << std::endl;
		break;
	case GRABBINGMODE_AUDIO:
		std::cout << "KODICHECK INFO: switching to AUDIO mode" << std::endl;
		break;
	case GRABBINGMODE_MENU:
		std::cout << "KODICHECK INFO: switching to MENU mode" << std::endl;
		break;
	case GRABBINGMODE_OFF:
		std::cout << "KODICHECK INFO: switching to OFF mode" << std::endl;
		break;
	case GRABBINGMODE_INVALID:
		std::cout << "KODICHECK INFO: switching to INVALID mode" << std::endl;
		break;
	}

	// only emit the new state when we want to grab in screensaver mode or when the screensaver is deactivated
	if (!_previousScreensaverMode)
	{
		emit grabbingMode(newGrabbingMode);
	}
	_previousGrabbingMode = newGrabbingMode;
}

void XBMCVideoChecker::setScreensaverMode(bool isOnScreensaver)
{
	if (isOnScreensaver == _previousScreensaverMode)
	{
		// no change
		return;
	}

	emit grabbingMode(isOnScreensaver ? GRABBINGMODE_OFF : _previousGrabbingMode);
	_previousScreensaverMode = isOnScreensaver;
}

void XBMCVideoChecker::setVideoMode(VideoMode newVideoMode)
{
	if (newVideoMode == _previousVideoMode)
	{
		// no change
		return;
	}

	switch (newVideoMode)
	{
	case VIDEO_2D:
		std::cout << "KODICHECK INFO: switching to 2D mode" << std::endl;
		break;
	case VIDEO_3DSBS:
		std::cout << "KODICHECK INFO: switching to 3D SBS mode" << std::endl;
		break;
	case VIDEO_3DTAB:
		std::cout << "KODICHECK INFO: switching to 3D TAB mode" << std::endl;
		break;
	}

	emit videoMode(newVideoMode);
	_previousVideoMode = newVideoMode;
}
<|endoftext|>