<commit_before>#include "graphics/gl_ext.h"

PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLLINGPROGRAMPROC glLinkProgram;
PFNGLGETATTRIBLOCATION glGetAttribLocation;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i;
PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f;
PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f;
PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;

void loadGLExtensions()
{
	glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
	glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers");
	glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
	glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
	glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
	glLinkProgram = (PFNGLLINGPROGRAMPROC)wglGetProcAddress("glLinkProgram");
	glGetAttribLocation = (PFNGLGETATTRIBLOCATION)wglGetProcAddress("glGetAttribLocation");
	glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
	glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
	glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)wglGetProcAddress("glProgramUniform1i");
	glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)wglGetProcAddress("glProgramUniform1f");
	glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)wglGetProcAddress("glProgramUniform3f");
	glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)wglGetProcAddress("glProgramUniformMatrix4fv");
	glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
	glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
	glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
	glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
	glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
	glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
	glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
	glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
	glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
	glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
	glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress("glGenFramebuffers");
	glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress("glGenRenderbuffers");
	glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebuffer");
	glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress("glFramebufferRenderbuffer");
	glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress("glFramebufferTexture2D");
	glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress("glRenderbufferStorage");
	glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress("glBindRenderbuffer");
	glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress("glDeleteFramebuffers");
}<commit_msg>the loading of some gl extensions fixed<commit_after>#include "graphics/gl_ext.h"
#include <cstdio>

PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLLINGPROGRAMPROC glLinkProgram;
PFNGLGETATTRIBLOCATION glGetAttribLocation;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i;
PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f;
PFNGLPROGRAMUNIFORM3FPROC glProgramUniform3f;
PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;

PROC loadGLExtension(const char* name, float gl_version)
{
	if (gl_version >= 3.0f)
	{
		return wglGetProcAddress(name);
	}
	else
	{
		char tmp[200];
		sprintf_s(tmp, "%sEXT", name);
		return wglGetProcAddress(tmp);
	}
}

void loadGLExtensions()
{
	const char* gl_version_str = reinterpret_cast<const char*>(glGetString(GL_VERSION));
	float gl_version = (float)atof(gl_version_str);
	glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
	glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers");
	glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
	glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
	glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
	glLinkProgram = (PFNGLLINGPROGRAMPROC)wglGetProcAddress("glLinkProgram");
	glGetAttribLocation = (PFNGLGETATTRIBLOCATION)wglGetProcAddress("glGetAttribLocation");
	glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
	glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
	glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
	glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
	glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
	glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
	glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
	glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
	glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
	glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
	glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
	glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");

	glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)loadGLExtension("glGenFramebuffers", gl_version);
	glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)loadGLExtension("glGenRenderbuffers", gl_version);
	glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)loadGLExtension("glBindFramebuffer", gl_version);
	glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)loadGLExtension("glFramebufferRenderbuffer", gl_version);
	glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)loadGLExtension("glFramebufferTexture2D", gl_version);
	glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)loadGLExtension("glRenderbufferStorage", gl_version);
	glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)loadGLExtension("glBindRenderbuffer", gl_version);
	glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)loadGLExtension("glDeleteFramebuffers", gl_version);
	glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)loadGLExtension("glProgramUniformMatrix4fv", gl_version);
	glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)loadGLExtension("glProgramUniform1i", gl_version);
	glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)loadGLExtension("glProgramUniform1f", gl_version);
	glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)loadGLExtension("glProgramUniform3f", gl_version);

}<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 Weitian Leung
 *
 * This file is part of LyricsX.
 *
 * This file is distributed under the MIT License.
 * See the LICENSE file for details.
 *
*/

#include "application.h"

#include <QSettings>
#include <QIcon>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>

LRCX_BEGIN_NS

Application::Application(int &argc, char **argv)
	: QApplication(argc, argv)
{
	setApplicationName("lrcx");
	setWindowIcon(QIcon::fromTheme(QLatin1String("lyricsx"), QIcon(":/icons/32x32/lyricsx")));

	QString translation_dirs[] =
	{
		applicationDirPath() + "/translations",
		QStringLiteral(LRCX_TRANSLAIONS_DIR),
	};

	for (const QString &dir : translation_dirs)
	{
		QTranslator *translator = new QTranslator;
		if (translator->load(QLocale::system(), QString(), QString(), dir))
			installTranslator(translator);
		else
			delete translator;
	}

	// Qt translations
	QString qt_translation_dirs[] =
	{
		applicationDirPath() + "/translations",
		QLibraryInfo::location(QLibraryInfo::TranslationsPath),
	};

	for (const QString &dir : qt_translation_dirs)
	{
		QTranslator *translator = new QTranslator;
		if(translator->load(QLocale::system(), "qt", "_", dir))
			installTranslator(translator);
		else
			delete translator;
	}

	m_settings.reset(new QSettings(QSettings::NativeFormat,
								   QSettings::UserScope,
								   QLatin1String("lrcx")
								   )
					 );
}

Application::~Application()
{
}

QVariant Application::settings(AppSettings as) const
{
	const QString &key = asToString(as);

	return m_settings->value(key);
}

void Application::setSetting(AppSettings as, const QVariant &value)
{
	const QString &key = asToString(as);
	m_settings->setValue(key, value);
}

const QString& Application::asToString(AppSettings as) const
{
	static std::map<AppSettings, QString> s_map =
	{
		{ AS_WindowPostion,      "WindowPos" },
		{ AS_WindowMaximized,    "WindowMax" },
		{ AS_LrcLastDir,         "LrcLastDir" },
		{ AS_MusicLastDir,       "MusicLastDir" },
		{ AS_EditorFontFamily,   "EditorFont" },
		{ AS_EditorFontStyle,    "EditorFontStyle" },
		{ AS_EditorFontSize,     "EditorFontSize" },
		{ AS_LrcEditor,          "LrcEditor" },
	};

	return s_map[as];
}

LRCX_END_NS
<commit_msg>add data path for qt translation<commit_after>/**
 * Copyright (c) 2016 Weitian Leung
 *
 * This file is part of LyricsX.
 *
 * This file is distributed under the MIT License.
 * See the LICENSE file for details.
 *
*/

#include "application.h"

#include <QSettings>
#include <QIcon>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>

LRCX_BEGIN_NS

Application::Application(int &argc, char **argv)
	: QApplication(argc, argv)
{
	setApplicationName("lrcx");
	setWindowIcon(QIcon::fromTheme(QLatin1String("lyricsx"), QIcon(":/icons/32x32/lyricsx")));

	QString translation_dirs[] =
	{
		applicationDirPath() + "/translations",
		QStringLiteral(LRCX_TRANSLAIONS_DIR),
	};

	for (const QString &dir : translation_dirs)
	{
		QTranslator *translator = new QTranslator;
		if (translator->load(QLocale::system(), QString(), QString(), dir))
			installTranslator(translator);
		else
			delete translator;
	}

	// Qt translations
	QString qt_translation_dirs[] =
	{
		applicationDirPath() + "/translations",
		QStringLiteral(LRCX_TRANSLAIONS_DIR),
		QLibraryInfo::location(QLibraryInfo::TranslationsPath),
	};

	for (const QString &dir : qt_translation_dirs)
	{
		QTranslator *translator = new QTranslator;
		if(translator->load(QLocale::system(), "qt", "_", dir))
			installTranslator(translator);
		else
			delete translator;
	}

	m_settings.reset(new QSettings(QSettings::NativeFormat,
								   QSettings::UserScope,
								   QLatin1String("lrcx")
								   )
					 );
}

