<commit_before>#include "trayToolkit.h"
#include "trayPlatformGtk2.h"

#define XATOM(atom) static const Atom atom = XInternAtom(xev->xany.display, #atom, false)

namespace mintrayr {
namespace platform {

/**
 * Helper: Gdk filter function to "watch" the window
 */
static
GdkFilterReturn filterWindows(XEvent *xev, GdkEvent* event, nsIDOMWindow* window)
{
	XATOM(WM_DELETE_WINDOW);

	if (!xev) {
		return GDK_FILTER_CONTINUE;
	}

	switch (xev->type) {
		case UnmapNotify:
			if (DoMinimizeWindow(window, kTrayOnMinimize)) {
				return GDK_FILTER_REMOVE;
			}
			break;

		case ClientMessage:
			if (xev->xclient.data.l
					&& static_cast<Atom>(xev->xclient.data.l[0]) == WM_DELETE_WINDOW
					&& DoMinimizeWindow(window, kTrayOnClose)
			) {
				return GDK_FILTER_REMOVE;
			}
			break;

		default:
			break;
	}
	return GDK_FILTER_CONTINUE;
}

void Init() {}
void Destroy() {}

Icon* CreateIcon(TrayIconImpl *aOwner, nsIDOMWindow* aWindow, const nsString& aTitle)
{
	return new gtk2::Icon(aOwner, aWindow, aTitle);
}

NS_IMETHODIMP WatchWindow(nsIDOMWindow *aWindow)
{
	nsresult rv;

	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	GdkWindow *gdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!gdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}
	gdk_window_add_filter(gdkWindow, reinterpret_cast<GdkFilterFunc>(filterWindows), aWindow);

	return NS_OK;
}
NS_IMETHODIMP UnwatchWindow(nsIDOMWindow *aWindow)
{
	nsresult rv;

	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	GdkWindow *gdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!gdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}
	gdk_window_remove_filter(gdkWindow, reinterpret_cast<GdkFilterFunc>(filterWindows), aWindow);

	return NS_OK;
}

namespace gtk2 {

Icon::Icon(TrayIconImpl *aIcon, nsIDOMWindow *aWindow, const nsString& aTitle)
	: mStatusIcon(0), mGtkWindow(0), mGdkWindow(0), mIcon(aIcon)
{
	Init(aWindow, aTitle);
}
NS_IMETHODIMP Icon::Init(nsIDOMWindow *aWindow, const nsString& aTitle)
{
	nsresult rv;
	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	// Get the window
	mGdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!mGdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}

	// Get the widget and gtk window
	GtkWidget *widget;
	gdk_window_get_user_data(mGdkWindow, reinterpret_cast<gpointer*>(&widget));
	widget = gtk_widget_get_toplevel(widget);
	mGtkWindow = reinterpret_cast<GtkWindow*>(widget);

	// Set up tray icon
	mStatusIcon = gtk_status_icon_new();

	// Get the window icon and set it
	GdkPixbuf *buf = gtk_window_get_icon(mGtkWindow);
	if (buf) {
		gtk_status_icon_set_from_pixbuf(mStatusIcon, buf);
	}

	// Get and set the title
	if (aTitle.IsEmpty()) {
		gtk_status_icon_set_tooltip_text(mStatusIcon, gtk_window_get_title(mGtkWindow));
		gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK);
		propertyEventId = g_signal_connect(mGtkWindow, "property-notify-event", G_CALLBACK(gtkPropertyEvent), this);
	}
	else {
		NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
		gtk_status_icon_set_tooltip_text(mStatusIcon, reinterpret_cast<const char*>(titleUTF8.get()));
		propertyEventId = 0;
	}

	// Add signals
	g_signal_connect(G_OBJECT(mStatusIcon), "button-press-event", G_CALLBACK(gtkButtonEvent), this);
	g_signal_connect(G_OBJECT(mStatusIcon), "button-release-event", G_CALLBACK(gtkButtonEvent), this);

	// Make visible
	gtk_status_icon_set_visible(mStatusIcon, 1);
	return NS_OK;
}

Icon::~Icon()
{
	Restore();

	if (mStatusIcon) {
		gtk_status_icon_set_visible(mStatusIcon, 0);
		g_object_unref(mStatusIcon);
	}
	if (propertyEventId) {
		g_signal_handler_disconnect(mGtkWindow, propertyEventId);
	}
}

void Icon::Restore()
{
	gdk_window_show(mGdkWindow);
}

void Icon::Minimize() {
	// Hide the window
	gdk_window_hide(mGdkWindow);
}

void Icon::buttonEvent(GdkEventButton *event)
{
	nsString eventName;
	switch (event->type) {
		case GDK_BUTTON_RELEASE: // use release, so that we don't duplicate events
			eventName = NS_LITERAL_STRING("TrayClick");
			break;
		case GDK_2BUTTON_PRESS:
			eventName = NS_LITERAL_STRING("TrayDblClick");
			break;
		case GDK_3BUTTON_PRESS:
			eventName = NS_LITERAL_STRING("TrayTriClick");
			break;
		default:
			return;
	}

	nsPoint pt((nscoord)(event->x + event->x_root), (nscoord)(event->y + event->y_root));

	// Dispatch the event
#define HASSTATE(x) (event->state & x ? PR_TRUE : PR_FALSE)
	mIcon->DispatchMouseEvent(
			eventName,
			event->button - 1,
			pt,
			HASSTATE(GDK_CONTROL_MASK),
			HASSTATE(GDK_MOD1_MASK),
			HASSTATE(GDK_SHIFT_MASK)
			);
#undef HASSTATE
}

gboolean Icon::propertyEvent()
{
	gtk_status_icon_set_tooltip_text(mStatusIcon, gtk_window_get_title(mGtkWindow));
	return FALSE;
}

} // namespace gtk2

}} // namespaces
<commit_msg>Fix: mapping of windows does not restore<commit_after>#include "trayToolkit.h"
#include "trayPlatformGtk2.h"

#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"

#define XATOM(atom) static const Atom atom = XInternAtom(xev->xany.display, #atom, false)

namespace mintrayr {
namespace platform {

/**
 * Helper: Gdk filter function to "watch" the window
 */
static
GdkFilterReturn filterWindows(XEvent *xev, GdkEvent* event, nsIDOMWindow* window)
{
	XATOM(WM_DELETE_WINDOW);

	if (!xev) {
		return GDK_FILTER_CONTINUE;
	}

	switch (xev->type) {
		case MapNotify:
			{
				nsCOMPtr<trayITrayService> traySvc(do_GetService(TRAYSERVICE_CONTRACTID));
				traySvc->Restore(window);
			}
			break;

		case UnmapNotify:
			if (DoMinimizeWindow(window, kTrayOnMinimize)) {
				return GDK_FILTER_REMOVE;
			}
			break;

		case ClientMessage:
			if (xev->xclient.data.l
					&& static_cast<Atom>(xev->xclient.data.l[0]) == WM_DELETE_WINDOW
					&& DoMinimizeWindow(window, kTrayOnClose)
			) {
				return GDK_FILTER_REMOVE;
			}
			break;

		default:
			break;
	}
	return GDK_FILTER_CONTINUE;
}

void Init() {}
void Destroy() {}

Icon* CreateIcon(TrayIconImpl *aOwner, nsIDOMWindow* aWindow, const nsString& aTitle)
{
	return new gtk2::Icon(aOwner, aWindow, aTitle);
}

NS_IMETHODIMP WatchWindow(nsIDOMWindow *aWindow)
{
	nsresult rv;

	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	GdkWindow *gdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!gdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}
	gdk_window_add_filter(gdkWindow, reinterpret_cast<GdkFilterFunc>(filterWindows), aWindow);

	return NS_OK;
}
NS_IMETHODIMP UnwatchWindow(nsIDOMWindow *aWindow)
{
	nsresult rv;

	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	GdkWindow *gdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!gdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}
	gdk_window_remove_filter(gdkWindow, reinterpret_cast<GdkFilterFunc>(filterWindows), aWindow);

	return NS_OK;
}

namespace gtk2 {

Icon::Icon(TrayIconImpl *aIcon, nsIDOMWindow *aWindow, const nsString& aTitle)
	: mStatusIcon(0), mGtkWindow(0), mGdkWindow(0), mIcon(aIcon)
{
	Init(aWindow, aTitle);
}
NS_IMETHODIMP Icon::Init(nsIDOMWindow *aWindow, const nsString& aTitle)
{
	nsresult rv;
	nsCOMPtr<nsIBaseWindow> baseWindow;
	rv = GetBaseWindow(aWindow, getter_AddRefs(baseWindow));
	NS_ENSURE_SUCCESS(rv, rv);

	nativeWindow native = 0;
	rv = baseWindow->GetParentNativeWindow(&native);
	NS_ENSURE_SUCCESS(rv, rv);

	// Get the window
	mGdkWindow = gdk_window_get_toplevel(reinterpret_cast<GdkWindow*>(native));
	if (!mGdkWindow) {
		return NS_ERROR_UNEXPECTED;
	}

	// Get the widget and gtk window
	GtkWidget *widget;
	gdk_window_get_user_data(mGdkWindow, reinterpret_cast<gpointer*>(&widget));
	widget = gtk_widget_get_toplevel(widget);
	mGtkWindow = reinterpret_cast<GtkWindow*>(widget);

	// Set up tray icon
	mStatusIcon = gtk_status_icon_new();

	// Get the window icon and set it
	GdkPixbuf *buf = gtk_window_get_icon(mGtkWindow);
	if (buf) {
		gtk_status_icon_set_from_pixbuf(mStatusIcon, buf);
	}

	// Get and set the title
	if (aTitle.IsEmpty()) {
		gtk_status_icon_set_tooltip_text(mStatusIcon, gtk_window_get_title(mGtkWindow));
		gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK);
		propertyEventId = g_signal_connect(mGtkWindow, "property-notify-event", G_CALLBACK(gtkPropertyEvent), this);
	}
	else {
		NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
		gtk_status_icon_set_tooltip_text(mStatusIcon, reinterpret_cast<const char*>(titleUTF8.get()));
		propertyEventId = 0;
	}