Application::~Application()
{
}

QVariant Application::settings(AppSettings as) const
{
	const QString &key = asToString(as);

	return m_settings->value(key);
}

void Application::setSetting(AppSettings as, const QVariant &value)
{
	const QString &key = asToString(as);
	m_settings->setValue(key, value);
}

const QString& Application::asToString(AppSettings as) const
{
	static std::map<AppSettings, QString> s_map =
	{
		{ AS_WindowPostion,      "WindowPos" },
		{ AS_WindowMaximized,    "WindowMax" },
		{ AS_LrcLastDir,         "LrcLastDir" },
		{ AS_MusicLastDir,       "MusicLastDir" },
		{ AS_EditorFontFamily,   "EditorFont" },
		{ AS_EditorFontStyle,    "EditorFontStyle" },
		{ AS_EditorFontSize,     "EditorFontSize" },
		{ AS_LrcEditor,          "LrcEditor" },
	};

	return s_map[as];
}

LRCX_END_NS
<|endoftext|>


<commit_before>#include <armadillo>

#include "settings.h"
#include "RigidAlignment.h"

#include "landmark/LandmarkIO.h"

#include "mesh/MeshIO.h"
#include "mesh/Mesh.h"
#include "mesh/MeshNeighbors.h"
#include "mesh/MeshNeighborsIO.h"
#include "mesh/MeshOneRingNeighborsBuilder.h"
#include "mesh/MeshGeodesicNeighborsBuilder.h"
#include "mesh/MeshSphericalNeighborsBuilder.h"
#include "mesh/MeshResolution.h"

#include "mesh/MeshSmooth.h"

#include "optimization/matchtemplate/Energy.h"
#include "optimization/matchtemplate/EnergyMinimizer.h"
#include "optimization/matchtemplate/MinimizerSettings.h"

int main(int argc, char* argv[]) {

  Settings settings(argc, argv);

  // read input data
  Mesh source = MeshIO::read(settings.source);
  Mesh target = MeshIO::read(settings.target);

  if( settings.performRigidAlignment == true) {

    source = RigidAlignment(source, target, settings).perform();

  }

  // deal with target meshes that do not provide normals
  if( settings.fixedNeighbors == false && target.has_normals() == false ) {

    // try to estimate normals if the mesh has faces
    if( target.has_faces() == true ) {
      NormalEstimation estimation(target);
      target.set_vertex_normals(estimation.compute());
    } // end if
    else {
      // use point-to-point distance measure
      settings.energySettings.searchStrategy =
        matchTemplate::EnergySettings::SearchStrategy::BASIC;
    } // end else

  } // end if

  MeshResolution resolution(source);

  arma::vec min, max;

  source.get_bounding_box(min, max);

  const double scaleFactor = 1. / arma::norm( max - min );

  settings.energySettings.maxDistance  *= scaleFactor;
  settings.energySettings.searchRadius *= scaleFactor;

  MeshNeighbors neighbors;

  if( settings.meshNeighborhoodPresent == true ) {
    neighbors = MeshNeighborsIO::read(settings.meshNeighborhood);
  }
  else {
    MeshOneRingNeighborsBuilder builder(source);
    neighbors = neighbors + builder.get_neighbors();

    if( settings.addGeodesic == true ) {

      MeshGeodesicNeighborsBuilder builder(
        source, resolution.get_resolution() * settings.geodesicNeighborhoodSize);
      neighbors = neighbors + builder.get_neighbors();

    }

    if( settings.addSpherical == true ) {

      MeshSphericalNeighborsBuilder builder(
        source, resolution.get_resolution() * settings.geodesicNeighborhoodSize);
      neighbors = neighbors + builder.get_neighbors();

    }
  }

  for( arma::vec& vertex: source.get_vertices() ) {
    vertex *= scaleFactor;
  }

  for( arma::vec& vertex: target.get_vertices() ) {
    vertex *= scaleFactor;
  }

  matchTemplate::EnergyData data(source, neighbors, target);

  if(settings.landmarksPresent == true) {
    data.landmarks = LandmarkIO::read(settings.landmarks);

    for( Landmark& mark: data.landmarks ) {

      mark.targetPosition *= scaleFactor;

    }

  }

  settings.energySettings.weights["dataTerm"] = 1;
  settings.energySettings.weights["smoothnessTerm"] = settings.smoothnessTermWeight;
  settings.energySettings.weights["postSmoothnessTerm"] = settings.postSmoothnessTermWeight;
  settings.energySettings.changeFactors["smoothnessTerm"] = settings.smoothnessTermChange;
  settings.energySettings.weights["landmarkTerm"] = settings.landmarkTermWeight;
  settings.energySettings.changeFactors["landmarkTerm"] = settings.landmarkTermChange;

  matchTemplate::Energy energy(data, settings.energySettings);

  matchTemplate::EnergyMinimizer minimizer(energy, settings.minimizerSettings);

  minimizer.minimize();

  for( arma::vec& vertex: energy.derived_data().source.get_vertices() ) {
    vertex /= scaleFactor;
  }

  Mesh result = energy.derived_data().source;

  // remove normals
  result.get_vertex_normals().clear();

  MeshSmooth(result).apply(settings.meshSmoothIterations);

  MeshIO::write(result, settings.output);

  return 0;

}
<commit_msg>fixed mistake<commit_after>#include <armadillo>

#include "settings.h"
#include "RigidAlignment.h"

#include "landmark/LandmarkIO.h"

#include "mesh/MeshIO.h"
#include "mesh/Mesh.h"
#include "mesh/MeshNeighbors.h"
#include "mesh/MeshNeighborsIO.h"
#include "mesh/MeshOneRingNeighborsBuilder.h"
#include "mesh/MeshGeodesicNeighborsBuilder.h"
#include "mesh/MeshSphericalNeighborsBuilder.h"
#include "mesh/MeshResolution.h"

#include "mesh/MeshSmooth.h"

#include "optimization/matchtemplate/Energy.h"
#include "optimization/matchtemplate/EnergyMinimizer.h"
#include "optimization/matchtemplate/MinimizerSettings.h"

int main(int argc, char* argv[]) {

  Settings settings(argc, argv);

  // read input data
  Mesh source = MeshIO::read(settings.source);
  Mesh target = MeshIO::read(settings.target);

  if( settings.performRigidAlignment == true) {

    source = RigidAlignment(source, target, settings).perform();

  }

  // deal with target meshes that do not provide normals
  if( settings.fixedNeighbors == false && target.has_normals() == false ) {

    // try to estimate normals if the mesh has faces
    if( target.has_faces() == true ) {
      NormalEstimation estimation(target);
      target.set_vertex_normals(estimation.compute());
    } // end if
    else {
      // use point-to-point distance measure
      settings.energySettings.searchStrategy =
        matchTemplate::EnergySettings::SearchStrategy::BASIC;
    } // end else

  } // end if

  MeshResolution resolution(source);

  arma::vec min, max;

  source.get_bounding_box(min, max);

  const double scaleFactor = 1. / arma::norm( max - min );

  settings.energySettings.maxDistance  *= scaleFactor;
  settings.energySettings.searchRadius *= scaleFactor;

  MeshNeighbors neighbors;

  if( settings.meshNeighborhoodPresent == true ) {
    neighbors = MeshNeighborsIO::read(settings.meshNeighborhood);
  }
  else {
    MeshOneRingNeighborsBuilder builder(source);
    neighbors = neighbors + builder.get_neighbors();

    if( settings.addGeodesic == true ) {

      MeshGeodesicNeighborsBuilder builder(
        source, resolution.get_resolution() * settings.geodesicNeighborhoodSize);
      neighbors = neighbors + builder.get_neighbors();

    }

    if( settings.addSpherical == true ) {

      MeshSphericalNeighborsBuilder builder(
        source, resolution.get_resolution() * settings.sphericalNeighborhoodSize);
      neighbors = neighbors + builder.get_neighbors();

    }
  }

  for( arma::vec& vertex: source.get_vertices() ) {
    vertex *= scaleFactor;
  }

  for( arma::vec& vertex: target.get_vertices() ) {
    vertex *= scaleFactor;
  }

  matchTemplate::EnergyData data(source, neighbors, target);

  if(settings.landmarksPresent == true) {
    data.landmarks = LandmarkIO::read(settings.landmarks);

    for( Landmark& mark: data.landmarks ) {

      mark.targetPosition *= scaleFactor;

    }

  }

  settings.energySettings.weights["dataTerm"] = 1;
  settings.energySettings.weights["smoothnessTerm"] = settings.smoothnessTermWeight;
  settings.energySettings.weights["postSmoothnessTerm"] = settings.postSmoothnessTermWeight;
  settings.energySettings.changeFactors["smoothnessTerm"] = settings.smoothnessTermChange;
  settings.energySettings.weights["landmarkTerm"] = settings.landmarkTermWeight;
  settings.energySettings.changeFactors["landmarkTerm"] = settings.landmarkTermChange;

  matchTemplate::Energy energy(data, settings.energySettings);

  matchTemplate::EnergyMinimizer minimizer(energy, settings.minimizerSettings);

  minimizer.minimize();

  for( arma::vec& vertex: energy.derived_data().source.get_vertices() ) {
    vertex /= scaleFactor;
  }

  Mesh result = energy.derived_data().source;

  // remove normals
  result.get_vertex_normals().clear();

  MeshSmooth(result).apply(settings.meshSmoothIterations);

  MeshIO::write(result, settings.output);

  return 0;

}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
    Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
    Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
    Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
    Copyright (C) 2011-2013 Harald Sitter <sitter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "backend.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QLatin1Literal>
#include <QtCore/QtPlugin>
#include <QtCore/QVariant>
#include <QMessageBox>

#include <phonon/GlobalDescriptionContainer>
#include <phonon/pulsesupport.h>

#include <vlc/libvlc_version.h>

#include "audio/audiooutput.h"
#include "audio/audiodataoutput.h"
#include "audio/volumefadereffect.h"
#include "devicemanager.h"
#include "effect.h"
#include "effectmanager.h"
#include "mediaobject.h"
#include "sinknode.h"
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "utils/mime.h"
#ifdef PHONON_EXPERIMENTAL
#include "video/videodataoutput.h"
#endif
#ifndef PHONON_NO_GRAPHICSVIEW
#include "video/videographicsobject.h"
#endif
#include "video/videowidget.h"

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
Q_EXPORT_PLUGIN2(phonon_vlc, Phonon::VLC::Backend)
#endif

namespace Phonon
{
namespace VLC
{

Backend *Backend::self;

Backend::Backend(QObject *parent, const QVariantList &)
    : QObject(parent)
    , m_deviceManager(0)
    , m_effectManager(0)
{
    self = this;

    // Backend information properties
    setProperty("identifier",     QLatin1String("phonon_vlc"));
    setProperty("backendName",    QLatin1String("VLC"));
    setProperty("backendComment", QLatin1String("VLC backend for Phonon"));
    setProperty("backendVersion", QLatin1String(PHONON_VLC_VERSION));
    setProperty("backendIcon",    QLatin1String("vlc"));
    setProperty("backendWebsite", QLatin1String("https://projects.kde.org/projects/kdesupport/phonon/phonon-vlc"));

    // Check if we should enable debug output
    int debugLevel = qgetenv("PHONON_BACKEND_DEBUG").toInt();
    if (debugLevel > 3) // 3 is maximum
        debugLevel = 3;
    Debug::setMinimumDebugLevel((Debug::DebugLevel)((int) Debug::DEBUG_NONE - 1 - debugLevel));

    debug() << "Constructing Phonon-VLC Version" << PHONON_VLC_VERSION;

    // Actual libVLC initialisation
    if (LibVLC::init()) {
        debug() << "Using VLC version" << libvlc_get_version();
        if (!qApp->applicationName().isEmpty()) {
            QString userAgent =
                    QString("%0/%1 (Phonon/%2; Phonon-VLC/%3)").arg(
                        qApp->applicationName(),
                        qApp->applicationVersion(),
                        PHONON_VERSION_STR,
                        PHONON_VLC_VERSION);
            libvlc_set_user_agent(libvlc,
                                  qApp->applicationName().toUtf8().constData(),
                                  userAgent.toUtf8().constData());
        } else {
            qWarning("WARNING: Setting the user agent for streaming and"
                     " PulseAudio requires you to set QCoreApplication::applicationName()");
        }
#ifdef __GNUC__
#warning application name ought to be configurable by the consumer ... new api
#endif
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 1, 0, 0))
        PulseSupport::getInstance()->enable(true);
        const bool pulseActive = PulseSupport::getInstance()->isActive();
        PulseSupport::getInstance()->enable(false);
        if (!qApp->applicationName().isEmpty()) {
            const QString id = QString("org.kde.phonon.%1").arg(qApp->applicationName());
            const QString version = qApp->applicationVersion();
            const QString icon = qApp->applicationName();
            libvlc_set_app_id(libvlc,
                              id.toUtf8().constData(),
                              version.toUtf8().constData(),
                              icon.toUtf8().constData());
        } else if (pulseActive) {
            qWarning("WARNING: Setting PulseAudio context information requires you"
                     " to set QCoreApplication::applicationName() and"
                     " QCoreApplication::applicationVersion()");
        }
#endif
    } else {
#ifdef __GNUC__
    #warning TODO - this error message is as useful as a knife at a gun fight
#endif
        QMessageBox msg;
        msg.setIcon(QMessageBox::Critical);
        msg.setWindowTitle(tr("LibVLC Failed to Initialize"));
        msg.setText(tr("Phonon's VLC backend failed to start."
                       "\n\n"
                       "This usually means a problem with your VLC installation,"
                       " please report a bug with your distributor."));
        msg.setDetailedText(LibVLC::errorMessage());
        msg.exec();
        fatal() << "Phonon::VLC::vlcInit: Failed to initialize VLC";
    }