	// Add signals
	g_signal_connect(G_OBJECT(mStatusIcon), "button-press-event", G_CALLBACK(gtkButtonEvent), this);
	g_signal_connect(G_OBJECT(mStatusIcon), "button-release-event", G_CALLBACK(gtkButtonEvent), this);

	// Make visible
	gtk_status_icon_set_visible(mStatusIcon, 1);
	return NS_OK;
}

Icon::~Icon()
{
	Restore();

	if (mStatusIcon) {
		gtk_status_icon_set_visible(mStatusIcon, 0);
		g_object_unref(mStatusIcon);
	}
	if (propertyEventId) {
		g_signal_handler_disconnect(mGtkWindow, propertyEventId);
	}
}

void Icon::Restore()
{
	gdk_window_show(mGdkWindow);
}

void Icon::Minimize() {
	// Hide the window
	gdk_window_hide(mGdkWindow);
}

void Icon::buttonEvent(GdkEventButton *event)
{
	nsString eventName;
	switch (event->type) {
		case GDK_BUTTON_RELEASE: // use release, so that we don't duplicate events
			eventName = NS_LITERAL_STRING("TrayClick");
			break;
		case GDK_2BUTTON_PRESS:
			eventName = NS_LITERAL_STRING("TrayDblClick");
			break;
		case GDK_3BUTTON_PRESS:
			eventName = NS_LITERAL_STRING("TrayTriClick");
			break;
		default:
			return;
	}

	nsPoint pt((nscoord)(event->x + event->x_root), (nscoord)(event->y + event->y_root));

	// Dispatch the event
#define HASSTATE(x) (event->state & x ? PR_TRUE : PR_FALSE)
	mIcon->DispatchMouseEvent(
			eventName,
			event->button - 1,
			pt,
			HASSTATE(GDK_CONTROL_MASK),
			HASSTATE(GDK_MOD1_MASK),
			HASSTATE(GDK_SHIFT_MASK)
			);
#undef HASSTATE
}

gboolean Icon::propertyEvent()
{
	gtk_status_icon_set_tooltip_text(mStatusIcon, gtk_window_get_title(mGtkWindow));
	return FALSE;
}

} // namespace gtk2

}} // namespaces
<|endoftext|>


<commit_before>/******************************************************************
*
* uHTTP for C++
*
* Copyright (C) Satoshi Konno 2002
*
* This is licensed under BSD-style license, see file COPYING.
*
******************************************************************/

#include <uhttp/util/Thread.h>

#include <stdio.h>

using namespace uHTTP;

////////////////////////////////////////////////
// Thread Func
////////////////////////////////////////////////

#if defined(WIN32) && !defined(ITRON)
static DWORD WINAPI Win32ThreadProc(LPVOID lpParam) {
  Thread *thread = (Thread *)lpParam;
  thread->run();
  return 0;
}
#elif defined(BTRON)
static VOID BTronTaskProc(W param) {
  Thread *thread = (Thread *)param;
  thread->run();
  ext_tsk();
}
#elif defined(ITRON)
static TASK ITronTaskProc(int param) {
  T_RTSK rtsk;
  if (ref_tsk(TSK_SELF, &rtsk) != E_OK)
    return;
  Thread *thread = (Thread *)rtsk.exinf;
  thread->run();
  exd_tsk();
}
#elif defined(TENGINE) && !defined(PROCESS_BASE)
static VOID TEngineTaskProc(INT stacd, VP param) {
  Thread *thread = (Thread *)param;
  thread->run();
  tk_exd_tsk();
}
#elif defined(TENGINE) && defined(PROCESS_BASE)
static VOID TEngineProcessBasedTaskProc(W param) {
  Thread *thread = (Thread *)param;
  thread->run();
  b_ext_tsk();
}
#else
static void *PosixThreadProc(void *param) {
  Thread *thread = (Thread *)param;
  thread->run();
  return 0;
}
#endif

////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////

Thread::Thread() {
  setRunnableFlag(false);
}

bool Thread::start() {
  setRunnableFlag(true);
#if defined(WIN32) && !defined(ITRON)
  hThread = CreateThread(NULL, 0, Win32ThreadProc, (LPVOID)this, 0, &threadID);
#elif defined(BTRON)
  P_STATE pstate;
  prc_sts(0, &pstate, NULL);
  taskID = cre_tsk(BTronTaskProc, pstate.priority, (W)this);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
  if (wup_tsk(taskID) != 0) {
    setRunnableFlag(false);
    return false;
  }
#elif defined(ITRON)
  T_CTSK ctsk = {TA_HLNG,  (VP_INT)this, (FP)ITronTaskProc, 6, 512, NULL, NULL};
  taskID = acre_tsk(&ctsk);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
  if (sta_tsk(taskID, 0) != E_OK) {
    setRunnableFlag(false);
    del_tsk(taskID);
    return FALSE;
  }
#elif defined(TENGINE) && !defined(PROCESS_BASE)
  T_CTSK ctsk = {(VP)this, TA_HLNG, TEngineTaskProc,10, 2048};
  taskID = tk_cre_tsk(&ctsk);
  if (taskID < E_OK) {
    setRunnableFlag(false);
    return false;
  }
  if (tk_sta_tsk(taskID, 0) < E_OK) {
    setRunnableFlag(false);
    tk_del_tsk(thread->taskID);
    return false;
  }
#elif defined(TENGINE) && defined(PROCESS_BASE)
  P_STATE pstate;
  b_prc_sts(0, &pstate, NULL);
  taskID = b_cre_tsk(TEngineProcessBasedTaskProc, pstate.priority, (W)this);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
#else
  pthread_attr_t thread_attr;
  pthread_attr_init(&thread_attr);
  pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
  if (pthread_create(&thread, &thread_attr, PosixThreadProc, this) != 0) {
    setRunnableFlag(false);
    pthread_attr_destroy(&thread_attr);
  }
  pthread_attr_destroy(&thread_attr);
#endif
  return true;
}

Thread::~Thread() {
  stop();
}

bool Thread::stop() {
  if (isRunnable() == true) {
    setRunnableFlag(false);
#if defined(WIN32) && !defined(ITRON)
    TerminateThread(hThread, 0);
    WaitForSingleObject(hThread, INFINITE);
#elif defined(BTRON)
    ter_tsk(taskID);
#elif defined(ITRON)
    ter_tsk(taskID);
    del_tsk(taskID);
#elif defined(TENGINE) && !defined(PROCESS_BASE)
    tk_ter_tsk(taskID);
    tk_del_tsk(taskID);
#elif defined(TENGINE) && defined(PROCESS_BASE)
    b_ter_tsk(taskID);
#else
    pthread_cancel(thread);
    pthread_detach(thread);
#endif
  }
  return true;
}

void Thread::setRunnableFlag(bool flag) {
  runnableFlag = flag;
}

bool Thread::isRunnable() {
#if !defined(WIN32) && !defined(ITRON) && !defined(BTRON) && !defined(TENGINE) && !defined(PROCESS_BASE)
  pthread_testcancel();
#endif
  return runnableFlag;
}

<commit_msg>* Fixed Thread::start() to check resutls of pthread_*() on Unix platform.<commit_after>/******************************************************************
*
* uHTTP for C++
*
* Copyright (C) Satoshi Konno 2002
*
* This is licensed under BSD-style license, see file COPYING.
*
******************************************************************/

#include <uhttp/util/Thread.h>

#include <stdio.h>

using namespace uHTTP;

////////////////////////////////////////////////
// Thread Func
////////////////////////////////////////////////

#if defined(WIN32) && !defined(ITRON)
static DWORD WINAPI Win32ThreadProc(LPVOID lpParam) {
  Thread *thread = (Thread *)lpParam;
  thread->run();
  return 0;
}
#elif defined(BTRON)
static VOID BTronTaskProc(W param) {
  Thread *thread = (Thread *)param;
  thread->run();
  ext_tsk();
}
#elif defined(ITRON)
static TASK ITronTaskProc(int param) {
  T_RTSK rtsk;
  if (ref_tsk(TSK_SELF, &rtsk) != E_OK)
    return;
  Thread *thread = (Thread *)rtsk.exinf;
  thread->run();
  exd_tsk();
}
#elif defined(TENGINE) && !defined(PROCESS_BASE)
static VOID TEngineTaskProc(INT stacd, VP param) {
  Thread *thread = (Thread *)param;
  thread->run();
  tk_exd_tsk();
}
#elif defined(TENGINE) && defined(PROCESS_BASE)
static VOID TEngineProcessBasedTaskProc(W param) {
  Thread *thread = (Thread *)param;
  thread->run();
  b_ext_tsk();
}
#else
static void *PosixThreadProc(void *param) {
  Thread *thread = (Thread *)param;
  thread->run();
  return 0;
}
#endif

////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////

Thread::Thread() {
  setRunnableFlag(false);
}