    // Initialise PulseAudio support
    PulseSupport *pulse = PulseSupport::getInstance();
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
    // VLC 2.2 changed the stream creation order around internally which breaks
    // the Pulseaudio hijacking. Since VLC upstream doesn't feel like giving us
    // any more property control we now consider this feature unsupported. As
    // such whatever properties VLC sets will be what pulse knows about us.
    pulse->enable(true);
    connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));
#else
    pulse->enable(false);
#endif

    m_deviceManager = new DeviceManager(this);
    m_effectManager = new EffectManager(this);
}

Backend::~Backend()
{
    if (LibVLC::self)
        delete LibVLC::self;
    if (GlobalAudioChannels::self)
        delete GlobalAudioChannels::self;
    if (GlobalSubtitles::self)
        delete GlobalSubtitles::self;
    PulseSupport::shutdown();
}

QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
    if (!LibVLC::self || !libvlc)
        return 0;

    switch (c) {
    case MediaObjectClass:
        return new MediaObject(parent);
    case AudioOutputClass:
        return new AudioOutput(parent);
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 0, 0, 0))
    // Broken >= 2.0
    // https://trac.videolan.org/vlc/ticket/6992
    case AudioDataOutputClass:
        return new AudioDataOutput(parent);
#endif
#ifdef PHONON_EXPERIMENTAL
    case VideoDataOutputClass:
        return new VideoDataOutput(parent);
#endif
#ifndef PHONON_NO_GRAPHICSVIEW
    case VideoGraphicsObjectClass:
        return new VideoGraphicsObject(parent);
#endif
    case EffectClass:
        return effectManager()->createEffect(args[0].toInt(), parent);
    case VideoWidgetClass:
        return new VideoWidget(qobject_cast<QWidget *>(parent));
//    case VolumeFaderEffectClass:
#ifdef __GNUC__
#warning VFE crashes and has volume bugs ... deactivated
//        return new VolumeFaderEffect(parent);
#endif
    }

    warning() << "Backend class" << c << "is not supported by Phonon VLC :(";
    return 0;
}

QStringList Backend::availableMimeTypes() const
{
    if (m_supportedMimeTypes.isEmpty())
        const_cast<Backend *>(this)->m_supportedMimeTypes = mimeTypeList();
    return m_supportedMimeTypes;
}

QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
    QList<int> list;

    switch (type) {
    case Phonon::AudioChannelType: {
        list << GlobalAudioChannels::instance()->globalIndexes();
    }
    break;
    case Phonon::AudioOutputDeviceType:
    case Phonon::AudioCaptureDeviceType:
    case Phonon::VideoCaptureDeviceType: {
        return deviceManager()->deviceIds(type);
    }
    break;
    case Phonon::EffectType: {
        QList<EffectInfo> effectList = effectManager()->effects();
        for (int eff = 0; eff < effectList.size(); ++eff) {
            list.append(eff);
        }
    }
    break;
    case Phonon::SubtitleType: {
        list << GlobalSubtitles::instance()->globalIndexes();
    }
    break;
    }

    return list;
}

QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{
    QHash<QByteArray, QVariant> ret;

    switch (type) {
    case Phonon::AudioChannelType: {
        const AudioChannelDescription description = GlobalAudioChannels::instance()->fromIndex(index);
        ret.insert("name", description.name());
        ret.insert("description", description.description());
    }
    break;
    case Phonon::AudioOutputDeviceType:
    case Phonon::AudioCaptureDeviceType:
    case Phonon::VideoCaptureDeviceType: {
        // Index should be unique, even for different categories
        return deviceManager()->deviceProperties(index);
    }
    break;
    case Phonon::EffectType: {
        const QList<EffectInfo> effectList = effectManager()->effects();
        if (index >= 0 && index <= effectList.size()) {
            const EffectInfo &effect = effectList.at(index);
            ret.insert("name", effect.name());
            ret.insert("description", effect.description());
            ret.insert("author", effect.author());
        } else {
            Q_ASSERT(1); // Since we use list position as ID, this should not happen
        }
    }
    break;
    case Phonon::SubtitleType: {
        const SubtitleDescription description = GlobalSubtitles::instance()->fromIndex(index);
        ret.insert("name", description.name());
        ret.insert("description", description.description());
        ret.insert("type", description.property("type"));
    }
    break;
    }

    return ret;
}

bool Backend::startConnectionChange(QSet<QObject *> objects)
{
    //FIXME
    foreach(QObject * object, objects) {
        debug() << "Object:" << object->metaObject()->className();
    }

    // There is nothing we can do but hope the connection changes will not take too long
    // so that buffers would underrun
    // But we should be pretty safe the way xine works by not doing anything here.
    return true;
}

bool Backend::connectNodes(QObject *source, QObject *sink)
{
    debug() << "Backend connected" << source->metaObject()->className() << "to" << sink->metaObject()->className();

    SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
    if (sinkNode) {
        MediaObject *mediaObject = qobject_cast<MediaObject *>(source);
        if (mediaObject) {
            // Connect the SinkNode to a MediaObject
            sinkNode->connectToMediaObject(mediaObject);
            return true;
        }

        VolumeFaderEffect *effect = qobject_cast<VolumeFaderEffect *>(source);
        if (effect) {
            sinkNode->connectToMediaObject(effect->mediaObject());
            return true;
        }
    }

    warning() << "Linking" << source->metaObject()->className() << "to" << sink->metaObject()->className() << "failed";

    return false;
}

bool Backend::disconnectNodes(QObject *source, QObject *sink)
{
    SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
    if (sinkNode) {
        MediaObject *const mediaObject = qobject_cast<MediaObject *>(source);
        if (mediaObject) {
            // Disconnect the SinkNode from a MediaObject
            sinkNode->disconnectFromMediaObject(mediaObject);
            return true;
        }

        VolumeFaderEffect *const effect = qobject_cast<VolumeFaderEffect *>(source);
        if (effect) {
            sinkNode->disconnectFromMediaObject(effect->mediaObject());
            return true;
        }
    }

    return false;
}

bool Backend::endConnectionChange(QSet<QObject *> objects)
{
    foreach(QObject *object, objects) {
        debug() << "Object:" << object->metaObject()->className();
    }
    return true;
}

DeviceManager *Backend::deviceManager() const
{
    return m_deviceManager;
}

EffectManager *Backend::effectManager() const
{
    return m_effectManager;
}

} // namespace VLC
} // namespace Phonon
<commit_msg>revise set_app_id icon logic [fancy code copy from phonon::pulsesupport]<commit_after>/*
    Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
    Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
    Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
    Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
    Copyright (C) 2011-2013 Harald Sitter <sitter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "backend.h"

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QApplication>
#else
#include <QGuiApplication>
#endif
#include <QIcon>
#include <QLatin1Literal>
#include <QMessageBox>
#include <QtPlugin>
#include <QVariant>

#include <phonon/GlobalDescriptionContainer>
#include <phonon/pulsesupport.h>

#include <vlc/libvlc_version.h>

#include "audio/audiooutput.h"
#include "audio/audiodataoutput.h"
#include "audio/volumefadereffect.h"
#include "devicemanager.h"
#include "effect.h"
#include "effectmanager.h"
#include "mediaobject.h"
#include "sinknode.h"
#include "utils/debug.h"
#include "utils/libvlc.h"
#include "utils/mime.h"
#ifdef PHONON_EXPERIMENTAL
#include "video/videodataoutput.h"
#endif
#ifndef PHONON_NO_GRAPHICSVIEW
#include "video/videographicsobject.h"
#endif
#include "video/videowidget.h"

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
Q_EXPORT_PLUGIN2(phonon_vlc, Phonon::VLC::Backend)
#endif

namespace Phonon
{
namespace VLC
{

Backend *Backend::self;

Backend::Backend(QObject *parent, const QVariantList &)
    : QObject(parent)
    , m_deviceManager(0)
    , m_effectManager(0)
{
    self = this;

    // Backend information properties
    setProperty("identifier",     QLatin1String("phonon_vlc"));
    setProperty("backendName",    QLatin1String("VLC"));
    setProperty("backendComment", QLatin1String("VLC backend for Phonon"));
    setProperty("backendVersion", QLatin1String(PHONON_VLC_VERSION));
    setProperty("backendIcon",    QLatin1String("vlc"));
    setProperty("backendWebsite", QLatin1String("https://projects.kde.org/projects/kdesupport/phonon/phonon-vlc"));

    // Check if we should enable debug output
    int debugLevel = qgetenv("PHONON_BACKEND_DEBUG").toInt();
    if (debugLevel > 3) // 3 is maximum
        debugLevel = 3;
    Debug::setMinimumDebugLevel((Debug::DebugLevel)((int) Debug::DEBUG_NONE - 1 - debugLevel));

    debug() << "Constructing Phonon-VLC Version" << PHONON_VLC_VERSION;

    // Actual libVLC initialisation
    if (LibVLC::init()) {
        debug() << "Using VLC version" << libvlc_get_version();
        if (!qApp->applicationName().isEmpty()) {
            QString userAgent =
                    QString("%0/%1 (Phonon/%2; Phonon-VLC/%3)").arg(
                        qApp->applicationName(),
                        qApp->applicationVersion(),
                        PHONON_VERSION_STR,
                        PHONON_VLC_VERSION);
            libvlc_set_user_agent(libvlc,
                                  qApp->applicationName().toUtf8().constData(),
                                  userAgent.toUtf8().constData());
        } else {
            qWarning("WARNING: Setting the user agent for streaming and"
                     " PulseAudio requires you to set QCoreApplication::applicationName()");
        }
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 1, 0, 0))
        PulseSupport::getInstance()->enable(true);
        const bool pulseActive = PulseSupport::getInstance()->isActive();
        PulseSupport::getInstance()->enable(false);
        if (!qApp->applicationName().isEmpty()) {
            const QString id = QString("org.kde.phonon.%1").arg(qApp->applicationName());
            const QString version = qApp->applicationVersion();
            QString icon;
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
            if (!qApp->windowIcon().isNull()){
                // Try to get the fromTheme() name of the QIcon.
                icon = qApp->windowIcon().name();
            }
#endif
            if (icon.isEmpty()) {
                // If we failed to get a proper icon name, use the appname instead.
                icon = qApp->applicationName().toLower();
            }
            libvlc_set_app_id(libvlc,
                              id.toUtf8().constData(),
                              version.toUtf8().constData(),
                              icon.toUtf8().constData());
        } else if (pulseActive) {
            qWarning("WARNING: Setting PulseAudio context information requires you"
                     " to set QCoreApplication::applicationName(),"
                     " QCoreApplication::applicationVersion() and"
                     " QGuiApplication::windowIcon().");
        }

#endif
    } else {
#ifdef __GNUC__
    #warning TODO - this error message is as useful as a knife at a gun fight
#endif
        QMessageBox msg;
        msg.setIcon(QMessageBox::Critical);
        msg.setWindowTitle(tr("LibVLC Failed to Initialize"));
        msg.setText(tr("Phonon's VLC backend failed to start."
                       "\n\n"
                       "This usually means a problem with your VLC installation,"
                       " please report a bug with your distributor."));
        msg.setDetailedText(LibVLC::errorMessage());
        msg.exec();
        fatal() << "Phonon::VLC::vlcInit: Failed to initialize VLC";
    }

    // Initialise PulseAudio support
    PulseSupport *pulse = PulseSupport::getInstance();
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 0, 0))
    // VLC 2.2 changed the stream creation order around internally which breaks
    // the Pulseaudio hijacking. Since VLC upstream doesn't feel like giving us
    // any more property control we now consider this feature unsupported. As
    // such whatever properties VLC sets will be what pulse knows about us.
    pulse->enable(true);
    connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));
#else
    pulse->enable(false);
#endif

    m_deviceManager = new DeviceManager(this);
    m_effectManager = new EffectManager(this);
}

Backend::~Backend()
{
    if (LibVLC::self)
        delete LibVLC::self;
    if (GlobalAudioChannels::self)
        delete GlobalAudioChannels::self;
    if (GlobalSubtitles::self)
        delete GlobalSubtitles::self;
    PulseSupport::shutdown();
}

QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
    if (!LibVLC::self || !libvlc)
        return 0;

    switch (c) {
    case MediaObjectClass:
        return new MediaObject(parent);
    case AudioOutputClass:
        return new AudioOutput(parent);
#if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 0, 0, 0))
    // Broken >= 2.0
    // https://trac.videolan.org/vlc/ticket/6992
    case AudioDataOutputClass:
        return new AudioDataOutput(parent);
#endif
#ifdef PHONON_EXPERIMENTAL
    case VideoDataOutputClass:
        return new VideoDataOutput(parent);
#endif
#ifndef PHONON_NO_GRAPHICSVIEW
    case VideoGraphicsObjectClass:
        return new VideoGraphicsObject(parent);
#endif
    case EffectClass:
        return effectManager()->createEffect(args[0].toInt(), parent);
    case VideoWidgetClass:
        return new VideoWidget(qobject_cast<QWidget *>(parent));
//    case VolumeFaderEffectClass:
#ifdef __GNUC__
#warning VFE crashes and has volume bugs ... deactivated
//        return new VolumeFaderEffect(parent);
#endif
    }

    warning() << "Backend class" << c << "is not supported by Phonon VLC :(";
    return 0;
}

QStringList Backend::availableMimeTypes() const
{
    if (m_supportedMimeTypes.isEmpty())
        const_cast<Backend *>(this)->m_supportedMimeTypes = mimeTypeList();
    return m_supportedMimeTypes;
}

QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
    QList<int> list;

    switch (type) {
    case Phonon::AudioChannelType: {
        list << GlobalAudioChannels::instance()->globalIndexes();
    }
    break;
    case Phonon::AudioOutputDeviceType:
    case Phonon::AudioCaptureDeviceType:
    case Phonon::VideoCaptureDeviceType: {
        return deviceManager()->deviceIds(type);
    }
    break;
    case Phonon::EffectType: {
        QList<EffectInfo> effectList = effectManager()->effects();
        for (int eff = 0; eff < effectList.size(); ++eff) {
            list.append(eff);
        }
    }
    break;
    case Phonon::SubtitleType: {
        list << GlobalSubtitles::instance()->globalIndexes();
    }
    break;
    }

    return list;
}

QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{
    QHash<QByteArray, QVariant> ret;

    switch (type) {
    case Phonon::AudioChannelType: {
        const AudioChannelDescription description = GlobalAudioChannels::instance()->fromIndex(index);
        ret.insert("name", description.name());
        ret.insert("description", description.description());
    }
    break;
    case Phonon::AudioOutputDeviceType:
    case Phonon::AudioCaptureDeviceType:
    case Phonon::VideoCaptureDeviceType: {
        // Index should be unique, even for different categories
        return deviceManager()->deviceProperties(index);
    }
    break;
    case Phonon::EffectType: {
        const QList<EffectInfo> effectList = effectManager()->effects();
        if (index >= 0 && index <= effectList.size()) {
            const EffectInfo &effect = effectList.at(index);
            ret.insert("name", effect.name());
            ret.insert("description", effect.description());
            ret.insert("author", effect.author());
        } else {
            Q_ASSERT(1); // Since we use list position as ID, this should not happen
        }
    }
    break;
    case Phonon::SubtitleType: {
        const SubtitleDescription description = GlobalSubtitles::instance()->fromIndex(index);
        ret.insert("name", description.name());
        ret.insert("description", description.description());
        ret.insert("type", description.property("type"));
    }
    break;
    }

    return ret;
}

bool Backend::startConnectionChange(QSet<QObject *> objects)
{
    //FIXME
    foreach(QObject * object, objects) {
        debug() << "Object:" << object->metaObject()->className();
    }

    // There is nothing we can do but hope the connection changes will not take too long
    // so that buffers would underrun
    // But we should be pretty safe the way xine works by not doing anything here.
    return true;
}

bool Backend::connectNodes(QObject *source, QObject *sink)
{
    debug() << "Backend connected" << source->metaObject()->className() << "to" << sink->metaObject()->className();

    SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
    if (sinkNode) {
        MediaObject *mediaObject = qobject_cast<MediaObject *>(source);
        if (mediaObject) {
            // Connect the SinkNode to a MediaObject
            sinkNode->connectToMediaObject(mediaObject);
            return true;
        }

        VolumeFaderEffect *effect = qobject_cast<VolumeFaderEffect *>(source);
        if (effect) {
            sinkNode->connectToMediaObject(effect->mediaObject());
            return true;
        }
    }

    warning() << "Linking" << source->metaObject()->className() << "to" << sink->metaObject()->className() << "failed";

    return false;
}

bool Backend::disconnectNodes(QObject *source, QObject *sink)
{
    SinkNode *sinkNode = dynamic_cast<SinkNode *>(sink);
    if (sinkNode) {
        MediaObject *const mediaObject = qobject_cast<MediaObject *>(source);
        if (mediaObject) {
            // Disconnect the SinkNode from a MediaObject
            sinkNode->disconnectFromMediaObject(mediaObject);
            return true;
        }

        VolumeFaderEffect *const effect = qobject_cast<VolumeFaderEffect *>(source);
        if (effect) {
            sinkNode->disconnectFromMediaObject(effect->mediaObject());
            return true;
        }
    }

    return false;
}

bool Backend::endConnectionChange(QSet<QObject *> objects)
{
    foreach(QObject *object, objects) {
        debug() << "Object:" << object->metaObject()->className();
    }
    return true;
}

DeviceManager *Backend::deviceManager() const
{
    return m_deviceManager;
}

EffectManager *Backend::effectManager() const
{
    return m_effectManager;
}

} // namespace VLC
} // namespace Phonon
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>added Miro to the identifiable clients<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MR", "Miro"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Cloudius Systems
 */