bool Thread::start() {
  setRunnableFlag(true);
#if defined(WIN32) && !defined(ITRON)
  hThread = CreateThread(NULL, 0, Win32ThreadProc, (LPVOID)this, 0, &threadID);
#elif defined(BTRON)
  P_STATE pstate;
  prc_sts(0, &pstate, NULL);
  taskID = cre_tsk(BTronTaskProc, pstate.priority, (W)this);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
  if (wup_tsk(taskID) != 0) {
    setRunnableFlag(false);
    return false;
  }
#elif defined(ITRON)
  T_CTSK ctsk = {TA_HLNG,  (VP_INT)this, (FP)ITronTaskProc, 6, 512, NULL, NULL};
  taskID = acre_tsk(&ctsk);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
  if (sta_tsk(taskID, 0) != E_OK) {
    setRunnableFlag(false);
    del_tsk(taskID);
    return FALSE;
  }
#elif defined(TENGINE) && !defined(PROCESS_BASE)
  T_CTSK ctsk = {(VP)this, TA_HLNG, TEngineTaskProc,10, 2048};
  taskID = tk_cre_tsk(&ctsk);
  if (taskID < E_OK) {
    setRunnableFlag(false);
    return false;
  }
  if (tk_sta_tsk(taskID, 0) < E_OK) {
    setRunnableFlag(false);
    tk_del_tsk(thread->taskID);
    return false;
  }
#elif defined(TENGINE) && defined(PROCESS_BASE)
  P_STATE pstate;
  b_prc_sts(0, &pstate, NULL);
  taskID = b_cre_tsk(TEngineProcessBasedTaskProc, pstate.priority, (W)this);
  if (taskID < 0) {
    setRunnableFlag(false);
    return false;
  }
#else
  pthread_attr_t thread_attr;
  if (pthread_attr_init(&thread_attr) != 0)
    return false;
  if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
    pthread_attr_destroy(&thread_attr);
    return false;
  }
  if (pthread_create(&thread, &thread_attr, PosixThreadProc, this) != 0) {
    setRunnableFlag(false);
    pthread_attr_destroy(&thread_attr);
    return false;
  }
  pthread_attr_destroy(&thread_attr);
#endif
  return true;
}

Thread::~Thread() {
  stop();
}

bool Thread::stop() {
  if (isRunnable() == true) {
    setRunnableFlag(false);
#if defined(WIN32) && !defined(ITRON)
    TerminateThread(hThread, 0);
    WaitForSingleObject(hThread, INFINITE);
#elif defined(BTRON)
    ter_tsk(taskID);
#elif defined(ITRON)
    ter_tsk(taskID);
    del_tsk(taskID);
#elif defined(TENGINE) && !defined(PROCESS_BASE)
    tk_ter_tsk(taskID);
    tk_del_tsk(taskID);
#elif defined(TENGINE) && defined(PROCESS_BASE)
    b_ter_tsk(taskID);
#else
    pthread_cancel(thread);
    pthread_detach(thread);
#endif
  }
  return true;
}

void Thread::setRunnableFlag(bool flag) {
  runnableFlag = flag;
}

bool Thread::isRunnable() {
#if !defined(WIN32) && !defined(ITRON) && !defined(BTRON) && !defined(TENGINE) && !defined(PROCESS_BASE)
  pthread_testcancel();
#endif
  return runnableFlag;
}

<|endoftext|>


<commit_before>#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/extensions/ut_pex.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;

void test_pex()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48200, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49200, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50200, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 500000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	// make the peer connecting the two worthless to transfer
	// data, to force peer 3 to connect directly to peer 1 through pex
	ses2.set_upload_rate_limit(200);
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	ses1.add_extension(&create_ut_pex_plugin);
	ses2.add_extension(&create_ut_pex_plugin);

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, false, "_pex");

	test_sleep(1000);

	tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));
	tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1"), ses3.listen_port()));

	for (int i = 0; i < 40; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers << " - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< st3.num_peers
			<< std::endl;

		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	TEST_CHECK(tor3.is_seed());

	if (!tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1_pex"); } catch (std::exception&) {}
	try { remove_all("./tmp2_pex"); } catch (std::exception&) {}
	try { remove_all("./tmp3_pex"); } catch (std::exception&) {}

	test_pex();

	remove_all("./tmp1_pex");
	remove_all("./tmp2_pex");
	remove_all("./tmp3_pex");

	return 0;
}

<commit_msg>fixed pex test<commit_after>#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/extensions/ut_pex.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;

void test_pex()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48200, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49200, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50200, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 500000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	// make the peer connecting the two worthless to transfer
	// data, to force peer 3 to connect directly to peer 1 through pex
	ses2.set_upload_rate_limit(200);
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	ses1.add_extension(&create_ut_pex_plugin);
	ses2.add_extension(&create_ut_pex_plugin);

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, false, "_pex");

	test_sleep(1000);

	tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));
	tor2.connect_peer(tcp::endpoint(address::from_string("127.0.0.1"), ses3.listen_port()));

	for (int i = 0; i < 40; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers << " - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< st3.num_peers
			<< std::endl;

		if (st3.state == torrent_status::seeding) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor3.is_seed());

	if (!tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1_pex"); } catch (std::exception&) {}
	try { remove_all("./tmp2_pex"); } catch (std::exception&) {}
	try { remove_all("./tmp3_pex"); } catch (std::exception&) {}

	test_pex();

	remove_all("./tmp1_pex");
	remove_all("./tmp2_pex");
	remove_all("./tmp3_pex");

	return 0;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2013, 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/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/error.hpp> // for asio::error::get_ssl_category()
#endif

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
	int peer_errors;
	int ssl_disconnects;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false, 0, 0},
	{"nobody has a cert (connect to ssl port)", true, false, false, false, 1, 1},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false, 0, 0},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false, 1, 1},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false, 0, 0},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false, 1, 1},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false, 0, 0},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true, 0, 0},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false, 0, 0},
#endif
};

int peer_disconnects = 0;
int peer_errors = 0;
int ssl_peer_disconnects = 0;

bool on_alert(alert* a)
{
	if (alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	if (peer_error_alert* e = alert_cast<peer_error_alert>(a))
	{
		++peer_disconnects;
		++peer_errors;

#ifdef TORRENT_USE_OPENSSL
		if (e->error.category() == boost::asio::error::get_ssl_category())
			++ssl_peer_disconnects;
#endif
	}
	return false;
}

void test_ssl(int test_idx, bool use_utp)
{
	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;

	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s Protocol: %s\n\n", time_now_string(), test.name, use_utp ? "uTP": "TCP");

#ifndef TORRENT_USE_OPENSSL
	if (test.use_ssl_ports)
	{
		fprintf(stderr, "N/A\n");
		return;
	}
#endif

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	session_settings sett;

	sett.enable_incoming_utp = use_utp;
	sett.enable_outgoing_utp = use_utp;
	sett.enable_incoming_tcp = !use_utp;
	sett.enable_outgoing_tcp = !use_utp;

	sett.ssl_listen = 1024 + rand() % 50000;

	ses1.set_settings(sett);
	sett.ssl_listen += 10;
	ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "../ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	peer_disconnects = 0;
	ssl_peer_disconnects = 0;
	peer_errors = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 40;
#endif
	for (int i = 0; i < 40; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &on_alert);
		print_alerts(ses2, "ses2", true, true, true, &on_alert);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects >= 2)
		{
			fprintf(stderr, "too many disconnects (%d), breaking\n", peer_disconnects);
			break;
		}

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading
			|| st2.state == torrent_status::checking_resume_data);

		test_sleep(100);
	}

	fprintf(stderr, "peer_errors: %d  expected: %d\n", peer_errors, test.peer_errors);
	TEST_EQUAL(peer_errors, test.peer_errors);
#ifdef TORRENT_USE_OPENSSL
	fprintf(stderr, "ssl_disconnects: %d  expected: %d\n", ssl_peer_disconnects, test.ssl_disconnects);
	TEST_EQUAL(ssl_peer_disconnects, test.ssl_disconnects);
#endif
	fprintf(stderr, "%s: EXPECT: %s\n", time_now_string(), test.expected_to_complete ? "SUCCEESS" : "FAILURE");
	fprintf(stderr, "%s: RESULT: %s\n", time_now_string(), tor2.status().is_seeding ? "SUCCEESS" : "FAILURE");
	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
}

int test_main()
{
	using namespace libtorrent;

	// No support for SSL/uTP yet, so always pass in false
	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i, false);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<commit_msg>fix typo<commit_after>/*

Copyright (c) 2013, 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/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/error.hpp> // for asio::error::get_ssl_category()
#endif

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
	int peer_errors;
	int ssl_disconnects;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false, 0, 0},
	{"nobody has a cert (connect to ssl port)", true, false, false, false, 1, 1},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false, 0, 0},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false, 1, 1},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false, 0, 0},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false, 1, 1},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false, 0, 0},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true, 0, 0},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false, 0, 0},
#endif
};

int peer_disconnects = 0;
int peer_errors = 0;
int ssl_peer_disconnects = 0;

bool on_alert(alert* a)
{
	if (alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	if (peer_error_alert* e = alert_cast<peer_error_alert>(a))
	{
		++peer_disconnects;
		++peer_errors;

#ifdef TORRENT_USE_OPENSSL
		if (e->error.category() == boost::asio::error::get_ssl_category())
			++ssl_peer_disconnects;
#endif
	}
	return false;
}

void test_ssl(int test_idx, bool use_utp)
{
	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;

	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s Protocol: %s\n\n", time_now_string(), test.name, use_utp ? "uTP": "TCP");

#ifndef TORRENT_USE_OPENSSL
	if (test.use_ssl_ports)
	{
		fprintf(stderr, "N/A\n");
		return;
	}
#endif

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	session_settings sett;

	sett.enable_incoming_utp = use_utp;
	sett.enable_outgoing_utp = use_utp;
	sett.enable_incoming_tcp = !use_utp;
	sett.enable_outgoing_tcp = !use_utp;

	sett.ssl_listen = 1024 + rand() % 50000;

	ses1.set_settings(sett);
	sett.ssl_listen += 10;
	ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "../ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	peer_disconnects = 0;
	ssl_peer_disconnects = 0;
	peer_errors = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 40;
#endif
	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &on_alert);
		print_alerts(ses2, "ses2", true, true, true, &on_alert);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects >= 2)
		{
			fprintf(stderr, "too many disconnects (%d), breaking\n", peer_disconnects);
			break;
		}

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading
			|| st2.state == torrent_status::checking_resume_data);

		test_sleep(100);
	}

	fprintf(stderr, "peer_errors: %d  expected: %d\n", peer_errors, test.peer_errors);
	TEST_EQUAL(peer_errors, test.peer_errors);
#ifdef TORRENT_USE_OPENSSL
	fprintf(stderr, "ssl_disconnects: %d  expected: %d\n", ssl_peer_disconnects, test.ssl_disconnects);
	TEST_EQUAL(ssl_peer_disconnects, test.ssl_disconnects);
#endif
	fprintf(stderr, "%s: EXPECT: %s\n", time_now_string(), test.expected_to_complete ? "SUCCEESS" : "FAILURE");
	fprintf(stderr, "%s: RESULT: %s\n", time_now_string(), tor2.status().is_seeding ? "SUCCEESS" : "FAILURE");
	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
}

int test_main()
{
	using namespace libtorrent;

	// No support for SSL/uTP yet, so always pass in false
	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i, false);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<|endoftext|>


<commit_before>#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#include "music-player.h"
#include "globals.h"
#include <iostream>
#include "configuration.h"
#include "sound.h"

#include "dumb/include/dumb.h"
#include "gme/Music_Emu.h"

#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#include "ogg/logg.h"

#ifdef _WIN32
/* what do we need winalleg for?
 * reason: ...
 */
#include <winalleg.h>
#endif

#endif

#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif

#include "exceptions/exception.h"

namespace Util{

static double scaleVolume(double start){
    return start * Configuration::getMusicVolume() / 100;
}

MusicPlayer::MusicPlayer():
volume(1.0){
}

MusicPlayer::~MusicPlayer(){
}

static const char * typeToExtension( int i ){
    switch (i){
        case 0 : return ".xm";
        case 1 : return ".s3m";
        case 2 : return ".it";
        case 3 : return ".mod";
        default : return "";
    }
}

DUH * DumbPlayer::loadDumbFile(const char * path){
    DUH * what;
    for (int i = 0; i < 4; i++){
        /* the order of trying xm/s3m/it/mod matters because mod could be
         * confused with one of the other formats, so load it last.
         */
        switch (i){
            case 0 : {
                 what =  dumb_load_xm_quick(path);
                 break;
            }
            case 1 : {
                what = dumb_load_s3m_quick(path);
                break;
            }
            case 2 : {
                what = dumb_load_it_quick(path);
                break;
            }
            case 3 : {
                what = dumb_load_mod_quick(path);
                break;
            }
        }

        if (what != NULL){
            Global::debug(0) << "Loaded " << path << " type " << typeToExtension(i) << "(" << i << ")" << std::endl;
            return what;
        }
    }
    return NULL;
}

#ifdef USE_ALLEGRO

DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file != NULL){
        int buf = 1 << 11;
        player = al_start_duh(music_file, 2, 0, scaleVolume(volume), buf, Sound::FREQUENCY);
    }
}

void DumbPlayer::play(){
    al_resume_duh(this->player);
}

void DumbPlayer::poll(){
    if (al_poll_duh(this->player) != 0){
    }
}

void DumbPlayer::pause(){
    al_pause_duh(this->player);
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    al_duh_set_volume(player, scaleVolume(volume));
}

DumbPlayer::~DumbPlayer(){
    al_stop_duh(player);
    unload_duh(music_file);
}

static const int GME_BUFFER_SIZE = 1 << 11;
GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;

    stream = play_audio_stream(GME_BUFFER_SIZE, 16, 1, Sound::FREQUENCY, 255, 128);
    voice_set_priority(stream->voice, 255);
}

void GMEPlayer::play(){
    voice_start(stream->voice);
}

void GMEPlayer::poll(){
    short * buffer = (short*) get_audio_stream_buffer(stream);
    if (buffer){
        /* size in 16-bit samples is buffer size * channels */
        emulator->play(GME_BUFFER_SIZE * 2, buffer);
        if (emulator->track_ended()){
            gme_info_t * info;
            gme_track_info(emulator, &info, 0);
            int intro = info->intro_length;
            emulator->start_track(0);
            // Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
            /* skip past the intro if there is a loop */
            if (info->loop_length != 0){
                emulator->seek(intro);
            }
        }

        /* allegro wants unsigned data but gme produces signed so to convert
         * signed samples to unsigned samples we have to raise each value
         * by half the maximum value of a short (0xffff+1)/2 = 0x8000
         */
        for (int i = 0; i < GME_BUFFER_SIZE * 2; i++){
            buffer[i] += 0x8000;
        }

        free_audio_stream_buffer(stream);
    }
}

void GMEPlayer::pause(){
    voice_stop(stream->voice);
}

void GMEPlayer::setVolume(double volume){
    /* FIXME */
}

GMEPlayer::~GMEPlayer(){
    delete emulator;
    stop_audio_stream(stream);
}

#ifdef HAVE_OGG
OggPlayer::OggPlayer(const char * path){
    stream = logg_get_stream(path, scaleVolume(volume) * 255, 128, 1);
}

void OggPlayer::play(){
}

void OggPlayer::poll(){
    logg_update_stream(stream);
}

void OggPlayer::pause(){
}

void OggPlayer::setVolume(double volume){
}

OggPlayer::~OggPlayer(){
    logg_destroy_stream(stream);
}
#endif /* OGG */

#endif /* ALlEGRO */

#ifdef USE_SDL
DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file == NULL){
        throw Exception::Base(__FILE__, __LINE__);
    }

    int n_channels = 2;
    int position = 0;
    renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
    if (!renderer){
        Global::debug(0) << "Could not create renderer" << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
}

void DumbPlayer::render(Uint8 * stream, int length){
    double delta = 65536.0 / Sound::FREQUENCY;

    /* a frame is 32 bits, 16 bit samples with 2 channels = 2 * 16,
     * so we have to divide the number of 'dumb samples' by the
     * size of each frame, 32 bits = 4 bytes
     */
    /* FIXME: use global music volume to scale the output here */
    int n = duh_render(renderer, 16, 0, volume, delta, length / 4, stream);

    if (n == 0){
        Global::debug(0) << "Sound finished?" << std::endl;
    }

    /*
    short large = 0;
    for (int i = 0; i < length / 2; i++){
        short z = ((short *) stream)[i];
        if (z < 0){
            z = -z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest amplitude " << large << std::endl;
    */
}

struct DumbPlayerInfo{
    MusicPlayer * who;
};

void DumbPlayer::mixer(void * player_, Uint8 * stream, int length){
    DumbPlayerInfo * info = (DumbPlayerInfo *) player_;
    DumbPlayer * player = (DumbPlayer *) info->who;
    player->render(stream, length);
}

void DumbPlayer::pause(){
    Mix_HookMusic(NULL, NULL);
}

void DumbPlayer::play(){
    DumbPlayerInfo * me = new DumbPlayerInfo;
    me->who = this;
    Mix_HookMusic(mixer, me);
}

void DumbPlayer::poll(){
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
}

DumbPlayer::~DumbPlayer(){
    DumbPlayerInfo * info = (DumbPlayerInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    /* I'm pretty sure if we get this far then there is no chance
     * that our mixer function will still be active.
     */
    duh_end_sigrenderer(renderer);
    unload_duh(music_file);
}

struct GMEInfo{
    GMEPlayer * player;
};

GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;
}

void GMEPlayer::mixer(void * arg, Uint8 * stream, int length){
    GMEInfo * info = (GMEInfo*) arg;
    info->player->render(stream, length);
}

void GMEPlayer::render(Uint8 * stream, int length){
    /* length/2 to convert bytes to short */
    emulator->play(length / 2, (short*) stream);

    /*
    short large = 0;
    short small = 0;
    for (int i = 0; i < length / 2; i++){
        // ((short *) stream)[i] *= 2;
        short z = ((short *) stream)[i];
        if (z < small){
            small = z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
    */
}

void GMEPlayer::play(){
    GMEInfo * me = new GMEInfo;
    me->player = this;
    Mix_HookMusic(mixer, me);
}

void GMEPlayer::poll(){
}

void GMEPlayer::pause(){
}

void GMEPlayer::setVolume(double volume){
}