#include "reactor.hh"
#include "sstring.hh"
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
#include <bitset>
#include <limits>
#include <cctype>

class char_filter {
    using uchar = unsigned char;
public:
    template <typename Pred>
    explicit char_filter(Pred pred) {
        for (unsigned i = 0; i <= std::numeric_limits<uchar>::max(); ++i) {
            _filter.set(i, pred(i));
        }
    }
    bool operator()(char v) const { return _filter.test(uchar(v)); }
private:
    std::bitset<1 << std::numeric_limits<uchar>::digits> _filter;
};

char_filter tchar([](char c) {
    return std::isalnum(c) || std::string("-!#$%&'\\*\\+.^_`|~").find_first_of(c) != std::string::npos;
});
char_filter op_char([](char c) { return std::isupper(c); });
char_filter sp_char([](char c) { return std::isspace(c); });
char_filter nsp_char([](char c) { return !std::isspace(c); });
char_filter digit_char([](char c) { return std::isdigit(c); });

class http_server {
    std::vector<pollable_fd> _listeners;
public:
    void listen(ipv4_addr addr) {
        listen_options lo;
        lo.reuse_address = true;
        _listeners.push_back(the_reactor.listen(make_ipv4_address(addr), lo));
        do_accepts(_listeners.size() - 1);
    }
    void do_accepts(int which) {
        _listeners[which].accept().then([this, which] (pollable_fd fd, socket_address addr) mutable {
            (new connection(*this, std::move(fd), addr))->read();
            do_accepts(which);
        });
    }
    class connection {
        http_server& _server;
        pollable_fd _fd;
        socket_address _addr;
        input_stream_buffer<char> _read_buf;
        output_stream_buffer<char> _write_buf;
        bool _eof = false;
        static constexpr size_t limit = 4096;
        using tmp_buf = temporary_buffer<char>;
        struct request {
            sstring _method;
            sstring _url;
            sstring _version;
            std::unordered_map<sstring, sstring> _headers;
        };
        sstring _last_header_name;
        struct response {
            sstring _response_line;
            sstring _body;
            std::unordered_map<sstring, sstring> _headers;
        };
        std::unique_ptr<request> _req;
        std::unique_ptr<response> _resp;
        std::queue<std::unique_ptr<response>> _pending_responses;
    public:
        connection(http_server& server, pollable_fd&& fd, socket_address addr)
            : _server(server), _fd(std::move(fd)), _addr(addr), _read_buf(_fd, 8192)
            , _write_buf(_fd, 8192) {}
        void read() {
            _read_buf.read_until(limit, '\n').then([this] (tmp_buf start_line) {
                if (!start_line.size()) {
                    _eof = true;
                    maybe_done();
                    return;
                }
                _req = std::make_unique<request>();
                size_t pos = 0;
                size_t end = start_line.size();
                while (pos < end && op_char(start_line[pos])) {
                    ++pos;
                }
                if (pos == 0) {
                    return bad(std::move(_req));
                }
                _req->_method = sstring(start_line.begin(), pos);
                if (pos == end || start_line[pos++] != ' ') {
                    return bad(std::move(_req));
                }
                auto url = pos;
                while (pos < end && nsp_char(start_line[pos])) {
                    ++pos;
                }
                _req->_url = sstring(start_line.begin() + url, pos - url);
                if (pos == end || start_line[pos++] != ' ') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'H') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'T') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'T') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'P') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '/') {
                    return bad(std::move(_req));
                }
                auto ver = pos;
                if (pos == end || !digit_char(start_line[pos++])) {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '.') {
                    return bad(std::move(_req));
                }
                if (pos == end || !digit_char(start_line[pos++])) {
                    return bad(std::move(_req));
                }
                _req->_version = sstring(start_line.begin() + ver, pos - ver);
                if (pos == end || start_line[pos++] != '\r') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '\n') {
                    return bad(std::move(_req));
                }
                if (pos != end) {
                    return bad(std::move(_req));
                }
                if (_req->_method != "GET") {
                    return bad(std::move(_req));
                }
                _read_buf.read_until(limit, '\n').then([this] (tmp_buf header) {
                    parse_header(std::move(header));
                });
            });
        }
        void parse_header(tmp_buf header) {
            if (header.size() == 2 && header[0] == '\r' && header[1] == '\n') {
                generate_response(std::move(_req));
                read();
                return;
            }
            size_t pos = 0;
            size_t end = header.size();
            if (end < 2 || header[end-2] != '\r' || header[end-1] != '\n') {
                return bad(std::move(_req));
            }
            while (tchar(header[pos])) {
                ++pos;
            }
            if (pos) {
                sstring name = sstring(header.begin(), pos);
                while (pos != end && sp_char(header[pos])) {
                    ++pos;
                }
                if (pos == end || header[pos++] != ':') {
                    return bad(std::move(_req));
                }
                while (pos != end && sp_char(header[pos])) {
                    ++pos;
                }
                while (pos != end && sp_char(header[end-1])) {
                    --end;
                }
                sstring value = sstring(header.begin() + pos, end - pos);
                _req->_headers[name] = std::move(value);
                _last_header_name = std::move(name);
            } else {
                while (sp_char(header[pos])) {
                    ++pos;
                }
                while (pos != end && sp_char(header[end-1])) {
                    --end;
                }
                if (!pos || end == pos) {
                    return bad(std::move(_req));
                }
                _req->_headers[_last_header_name] += " ";
                _req->_headers[_last_header_name] += sstring(header.begin() + pos, end - pos);
            }
            _read_buf.read_until(limit, '\n').then([this] (tmp_buf header) {
                parse_header(std::move(header));
            });
        }
        void bad(std::unique_ptr<request> req) {
            auto resp = std::make_unique<response>();
            resp->_response_line = "HTTP/1.1 400 BAD REQUEST\r\n\r\n";
            respond(std::move(resp));
        }
        void respond(std::unique_ptr<response> resp) {
            if (!_resp) {
                _resp = std::move(resp);
                start_response();
            } else {
                _pending_responses.push(std::move(resp));
            }
        }
        void start_response() {
            _resp->_headers["Content-Length"] = to_sstring(_resp->_body.size());
            _write_buf.write(_resp->_response_line.begin(), _resp->_response_line.size()).then(
                    [this] (size_t n) mutable {
                return write_response_headers(_resp->_headers.begin());
            }).then([this] (size_t done) {
                return _write_buf.write("\r\n", 2);
            }).then([this] (size_t done) mutable {
                return write_body();
            }).then([this] (size_t done) {
                return _write_buf.flush();
            }).then([this] (bool done) {
                _resp.reset();
                if (!_pending_responses.empty()) {
                    _resp = std::move(_pending_responses.front());
                    _pending_responses.pop();
                    start_response();
                } else {
                    maybe_done();
                }
            });
        }
        future<size_t> write_response_headers(std::unordered_map<sstring, sstring>::iterator hi) {
            if (hi == _resp->_headers.end()) {
                return make_ready_future<size_t>(0);
            }
            promise<size_t> pr;
            auto fut = pr.get_future();
            _write_buf.write(hi->first.begin(), hi->first.size()).then(
                    [hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write(": ", 2);
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write(hi->second.begin(), hi->second.size());
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write("\r\n", 2);
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return write_response_headers(++hi);
            }).then([this, pr = std::move(pr)] (size_t done) mutable {
                pr.set_value(done);
            });
            return fut;
        }
        void generate_response(std::unique_ptr<request> req) {
            auto resp = std::make_unique<response>();
            resp->_response_line = "HTTP/1.1 200 OK\r\n";
            resp->_headers["Content-Type"] = "text/html";
            resp->_body = "<title>this is the future</title>
Future!!
";
            respond(std::move(resp));
        }
        future<size_t> write_body() {
            return _write_buf.write(_resp->_body.begin(), _resp->_body.size());
        }
        void maybe_done() {
            if (_eof && !_req && !_resp && _pending_responses.empty()) {
                delete this;
            }
        }
    };
};