GMEPlayer::~GMEPlayer(){
    GMEInfo * info = (GMEInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    delete emulator;
}

#ifdef HAVE_OGG

OggPlayer::OggPlayer(const char * path){
    music = Mix_LoadMUS(path);
}

void OggPlayer::play(){
    Mix_PlayMusic(music, -1);
}

void OggPlayer::poll(){
}

void OggPlayer::pause(){
    Mix_PauseMusic();
}

void OggPlayer::setVolume(double volume){
    Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

OggPlayer::~OggPlayer(){
    Mix_FreeMusic(music);
}

#endif /* OGG */

#endif /* SDL */

}
<commit_msg>throw exception if music cant be loaded<commit_after>#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#include "music-player.h"
#include "globals.h"
#include <iostream>
#include "configuration.h"
#include "sound.h"

#include "dumb/include/dumb.h"
#include "gme/Music_Emu.h"

#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#include "ogg/logg.h"

#ifdef _WIN32
/* what do we need winalleg for?
 * reason: ...
 */
#include <winalleg.h>
#endif

#endif

#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif

#include "exceptions/exception.h"
#include <sstream>

namespace Util{

class MusicException: public Exception::Base {
public:
    MusicException(const std::string & file, int line, const std::string & reason):
        Exception::Base(file, line),
        reason(reason){
        }

    MusicException(const MusicException & copy):
    Exception::Base(copy),
    reason(copy.reason){
    }

    virtual ~MusicException() throw(){
    }

protected:
    virtual const std::string getReason() const {
        return reason;
    }

    virtual Exception::Base * copy() const {
        return new MusicException(*this);
    }

    std::string reason;
};

static double scaleVolume(double start){
    return start * Configuration::getMusicVolume() / 100;
}

MusicPlayer::MusicPlayer():
volume(1.0){
}

MusicPlayer::~MusicPlayer(){
}

static const char * typeToExtension( int i ){
    switch (i){
        case 0 : return ".xm";
        case 1 : return ".s3m";
        case 2 : return ".it";
        case 3 : return ".mod";
        default : return "";
    }
}

DUH * DumbPlayer::loadDumbFile(const char * path){
    DUH * what;
    for (int i = 0; i < 4; i++){
        /* the order of trying xm/s3m/it/mod matters because mod could be
         * confused with one of the other formats, so load it last.
         */
        switch (i){
            case 0 : {
                 what =  dumb_load_xm_quick(path);
                 break;
            }
            case 1 : {
                what = dumb_load_s3m_quick(path);
                break;
            }
            case 2 : {
                what = dumb_load_it_quick(path);
                break;
            }
            case 3 : {
                what = dumb_load_mod_quick(path);
                break;
            }
        }

        if (what != NULL){
            Global::debug(0) << "Loaded " << path << " type " << typeToExtension(i) << "(" << i << ")" << std::endl;
            return what;
        }
    }
    return NULL;
}

#ifdef USE_ALLEGRO

DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file != NULL){
        int buf = 1 << 11;
        player = al_start_duh(music_file, 2, 0, scaleVolume(volume), buf, Sound::FREQUENCY);
    } else {
        std::ostringstream error;
        error << "Could not DUMB file load " << path;
        throw MusicException(__FILE__, __LINE__, path.str());
    }
}

void DumbPlayer::play(){
    al_resume_duh(this->player);
}

void DumbPlayer::poll(){
    if (al_poll_duh(this->player) != 0){
    }
}

void DumbPlayer::pause(){
    al_pause_duh(this->player);
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    al_duh_set_volume(player, scaleVolume(volume));
}

DumbPlayer::~DumbPlayer(){
    al_stop_duh(player);
    unload_duh(music_file);
}

static const int GME_BUFFER_SIZE = 1 << 11;
GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;

    stream = play_audio_stream(GME_BUFFER_SIZE, 16, 1, Sound::FREQUENCY, 255, 128);
    voice_set_priority(stream->voice, 255);
}

void GMEPlayer::play(){
    voice_start(stream->voice);
}

void GMEPlayer::poll(){
    short * buffer = (short*) get_audio_stream_buffer(stream);
    if (buffer){
        /* size in 16-bit samples is buffer size * channels */
        emulator->play(GME_BUFFER_SIZE * 2, buffer);
        if (emulator->track_ended()){
            gme_info_t * info;
            gme_track_info(emulator, &info, 0);
            int intro = info->intro_length;
            emulator->start_track(0);
            // Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
            /* skip past the intro if there is a loop */
            if (info->loop_length != 0){
                emulator->seek(intro);
            }
        }

        /* allegro wants unsigned data but gme produces signed so to convert
         * signed samples to unsigned samples we have to raise each value
         * by half the maximum value of a short (0xffff+1)/2 = 0x8000
         */
        for (int i = 0; i < GME_BUFFER_SIZE * 2; i++){
            buffer[i] += 0x8000;
        }

        free_audio_stream_buffer(stream);
    }
}

void GMEPlayer::pause(){
    voice_stop(stream->voice);
}

void GMEPlayer::setVolume(double volume){
    /* FIXME */
}

GMEPlayer::~GMEPlayer(){
    delete emulator;
    stop_audio_stream(stream);
}

#ifdef HAVE_OGG
OggPlayer::OggPlayer(const char * path){
    stream = logg_get_stream(path, scaleVolume(volume) * 255, 128, 1);
    if (stream == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load ogg file");
    }
}

void OggPlayer::play(){
}

void OggPlayer::poll(){
    logg_update_stream(stream);
}

void OggPlayer::pause(){
}

void OggPlayer::setVolume(double volume){
}

OggPlayer::~OggPlayer(){
    logg_destroy_stream(stream);
}
#endif /* OGG */

#endif /* ALlEGRO */

#ifdef USE_SDL
DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file == NULL){
        std::ostringstream error;
        error << "Could not load DUMB file " << path;
        throw MusicException(__FILE__, __LINE__, error.str());
    }

    int n_channels = 2;
    int position = 0;
    renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
    if (!renderer){
        Global::debug(0) << "Could not create renderer" << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
}

void DumbPlayer::render(Uint8 * stream, int length){
    double delta = 65536.0 / Sound::FREQUENCY;

    /* a frame is 32 bits, 16 bit samples with 2 channels = 2 * 16,
     * so we have to divide the number of 'dumb samples' by the
     * size of each frame, 32 bits = 4 bytes
     */
    /* FIXME: use global music volume to scale the output here */
    int n = duh_render(renderer, 16, 0, volume, delta, length / 4, stream);

    if (n == 0){
        Global::debug(0) << "Sound finished?" << std::endl;
    }

    /*
    short large = 0;
    for (int i = 0; i < length / 2; i++){
        short z = ((short *) stream)[i];
        if (z < 0){
            z = -z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest amplitude " << large << std::endl;
    */
}

struct DumbPlayerInfo{
    MusicPlayer * who;
};

void DumbPlayer::mixer(void * player_, Uint8 * stream, int length){
    DumbPlayerInfo * info = (DumbPlayerInfo *) player_;
    DumbPlayer * player = (DumbPlayer *) info->who;
    player->render(stream, length);
}

void DumbPlayer::pause(){
    Mix_HookMusic(NULL, NULL);
}

void DumbPlayer::play(){
    DumbPlayerInfo * me = new DumbPlayerInfo;
    me->who = this;
    Mix_HookMusic(mixer, me);
}

void DumbPlayer::poll(){
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
}

DumbPlayer::~DumbPlayer(){
    DumbPlayerInfo * info = (DumbPlayerInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    /* I'm pretty sure if we get this far then there is no chance
     * that our mixer function will still be active.
     */
    duh_end_sigrenderer(renderer);
    unload_duh(music_file);
}

struct GMEInfo{
    GMEPlayer * player;
};

GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;
}

void GMEPlayer::mixer(void * arg, Uint8 * stream, int length){
    GMEInfo * info = (GMEInfo*) arg;
    info->player->render(stream, length);
}

void GMEPlayer::render(Uint8 * stream, int length){
    /* length/2 to convert bytes to short */
    emulator->play(length / 2, (short*) stream);

    /*
    short large = 0;
    short small = 0;
    for (int i = 0; i < length / 2; i++){
        // ((short *) stream)[i] *= 2;
        short z = ((short *) stream)[i];
        if (z < small){
            small = z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
    */
}

void GMEPlayer::play(){
    GMEInfo * me = new GMEInfo;
    me->player = this;
    Mix_HookMusic(mixer, me);
}

void GMEPlayer::poll(){
}

void GMEPlayer::pause(){
}

void GMEPlayer::setVolume(double volume){
}