int main(int ac, char** av) {
    http_server server;
    server.listen({{}, 10000});
    the_reactor.run();
    return 0;
}

<commit_msg>httpd: handle errors<commit_after>/*
 * Copyright 2014 Cloudius Systems
 */

#include "reactor.hh"
#include "sstring.hh"
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
#include <bitset>
#include <limits>
#include <cctype>

class char_filter {
    using uchar = unsigned char;
public:
    template <typename Pred>
    explicit char_filter(Pred pred) {
        for (unsigned i = 0; i <= std::numeric_limits<uchar>::max(); ++i) {
            _filter.set(i, pred(i));
        }
    }
    bool operator()(char v) const { return _filter.test(uchar(v)); }
private:
    std::bitset<1 << std::numeric_limits<uchar>::digits> _filter;
};

char_filter tchar([](char c) {
    return std::isalnum(c) || std::string("-!#$%&'\\*\\+.^_`|~").find_first_of(c) != std::string::npos;
});
char_filter op_char([](char c) { return std::isupper(c); });
char_filter sp_char([](char c) { return std::isspace(c); });
char_filter nsp_char([](char c) { return !std::isspace(c); });
char_filter digit_char([](char c) { return std::isdigit(c); });

class http_server {
    std::vector<pollable_fd> _listeners;
public:
    void listen(ipv4_addr addr) {
        listen_options lo;
        lo.reuse_address = true;
        _listeners.push_back(the_reactor.listen(make_ipv4_address(addr), lo));
        do_accepts(_listeners.size() - 1);
    }
    void do_accepts(int which) {
        _listeners[which].accept().then([this, which] (pollable_fd fd, socket_address addr) mutable {
            (new connection(*this, std::move(fd), addr))->read().rescue([this] (auto get_ex) {
                try {
                    get_ex();
                } catch (std::exception& ex) {
                    std::cout << "request error " << ex.what() << "\n";
                }
            });
            do_accepts(which);
        }).rescue([] (auto get_ex) {
            try {
                get_ex();
            } catch (std::exception& ex) {
                std::cout << "accept failed: " << ex.what() << "\n";
            }
        });
    }
    class connection {
        http_server& _server;
        pollable_fd _fd;
        socket_address _addr;
        input_stream_buffer<char> _read_buf;
        output_stream_buffer<char> _write_buf;
        bool _eof = false;
        static constexpr size_t limit = 4096;
        using tmp_buf = temporary_buffer<char>;
        struct request {
            sstring _method;
            sstring _url;
            sstring _version;
            std::unordered_map<sstring, sstring> _headers;
        };
        sstring _last_header_name;
        struct response {
            sstring _response_line;
            sstring _body;
            std::unordered_map<sstring, sstring> _headers;
        };
        std::unique_ptr<request> _req;
        std::unique_ptr<response> _resp;
        std::queue<std::unique_ptr<response>> _pending_responses;
    public:
        connection(http_server& server, pollable_fd&& fd, socket_address addr)
            : _server(server), _fd(std::move(fd)), _addr(addr), _read_buf(_fd, 8192)
            , _write_buf(_fd, 8192) {}
        future<> read() {
            return _read_buf.read_until(limit, '\n').then([this] (tmp_buf start_line) {
                if (!start_line.size()) {
                    _eof = true;
                    maybe_done();
                    return make_ready_future<>();
                }
                _req = std::make_unique<request>();
                size_t pos = 0;
                size_t end = start_line.size();
                while (pos < end && op_char(start_line[pos])) {
                    ++pos;
                }
                if (pos == 0) {
                    return bad(std::move(_req));
                }
                _req->_method = sstring(start_line.begin(), pos);
                if (pos == end || start_line[pos++] != ' ') {
                    return bad(std::move(_req));
                }
                auto url = pos;
                while (pos < end && nsp_char(start_line[pos])) {
                    ++pos;
                }
                _req->_url = sstring(start_line.begin() + url, pos - url);
                if (pos == end || start_line[pos++] != ' ') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'H') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'T') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'T') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != 'P') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '/') {
                    return bad(std::move(_req));
                }
                auto ver = pos;
                if (pos == end || !digit_char(start_line[pos++])) {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '.') {
                    return bad(std::move(_req));
                }
                if (pos == end || !digit_char(start_line[pos++])) {
                    return bad(std::move(_req));
                }
                _req->_version = sstring(start_line.begin() + ver, pos - ver);
                if (pos == end || start_line[pos++] != '\r') {
                    return bad(std::move(_req));
                }
                if (pos == end || start_line[pos++] != '\n') {
                    return bad(std::move(_req));
                }
                if (pos != end) {
                    return bad(std::move(_req));
                }
                if (_req->_method != "GET") {
                    return bad(std::move(_req));
                }
                return _read_buf.read_until(limit, '\n').then([this] (tmp_buf header) {
                    return parse_header(std::move(header));
                });
            });
        }
        future<> parse_header(tmp_buf header) {
            if (header.size() == 2 && header[0] == '\r' && header[1] == '\n') {
                generate_response(std::move(_req));
                read().rescue([zis = this] (auto get_ex) mutable {
                    try {
                        get_ex();
                    } catch (std::exception& ex) {
                        std::cout << "read failed with " << ex.what() << "\n";
                        zis->maybe_done();
                    }
                });
                return make_ready_future<>();
            }
            size_t pos = 0;
            size_t end = header.size();
            if (end < 2 || header[end-2] != '\r' || header[end-1] != '\n') {
                return bad(std::move(_req));
            }
            while (tchar(header[pos])) {
                ++pos;
            }
            if (pos) {
                sstring name = sstring(header.begin(), pos);
                while (pos != end && sp_char(header[pos])) {
                    ++pos;
                }
                if (pos == end || header[pos++] != ':') {
                    return bad(std::move(_req));
                }
                while (pos != end && sp_char(header[pos])) {
                    ++pos;
                }
                while (pos != end && sp_char(header[end-1])) {
                    --end;
                }
                sstring value = sstring(header.begin() + pos, end - pos);
                _req->_headers[name] = std::move(value);
                _last_header_name = std::move(name);
            } else {
                while (sp_char(header[pos])) {
                    ++pos;
                }
                while (pos != end && sp_char(header[end-1])) {
                    --end;
                }
                if (!pos || end == pos) {
                    return bad(std::move(_req));
                }
                _req->_headers[_last_header_name] += " ";
                _req->_headers[_last_header_name] += sstring(header.begin() + pos, end - pos);
            }
            return _read_buf.read_until(limit, '\n').then([this] (tmp_buf header) {
                return parse_header(std::move(header));
            });
        }
        future<> bad(std::unique_ptr<request> req) {
            auto resp = std::make_unique<response>();
            resp->_response_line = "HTTP/1.1 400 BAD REQUEST\r\n\r\n";
            respond(std::move(resp));
            _eof = true;
            throw std::runtime_error("failed to parse request");
        }
        void respond(std::unique_ptr<response> resp) {
            if (!_resp) {
                _resp = std::move(resp);
                start_response();
            } else {
                _pending_responses.push(std::move(resp));
            }
        }
        void start_response() {
            _resp->_headers["Content-Length"] = to_sstring(_resp->_body.size());
            _write_buf.write(_resp->_response_line.begin(), _resp->_response_line.size()).then(
                    [this] (size_t n) mutable {
                return write_response_headers(_resp->_headers.begin());
            }).then([this] (size_t done) {
                return _write_buf.write("\r\n", 2);
            }).then([this] (size_t done) mutable {
                return write_body();
            }).then([this] (size_t done) {
                return _write_buf.flush();
            }).then([this] (bool done) {
                _resp.reset();
                if (!_pending_responses.empty()) {
                    _resp = std::move(_pending_responses.front());
                    _pending_responses.pop();
                    start_response();
                } else {
                    maybe_done();
                }
            });
        }
        future<size_t> write_response_headers(std::unordered_map<sstring, sstring>::iterator hi) {
            if (hi == _resp->_headers.end()) {
                return make_ready_future<size_t>(0);
            }
            promise<size_t> pr;
            auto fut = pr.get_future();
            _write_buf.write(hi->first.begin(), hi->first.size()).then(
                    [hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write(": ", 2);
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write(hi->second.begin(), hi->second.size());
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return _write_buf.write("\r\n", 2);
            }).then([hi, this, pr = std::move(pr)] (size_t done) mutable {
                return write_response_headers(++hi);
            }).then([this, pr = std::move(pr)] (size_t done) mutable {
                pr.set_value(done);
            });
            return fut;
        }
        void generate_response(std::unique_ptr<request> req) {
            auto resp = std::make_unique<response>();
            resp->_response_line = "HTTP/1.1 200 OK\r\n";
            resp->_headers["Content-Type"] = "text/html";
            resp->_body = "<title>this is the future</title>
Future!!
";
            respond(std::move(resp));
        }
        future<size_t> write_body() {
            return _write_buf.write(_resp->_body.begin(), _resp->_body.size());
        }
        void maybe_done() {
            if (_eof && !_req && !_resp && _pending_responses.empty()) {
                delete this;
            }
        }
    };
};

int main(int ac, char** av) {
    http_server server;
    server.listen({{}, 10000});
    the_reactor.run();
    return 0;
}

<|endoftext|>