GMEPlayer::~GMEPlayer(){
    GMEInfo * info = (GMEInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    delete emulator;
}

#ifdef HAVE_OGG

OggPlayer::OggPlayer(const char * path){
    music = Mix_LoadMUS(path);
    if (music == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load OGG file");
    }
}

void OggPlayer::play(){
    Mix_PlayMusic(music, -1);
}

void OggPlayer::poll(){
}

void OggPlayer::pause(){
    Mix_PauseMusic();
}

void OggPlayer::setVolume(double volume){
    Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

OggPlayer::~OggPlayer(){
    Mix_FreeMusic(music);
}

#endif /* OGG */

#endif /* SDL */

}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ Includes -----------------------------------
#include <limits>
#include <utility>

// Local Includes -----------------------------------
#include "libmesh/elem.h"
#include "libmesh/location_maps.h"
#include "libmesh/mesh_base.h"
#include "libmesh/node.h"
#include "libmesh/parallel.h"

//--------------------------------------------------------------------------
namespace
{
  using libMesh::Real;

  // 10 bits per coordinate, to work with 32+ bit machines
  const unsigned int chunkmax = 1024;
  const Real chunkfloat = 1024.0;
}

namespace libMesh
{

//--------------------------------------------------------------------------
template <typename T>
void LocationMap<T>::init(MeshBase& mesh)
{
  // This function must be run on all processors at once
  // for non-serial meshes
  if (!mesh.is_serial())
    parallel_only();

  START_LOG("init()", "LocationMap");

  // Clear the old map
  _map.clear();

  // Cache a bounding box
  _lower_bound.clear();
  _lower_bound.resize(LIBMESH_DIM, std::numeric_limits<Real>::max());
  _upper_bound.clear();
  _upper_bound.resize(LIBMESH_DIM, -std::numeric_limits<Real>::max());

  MeshBase::node_iterator       it  = mesh.nodes_begin();
  const MeshBase::node_iterator end = mesh.nodes_end();

  for (; it != end; ++it)
    {
      Node* node = *it;

      for (unsigned int i=0; i != LIBMESH_DIM; ++i)
        {
          // Expand the bounding box if necessary
          _lower_bound[i] = std::min(_lower_bound[i],
                                     (*node)(i));
          _upper_bound[i] = std::max(_upper_bound[i],
                                     (*node)(i));
        }
    }

  // On a parallel mesh we might not yet have a full bounding box
  if (!mesh.is_serial())
    {
      CommWorld.min(_lower_bound);
      CommWorld.max(_upper_bound);
    }

  this->fill(mesh);

  STOP_LOG("init()", "LocationMap");
}

template <typename T>
void LocationMap<T>::insert(T &t)
{
  this->_map.insert(std::make_pair(this->key(this->point_of(t)), &t));
}

template <>
Point LocationMap<Node>::point_of(const Node& node) const
{
  return node;
}

template <>
Point LocationMap<Elem>::point_of(const Elem& elem) const
{
  return elem.centroid();
}

template <typename T>
T* LocationMap<T>::find(const Point& p,
                     const Real tol)
{
  START_LOG("find()","LocationMap");

  // Look for a likely key in the multimap
  unsigned int pointkey = this->key(p);

  // Look for the exact key first
  std::pair<typename map_type::iterator,
            typename map_type::iterator>
    pos = _map.equal_range(pointkey);

  while (pos.first != pos.second)
    if (p.absolute_fuzzy_equals
         (this->point_of(*(pos.first->second)), tol))
      {
	STOP_LOG("find()","LocationMap");
	return pos.first->second;
      }
    else
      ++pos.first;

  // Look for neighboring bins' keys next
  for (int xoffset = -1; xoffset != 2; ++xoffset)
    {
      for (int yoffset = -1; yoffset != 2; ++yoffset)
        {
          for (int zoffset = -1; zoffset != 2; ++zoffset)
            {
              std::pair<typename map_type::iterator,
                        typename map_type::iterator>
                pos = _map.equal_range(pointkey +
				       xoffset*chunkmax*chunkmax +
				       yoffset*chunkmax +
				       zoffset);
              while (pos.first != pos.second)
                if (p.absolute_fuzzy_equals
                     (this->point_of(*(pos.first->second)), tol))
		  {
		    STOP_LOG("find()","LocationMap");
		    return pos.first->second;
		  }
                else
                  ++pos.first;
            }
        }
    }

  STOP_LOG("find()","LocationMap");
  return NULL;
}

template <typename T>
unsigned int LocationMap<T>::key(const Point& p)
{
  Real xscaled = 0., yscaled = 0., zscaled = 0.;

  Real deltax = _upper_bound[0] - _lower_bound[0];

  if (std::abs(deltax) > TOLERANCE)
    xscaled = (p(0) - _lower_bound[0])/deltax;

  // Only check y-coords if libmesh is compiled with LIBMESH_DIM>1
#if LIBMESH_DIM > 1
  Real deltay = _upper_bound[1] - _lower_bound[1];

  if (std::abs(deltay) > TOLERANCE)
    yscaled = (p(1) - _lower_bound[1])/deltay;
#endif

  // Only check z-coords if libmesh is compiled with LIBMESH_DIM>2
#if LIBMESH_DIM > 2
  Real deltaz = _upper_bound[2] - _lower_bound[2];

  if (std::abs(deltaz) > TOLERANCE)
    zscaled = (p(2) - _lower_bound[2])/deltaz;
#endif

  unsigned int n0 = static_cast<unsigned int> (chunkfloat * xscaled),
               n1 = static_cast<unsigned int> (chunkfloat * yscaled),
               n2 = static_cast<unsigned int> (chunkfloat * zscaled);

  return chunkmax*chunkmax*n0 + chunkmax*n1 + n2;
}

template <>
void LocationMap<Node>::fill(MeshBase& mesh)
{
  // Populate the nodes map
  MeshBase::node_iterator  it = mesh.nodes_begin(),
                          end = mesh.nodes_end();
  for (; it != end; ++it)
    this->insert(**it);
}

template <>
void LocationMap<Elem>::fill(MeshBase& mesh)
{
  // Populate the elem map
  MeshBase::element_iterator       it  = mesh.active_elements_begin(),
                                   end = mesh.active_elements_end();
  for (; it != end; ++it)
    this->insert(**it);
}

template class LocationMap<Elem>;
template class LocationMap<Node>;

} // namespace libMesh
<commit_msg>Changes in location_maps.C for -Wshadow.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ Includes -----------------------------------
#include <limits>
#include <utility>

// Local Includes -----------------------------------
#include "libmesh/elem.h"
#include "libmesh/location_maps.h"
#include "libmesh/mesh_base.h"
#include "libmesh/node.h"
#include "libmesh/parallel.h"

//--------------------------------------------------------------------------
namespace
{
  using libMesh::Real;

  // 10 bits per coordinate, to work with 32+ bit machines
  const unsigned int chunkmax = 1024;
  const Real chunkfloat = 1024.0;
}

namespace libMesh
{

//--------------------------------------------------------------------------
template <typename T>
void LocationMap<T>::init(MeshBase& mesh)
{
  // This function must be run on all processors at once
  // for non-serial meshes
  if (!mesh.is_serial())
    parallel_only();

  START_LOG("init()", "LocationMap");

  // Clear the old map
  _map.clear();

  // Cache a bounding box
  _lower_bound.clear();
  _lower_bound.resize(LIBMESH_DIM, std::numeric_limits<Real>::max());
  _upper_bound.clear();
  _upper_bound.resize(LIBMESH_DIM, -std::numeric_limits<Real>::max());

  MeshBase::node_iterator       it  = mesh.nodes_begin();
  const MeshBase::node_iterator end = mesh.nodes_end();

  for (; it != end; ++it)
    {
      Node* node = *it;

      for (unsigned int i=0; i != LIBMESH_DIM; ++i)
        {
          // Expand the bounding box if necessary
          _lower_bound[i] = std::min(_lower_bound[i],
                                     (*node)(i));
          _upper_bound[i] = std::max(_upper_bound[i],
                                     (*node)(i));
        }
    }

  // On a parallel mesh we might not yet have a full bounding box
  if (!mesh.is_serial())
    {
      CommWorld.min(_lower_bound);
      CommWorld.max(_upper_bound);
    }

  this->fill(mesh);

  STOP_LOG("init()", "LocationMap");
}

template <typename T>
void LocationMap<T>::insert(T &t)
{
  this->_map.insert(std::make_pair(this->key(this->point_of(t)), &t));
}

template <>
Point LocationMap<Node>::point_of(const Node& node) const
{
  return node;
}

template <>
Point LocationMap<Elem>::point_of(const Elem& elem) const
{
  return elem.centroid();
}

template <typename T>
T* LocationMap<T>::find(const Point& p,
                     const Real tol)
{
  START_LOG("find()","LocationMap");

  // Look for a likely key in the multimap
  unsigned int pointkey = this->key(p);

  // Look for the exact key first
  std::pair<typename map_type::iterator,
            typename map_type::iterator>
    pos = _map.equal_range(pointkey);

  while (pos.first != pos.second)
    if (p.absolute_fuzzy_equals
         (this->point_of(*(pos.first->second)), tol))
      {
	STOP_LOG("find()","LocationMap");
	return pos.first->second;
      }
    else
      ++pos.first;

  // Look for neighboring bins' keys next
  for (int xoffset = -1; xoffset != 2; ++xoffset)
    {
      for (int yoffset = -1; yoffset != 2; ++yoffset)
        {
          for (int zoffset = -1; zoffset != 2; ++zoffset)
            {
              std::pair<typename map_type::iterator,
                        typename map_type::iterator>
                key_pos = _map.equal_range(pointkey +
				       xoffset*chunkmax*chunkmax +
				       yoffset*chunkmax +
				       zoffset);
              while (key_pos.first != key_pos.second)
                if (p.absolute_fuzzy_equals
                     (this->point_of(*(key_pos.first->second)), tol))
		  {
		    STOP_LOG("find()","LocationMap");
		    return key_pos.first->second;
		  }
                else
                  ++key_pos.first;
            }
        }
    }

  STOP_LOG("find()","LocationMap");
  return NULL;
}

template <typename T>
unsigned int LocationMap<T>::key(const Point& p)
{
  Real xscaled = 0., yscaled = 0., zscaled = 0.;

  Real deltax = _upper_bound[0] - _lower_bound[0];

  if (std::abs(deltax) > TOLERANCE)
    xscaled = (p(0) - _lower_bound[0])/deltax;

  // Only check y-coords if libmesh is compiled with LIBMESH_DIM>1
#if LIBMESH_DIM > 1
  Real deltay = _upper_bound[1] - _lower_bound[1];

  if (std::abs(deltay) > TOLERANCE)
    yscaled = (p(1) - _lower_bound[1])/deltay;
#endif

  // Only check z-coords if libmesh is compiled with LIBMESH_DIM>2
#if LIBMESH_DIM > 2
  Real deltaz = _upper_bound[2] - _lower_bound[2];

  if (std::abs(deltaz) > TOLERANCE)
    zscaled = (p(2) - _lower_bound[2])/deltaz;
#endif

  unsigned int n0 = static_cast<unsigned int> (chunkfloat * xscaled),
               n1 = static_cast<unsigned int> (chunkfloat * yscaled),
               n2 = static_cast<unsigned int> (chunkfloat * zscaled);

  return chunkmax*chunkmax*n0 + chunkmax*n1 + n2;
}

template <>
void LocationMap<Node>::fill(MeshBase& mesh)
{
  // Populate the nodes map
  MeshBase::node_iterator  it = mesh.nodes_begin(),
                          end = mesh.nodes_end();
  for (; it != end; ++it)
    this->insert(**it);
}

template <>
void LocationMap<Elem>::fill(MeshBase& mesh)
{
  // Populate the elem map
  MeshBase::element_iterator       it  = mesh.active_elements_begin(),
                                   end = mesh.active_elements_end();
  for (; it != end; ++it)
    this->insert(**it);
}

template class LocationMap<Elem>;
template class LocationMap<Node>;

} // namespace libMesh
<|endoftext|>


<commit_before>/* ecppc.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet 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 2 of the License, or
(at your option) any later version.

Tntnet 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 tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include "tnt/ecppc/ecppc.h"
#include "tnt/ecppc/generator.h"
#include "tnt/ecppc/dependencygenerator.h"
#include <tnt/mimedb.h>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include <cxxtools/loginit.h>

namespace tnt
{
  namespace ecppc
  {
    Ecppc::Ecppc(int& argc, char* argv[])
      : requestname(cxxtools::Arg<std::string>(argc, argv, 'n')),
        ns(cxxtools::Arg<std::string>(argc, argv, 'N')),
        ofile(cxxtools::Arg<std::string>(argc, argv, 'o')),
        odir(cxxtools::Arg<std::string>(argc, argv, 'O')),
        mimetype(argc, argv, 'm'),
        mimedb(argc, argv, "--mimetypes", "/etc/mime.types"),
        binary(argc, argv, 'b'),
        multibinary(argc, argv, 'b'),
        singleton(argc, argv, 's'),
        componentclass(argc, argv, 'C'),
        baseclass(argc, argv, 'B'),
        htmlcompress(argc, argv, "--compress-html"),
        csscompress(argc, argv, "--compress-css"),
        jscompress(argc, argv, "--compress-js"),
        compress(argc, argv, 'z'),
        externData(argc, argv, 'x'),
        noData(argc, argv, "--nodata"),
        verbose(argc, argv, 'v'),
        debug(argc, argv, 'd'),
        trace(argc, argv, 't'),
        splitBar(argc, argv, 'S'),
        splitChars(argc, argv, "--split-chars"),
        generateDependencies(argc, argv, 'M'),
        generateHeader(argc, argv, 'h')
    {
      if (argc < 2 || argv[1][0] == '-')
        throw Usage(argv[0]);
      inputfile = argv[1];
      std::copy(argv + 1, argv + argc, std::inserter(inputfiles, inputfiles.end()));

      if (debug)
        log_init_debug();
      else
        log_init();
    }

    int Ecppc::run()
    {
      // requestname aus Inputdatei
      if (requestname.empty())
      {
        if (multibinary)
        {
          std::cerr << "warning: no requestname passed (with -n) - using \"images\"" << std::endl;
          requestname = "images";
        }
        else
        {
          std::string input = inputfile;
          std::string::size_type pos_dot = input.find_last_of(".");
          std::string::size_type pos_slash = input.find_last_of("\\/");
          if (pos_dot != std::string::npos)
          {
            if (pos_slash == std::string::npos)
            {
              requestname = input.substr(0, pos_dot);
            }
            else if (pos_slash < pos_dot)
            {
              requestname = input.substr(pos_slash + 1, pos_dot - pos_slash - 1);

              if (ns.empty())
              {
                std::string::size_type pos_slash2 = input.find_last_of("\\/", pos_slash - 1);
                if (pos_slash2 == std::string::npos)
                  ns = input.substr(0, pos_slash);
                else
                  ns = input.substr(pos_slash2 + 1, pos_slash - pos_slash2 - 1);
              }
            }

            extname = input.substr(pos_dot + 1);
          }
          else
          {
            requestname = input;
          }

          if (requestname.empty())
          {
            std::cerr << "cannot derive classname from filename. Use -n" << std::endl;
            return -1;
          }
        }
      }
      else if (ns.empty())
      {
        std::string::size_type p = requestname.find("::");
        if (p != std::string::npos)
        {
          ns = requestname.substr(0, p);
          requestname.erase(0, p + 2);
        }
      }

      if (generateDependencies)
        return runDepencencies();
      else
        return runGenerator();
    }

    int Ecppc::runGenerator()
    {
      if (ofile.empty())
      {
        if (ns.empty())
          ofile = requestname;
        else
          ofile = ns + '/' + requestname;
      }

      // strip cpp-extension from outputfilename
      if (ofile.size() == ofile.rfind(".cpp") + 4)
        ofile = ofile.substr(0, ofile.size() - 4);

      // create generator
      tnt::ecppc::Generator generator(requestname, ns);

      // initialize
      generator.setDebug(trace);

      if (mimetype.isSet())
        generator.setMimetype(mimetype);
      else if (!extname.empty() && !multibinary)
      {
        tnt::MimeDb db(mimedb);
        tnt::MimeDb::const_iterator it = db.find(extname);
        if (it != db.end())
          generator.setMimetype(it->second);
      }

      if (htmlcompress)
        generator.setHtmlCompress();
      else if (csscompress)
        generator.setCssCompress();
      else if (jscompress)
        generator.setJsCompress();

      generator.setCompress(compress);
      generator.setExternData(externData);
      generator.setNoData(noData);

      if (singleton.isSet())
        generator.setSingleton(singleton);
      if (componentclass.isSet())
        generator.setComponentclass(componentclass);
      if (baseclass.isSet())
        generator.setBaseclass(baseclass);

      std::string obase = odir;
      if (!obase.empty())
        obase += '/';
      obase += ofile;

      //
      // parse sourcefile
      //

      if (multibinary)
      {
        tnt::MimeDb mimeDb;
        if (!mimetype.isSet())
          mimeDb.read(mimedb);

        for (inputfiles_type::const_iterator it = inputfiles.begin();
             it != inputfiles.end(); ++it)
        {
          inputfile = it->c_str();

          struct stat st;
          if (stat(inputfile, &st) != 0)
            throw std::runtime_error("can't stat " + std::string(inputfile));

          std::ifstream in(inputfile);
          if (!in)
            throw std::runtime_error("can't read " + std::string(inputfile));

          std::ostringstream content;
          content << in.rdbuf();

          std::string mime;
          if (mimetype.isSet())
            mime = mimetype;
          else
            mime = mimeDb.getMimetype(inputfile);

          generator.addImage(inputfile, content.str(), mime, st.st_ctime);
        }
      }
      else
      {
        std::ifstream in(inputfile);
        if (binary)
        {
          std::ostringstream html;
          html << in.rdbuf();
          generator.onHtml(html.str());
          generator.setRawMode();

          struct stat st;
          if (stat(inputfile, &st) == 0)
            generator.setLastModifiedTime(st.st_ctime);
        }
        else
          runParser(in, generator);
      }

      //
      // generate Code
      //
      if (generateHeader)
      {
        if (verbose)
          std::cout << "generate " << obase << ".h" << std::endl;
        std::ofstream hout((obase + ".h").c_str());
        generator.getHeader(hout, ofile + ".h");
        hout.close();

        if (verbose)
          std::cout << "generate " << obase << ".cpp" << std::endl;
        std::ofstream sout((obase + ".cpp").c_str());
        generator.getCpp(sout, ofile + ".cpp");
        sout.close();
      }
      else
      {
        if (verbose)
          std::cout << "generate " << obase << ".cpp" << std::endl;
        std::ofstream sout((obase + ".cpp").c_str());
        generator.getCppWoHeader(sout, ofile + ".cpp");
        sout.close();
      }

      return 0;
    }

    int Ecppc::runDepencencies()
    {
      tnt::ecppc::Dependencygenerator generator(requestname, inputfile);
      std::ifstream in(inputfile);
      if (!binary)
        runParser(in, generator);

      if (ofile.empty())
        generator.getDependencies(std::cout, generateHeader);
      else
      {
        std::ofstream out(ofile.c_str());
        generator.getDependencies(out, generateHeader);
      }

      return 0;
    }

    void Ecppc::runParser(std::istream& in, tnt::ecpp::ParseHandler& handler)
    {
      // create parser
      tnt::ecpp::Parser parser(handler);

      parser.setSplitBar(splitBar);
      if (splitChars.isSet())
      {
        if (splitChars.getValue()[0] == '\0'
         || splitChars.getValue()[1] == '\0'
         || splitChars.getValue()[2] != '\0')
          throw std::runtime_error("--split-chars needs exactly 2 characters");

        parser.setSplitChars(splitChars.getValue()[0],
                             splitChars.getValue()[1]);
      }

      parser.parse(in);
    }

    Usage::Usage(const char* progname)
    {
      std::ostringstream o;
      o << PACKAGE_STRING "\n\n"
           "ecppc-compiler\n\n"
           "usage: " << progname << " [options] ecpp-source\n\n"
           "  -o filename      outputfile\n"
           "  -n name          classname\n"
           "  -m type          Mimetype\n"
           "  -s               generate singleton\n"
           "  -s-              generate no singleton\n"
           "  -b               binary\n"
           "  -bb              generate multibinary component\n"
           "  -B class         additional base-class\n"
           "  -C class         alternative base-class (derived from tnt::ecppComponent)\n"
           "  --compress-html  remove some space in HTML-code\n"
           "  --compress-css   remove some space in CSS-code\n"
           "  --compress-js    remove some space in JavaScript-code\n"
           "  -z               compress constant data\n"
           "  -x               look for constants in language-specific library\n"
           "  -v               verbose\n"
           "  -t               generate traces\n"
           "  -S               split chunks at '{' und '}'\n"
           "  --split-chars zz select alternative split-chars\n"
           "  -M               generate dependency form Makefile\n"
           "  -h               generate separate header-file\n";
      msg = o.str();
    }
  }
}

int main(int argc, char* argv[])
{
  std::ios::sync_with_stdio(false);

  try
  {
    tnt::ecppc::Ecppc app(argc, argv);
    return app.run();
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
    return -1;
  }
}
<commit_msg>strip path from filenames in multibinary-mode<commit_after>/* ecppc.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet 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 2 of the License, or
(at your option) any later version.

Tntnet 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 tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include "tnt/ecppc/ecppc.h"
#include "tnt/ecppc/generator.h"
#include "tnt/ecppc/dependencygenerator.h"
#include <tnt/mimedb.h>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include <cxxtools/loginit.h>

namespace tnt
{
  namespace ecppc
  {
    Ecppc::Ecppc(int& argc, char* argv[])
      : requestname(cxxtools::Arg<std::string>(argc, argv, 'n')),
        ns(cxxtools::Arg<std::string>(argc, argv, 'N')),
        ofile(cxxtools::Arg<std::string>(argc, argv, 'o')),
        odir(cxxtools::Arg<std::string>(argc, argv, 'O')),
        mimetype(argc, argv, 'm'),
        mimedb(argc, argv, "--mimetypes", "/etc/mime.types"),
        binary(argc, argv, 'b'),
        multibinary(argc, argv, 'b'),
        singleton(argc, argv, 's'),
        componentclass(argc, argv, 'C'),
        baseclass(argc, argv, 'B'),
        htmlcompress(argc, argv, "--compress-html"),
        csscompress(argc, argv, "--compress-css"),
        jscompress(argc, argv, "--compress-js"),
        compress(argc, argv, 'z'),
        externData(argc, argv, 'x'),
        noData(argc, argv, "--nodata"),
        verbose(argc, argv, 'v'),
        debug(argc, argv, 'd'),
        trace(argc, argv, 't'),
        splitBar(argc, argv, 'S'),
        splitChars(argc, argv, "--split-chars"),
        generateDependencies(argc, argv, 'M'),
        generateHeader(argc, argv, 'h')
    {
      if (argc < 2 || argv[1][0] == '-')
        throw Usage(argv[0]);
      inputfile = argv[1];
      std::copy(argv + 1, argv + argc, std::inserter(inputfiles, inputfiles.end()));

      if (debug)
        log_init_debug();
      else
        log_init();
    }

    int Ecppc::run()
    {
      // requestname aus Inputdatei
      if (requestname.empty())
      {
        if (multibinary)
        {
          std::cerr << "warning: no requestname passed (with -n) - using \"images\"" << std::endl;
          requestname = "images";
        }
        else
        {
          std::string input = inputfile;
          std::string::size_type pos_dot = input.find_last_of(".");
          std::string::size_type pos_slash = input.find_last_of("\\/");
          if (pos_dot != std::string::npos)
          {
            if (pos_slash == std::string::npos)
            {
              requestname = input.substr(0, pos_dot);
            }
            else if (pos_slash < pos_dot)
            {
              requestname = input.substr(pos_slash + 1, pos_dot - pos_slash - 1);

              if (ns.empty())
              {
                std::string::size_type pos_slash2 = input.find_last_of("\\/", pos_slash - 1);
                if (pos_slash2 == std::string::npos)
                  ns = input.substr(0, pos_slash);
                else
                  ns = input.substr(pos_slash2 + 1, pos_slash - pos_slash2 - 1);
              }
            }

            extname = input.substr(pos_dot + 1);
          }
          else
          {
            requestname = input;
          }

          if (requestname.empty())
          {
            std::cerr << "cannot derive classname from filename. Use -n" << std::endl;
            return -1;
          }
        }
      }
      else if (ns.empty())
      {
        std::string::size_type p = requestname.find("::");
        if (p != std::string::npos)
        {
          ns = requestname.substr(0, p);
          requestname.erase(0, p + 2);
        }
      }

      if (generateDependencies)
        return runDepencencies();
      else
        return runGenerator();
    }

    int Ecppc::runGenerator()
    {
      if (ofile.empty())
      {
        if (ns.empty())
          ofile = requestname;
        else
          ofile = ns + '/' + requestname;
      }

      // strip cpp-extension from outputfilename
      if (ofile.size() == ofile.rfind(".cpp") + 4)
        ofile = ofile.substr(0, ofile.size() - 4);

      // create generator
      tnt::ecppc::Generator generator(requestname, ns);

      // initialize
      generator.setDebug(trace);

      if (mimetype.isSet())
        generator.setMimetype(mimetype);
      else if (!extname.empty() && !multibinary)
      {
        tnt::MimeDb db(mimedb);
        tnt::MimeDb::const_iterator it = db.find(extname);
        if (it != db.end())
          generator.setMimetype(it->second);
      }

      if (htmlcompress)
        generator.setHtmlCompress();
      else if (csscompress)
        generator.setCssCompress();
      else if (jscompress)
        generator.setJsCompress();

      generator.setCompress(compress);
      generator.setExternData(externData);
      generator.setNoData(noData);

      if (singleton.isSet())
        generator.setSingleton(singleton);
      if (componentclass.isSet())
        generator.setComponentclass(componentclass);
      if (baseclass.isSet())
        generator.setBaseclass(baseclass);

      std::string obase = odir;
      if (!obase.empty())
        obase += '/';
      obase += ofile;

      //
      // parse sourcefile
      //

      if (multibinary)
      {
        tnt::MimeDb mimeDb;
        if (!mimetype.isSet())
          mimeDb.read(mimedb);

        for (inputfiles_type::const_iterator it = inputfiles.begin();
             it != inputfiles.end(); ++it)
        {
          std::string inputfile = *it;

          struct stat st;
          if (stat(inputfile.c_str(), &st) != 0)
            throw std::runtime_error("can't stat " + inputfile);

          std::ifstream in(inputfile.c_str());
          if (!in)
            throw std::runtime_error("can't read " + inputfile);

          std::ostringstream content;
          content << in.rdbuf();

          std::string mime;
          if (mimetype.isSet())
            mime = mimetype;
          else
            mime = mimeDb.getMimetype(inputfile);

          // strip path
          std::string::size_type p;
          if ((p = inputfile.find_last_of('/')) != std::string::npos)
            inputfile.erase(0, p + 1);

          generator.addImage(inputfile, content.str(), mime, st.st_ctime);
        }
      }
      else
      {
        std::ifstream in(inputfile);
        if (binary)
        {
          std::ostringstream html;
          html << in.rdbuf();
          generator.onHtml(html.str());
          generator.setRawMode();

          struct stat st;
          if (stat(inputfile, &st) == 0)
            generator.setLastModifiedTime(st.st_ctime);
        }
        else
          runParser(in, generator);
      }

      //
      // generate Code
      //
      if (generateHeader)
      {
        if (verbose)
          std::cout << "generate " << obase << ".h" << std::endl;
        std::ofstream hout((obase + ".h").c_str());
        generator.getHeader(hout, ofile + ".h");
        hout.close();

        if (verbose)
          std::cout << "generate " << obase << ".cpp" << std::endl;
        std::ofstream sout((obase + ".cpp").c_str());
        generator.getCpp(sout, ofile + ".cpp");
        sout.close();
      }
      else
      {
        if (verbose)
          std::cout << "generate " << obase << ".cpp" << std::endl;
        std::ofstream sout((obase + ".cpp").c_str());
        generator.getCppWoHeader(sout, ofile + ".cpp");
        sout.close();
      }

      return 0;
    }

    int Ecppc::runDepencencies()
    {
      tnt::ecppc::Dependencygenerator generator(requestname, inputfile);
      std::ifstream in(inputfile);
      if (!binary)
        runParser(in, generator);

      if (ofile.empty())
        generator.getDependencies(std::cout, generateHeader);
      else
      {
        std::ofstream out(ofile.c_str());
        generator.getDependencies(out, generateHeader);
      }

      return 0;
    }

    void Ecppc::runParser(std::istream& in, tnt::ecpp::ParseHandler& handler)
    {
      // create parser
      tnt::ecpp::Parser parser(handler);

      parser.setSplitBar(splitBar);
      if (splitChars.isSet())
      {
        if (splitChars.getValue()[0] == '\0'
         || splitChars.getValue()[1] == '\0'
         || splitChars.getValue()[2] != '\0')
          throw std::runtime_error("--split-chars needs exactly 2 characters");

        parser.setSplitChars(splitChars.getValue()[0],
                             splitChars.getValue()[1]);
      }

      parser.parse(in);
    }

    Usage::Usage(const char* progname)
    {
      std::ostringstream o;
      o << PACKAGE_STRING "\n\n"
           "ecppc-compiler\n\n"
           "usage: " << progname << " [options] ecpp-source\n\n"
           "  -o filename      outputfile\n"
           "  -n name          classname\n"
           "  -m type          Mimetype\n"
           "  -s               generate singleton\n"
           "  -s-              generate no singleton\n"
           "  -b               binary\n"
           "  -bb              generate multibinary component\n"
           "  -B class         additional base-class\n"
           "  -C class         alternative base-class (derived from tnt::ecppComponent)\n"
           "  --compress-html  remove some space in HTML-code\n"
           "  --compress-css   remove some space in CSS-code\n"
           "  --compress-js    remove some space in JavaScript-code\n"
           "  -z               compress constant data\n"
           "  -x               look for constants in language-specific library\n"
           "  -v               verbose\n"
           "  -t               generate traces\n"
           "  -S               split chunks at '{' und '}'\n"
           "  --split-chars zz select alternative split-chars\n"
           "  -M               generate dependency form Makefile\n"
           "  -h               generate separate header-file\n";
      msg = o.str();
    }
  }
}

int main(int argc, char* argv[])
{
  std::ios::sync_with_stdio(false);

  try
  {
    tnt::ecppc::Ecppc app(argc, argv);
    return app.run();
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what() << std::endl;
    return -1;
  }
}
<|endoftext|>