<commit_before>/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_function_detect_recursion.cpp
 * Determine whether a shader contains static recursion.
 *
 * Consider the (possibly disjoint) graph of function calls in a shader.  If a
 * program contains recursion, this graph will contain a cycle.  If a function
 * is part of a cycle, it will have a caller and it will have a callee (it
 * calls another function).
 *
 * To detect recursion, the function call graph is constructed.  The graph is
 * repeatedly reduced by removing any function that either has no callees
 * (leaf functions) or has no caller.  Eventually the only functions that
 * remain will be the functions in the cycles.
 *
 * The GLSL spec is a bit wishy-washy about recursion.
 *
 * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
 *
 *     "Behavior is undefined if recursion is used. Recursion means having any
 *     function appearing more than once at any one time in the run-time stack
 *     of function calls. That is, a function may not call itself either
 *     directly or indirectly. Compilers may give diagnostic messages when
 *     this is detectable at compile time, but not all such cases can be
 *     detected at compile time."
 *
 * From page 79 (page 85 of the PDF):
 *
 *     "22) Should recursion be supported?
 *
 *      DISCUSSION: Probably not necessary, but another example of limiting
 *      the language based on how it would directly map to hardware. One
 *      thought is that recursion would benefit ray tracing shaders. On the
 *      other hand, many recursion operations can also be implemented with the
 *      user managing the recursion through arrays. RenderMan doesn't support
 *      recursion. This could be added at a later date, if it proved to be
 *      necessary.
 *
 *      RESOLVED on September 10, 2002: Implementations are not required to
 *      support recursion.
 *
 *      CLOSED on September 10, 2002."
 *
 * From page 79 (page 85 of the PDF):
 *
 *     "56) Is it an error for an implementation to support recursion if the
 *     specification says recursion is not supported?
 *
 *     ADDED on September 10, 2002.
 *
 *     DISCUSSION: This issues is related to Issue (22). If we say that
 *     recursion (or some other piece of functionality) is not supported, is
 *     it an error for an implementation to support it? Perhaps the
 *     specification should remain silent on these kind of things so that they
 *     could be gracefully added later as an extension or as part of the
 *     standard.
 *
 *     RESOLUTION: Languages, in general, have programs that are not
 *     well-formed in ways a compiler cannot detect. Portability is only
 *     ensured for well-formed programs. Detecting recursion is an example of
 *     this. The language will say a well-formed program may not recurse, but
 *     compilers are not forced to detect that recursion may happen.
 *
 *     CLOSED: November 29, 2002."
 *
 * In GLSL 1.10 the behavior of recursion is undefined.  Compilers don't have
 * to reject shaders (at compile-time or link-time) that contain recursion.
 * Instead they could work, or crash, or kill a kitten.
 *
 * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec:
 *
 *     "Recursion is not allowed, not even statically. Static recursion is
 *     present if the static function call graph of the program contains
 *     cycles."
 *
 * This langauge clears things up a bit, but it still leaves a lot of
 * questions unanswered.
 *
 *     - Is the error generated at compile-time or link-time?
 *
 *     - Is it an error to have a recursive function that is never statically
 *       called by main or any function called directly or indirectly by main?
 *       Technically speaking, such a function is not in the "static function
 *       call graph of the program" at all.
 *
 * \bug
 * If a shader has multiple cycles, this algorithm may erroneously complain
 * about functions that aren't in any cycle, but are in the part of the call
 * tree that connects them.  For example, if the call graph consists of a
 * cycle between A and B, and a cycle between D and E, and B also calls C
 * which calls D, then this algorithm will report C as a function which "has
 * static recursion" even though it is not part of any cycle.
 *
 * A better algorithm for cycle detection that doesn't have this drawback can
 * be found here:
 *
 * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm
 *
 * \author Ian Romanick <ian.d.romanick@intel.com>
 */
#include "main/core.h"
#include "ir.h"
#include "glsl_parser_extras.h"
#include "linker.h"
#include "program/hash_table.h"
#include "program.h"

struct call_node : public exec_node {
   class function *func;
};

class function {
public:
   function(ir_function_signature *sig)
      : sig(sig)
   {
      /* empty */
   }

   /* Callers of this ralloc-based new need not call delete. It's
    * easier to just ralloc_free 'ctx' (or any of its ancestors). */
   static void* operator new(size_t size, void *ctx)
   {
      void *node;

      node = ralloc_size(ctx, size);
      assert(node != NULL);

      return node;
   }

   /* If the user *does* call delete, that's OK, we will just
    * ralloc_free in that case. */
   static void operator delete(void *node)
   {
      ralloc_free(node);
   }

   ir_function_signature *sig;

   /** List of functions called by this function. */
   exec_list callees;

   /** List of functions that call this function. */
   exec_list callers;
};

class has_recursion_visitor : public ir_hierarchical_visitor {
public:
   has_recursion_visitor()
      : current(NULL)
   {
      this->mem_ctx = ralloc_context(NULL);
      this->function_hash = hash_table_ctor(0, hash_table_pointer_hash,
					    hash_table_pointer_compare);
   }

   ~has_recursion_visitor()
   {
      hash_table_dtor(this->function_hash);
      ralloc_free(this->mem_ctx);
   }

   function *get_function(ir_function_signature *sig)
   {
      function *f = (function *) hash_table_find(this->function_hash, sig);
      if (f == NULL) {
	 f = new(mem_ctx) function(sig);
	 hash_table_insert(this->function_hash, f, sig);
      }

      return f;
   }

   virtual ir_visitor_status visit_enter(ir_function_signature *sig)
   {
      this->current = this->get_function(sig);
      return visit_continue;
   }

   virtual ir_visitor_status visit_leave(ir_function_signature *sig)
   {
      (void) sig;
      this->current = NULL;
      return visit_continue;
   }

   virtual ir_visitor_status visit_enter(ir_call *call)
   {
      /* At global scope this->current will be NULL.  Since there is no way to
       * call global scope, it can never be part of a cycle.  Don't bother
       * adding calls from global scope to the graph.
       */
      if (this->current == NULL)
	 return visit_continue;

      function *const target = this->get_function(call->callee);

      /* Create a link from the caller to the callee.
       */
      call_node *node = new(mem_ctx) call_node;
      node->func = target;
      this->current->callees.push_tail(node);

      /* Create a link from the callee to the caller.
       */
      node = new(mem_ctx) call_node;
      node->func = this->current;
      target->callers.push_tail(node);
      return visit_continue;
   }

   function *current;
   struct hash_table *function_hash;
   void *mem_ctx;
   bool progress;
};

static void
destroy_links(exec_list *list, function *f)
{
   foreach_list_safe(node, list) {
      struct call_node *n = (struct call_node *) node;

      /* If this is the right function, remove it.  Note that the loop cannot
       * terminate now.  There can be multiple links to a function if it is
       * either called multiple times or calls multiple times.
       */
      if (n->func == f)
	 n->remove();
   }
}

/**
 * Remove a function if it has either no in or no out links
 */
static void
remove_unlinked_functions(const void *key, void *data, void *closure)
{
   has_recursion_visitor *visitor = (has_recursion_visitor *) closure;
   function *f = (function *) data;

   if (f->callers.is_empty() || f->callees.is_empty()) {
      while (!f->callers.is_empty()) {
	 struct call_node *n = (struct call_node *) f->callers.pop_head();
	 destroy_links(& n->func->callees, f);
      }

      while (!f->callees.is_empty()) {
	 struct call_node *n = (struct call_node *) f->callees.pop_head();
	 destroy_links(& n->func->callers, f);
      }

      hash_table_remove(visitor->function_hash, key);
      visitor->progress = true;
   }
}

static void
emit_errors_unlinked(const void *key, void *data, void *closure)
{
   struct _mesa_glsl_parse_state *state =
      (struct _mesa_glsl_parse_state *) closure;
   function *f = (function *) data;
   YYLTYPE loc;

   (void) key;

   char *proto = prototype_string(f->sig->return_type,
				  f->sig->function_name(),
				  &f->sig->parameters);

   memset(&loc, 0, sizeof(loc));
   _mesa_glsl_error(&loc, state,
		    "function `%s' has static recursion.",
		    proto);
   ralloc_free(proto);
}

static void
emit_errors_linked(const void *key, void *data, void *closure)
{
   struct gl_shader_program *prog =
      (struct gl_shader_program *) closure;
   function *f = (function *) data;

   (void) key;

   char *proto = prototype_string(f->sig->return_type,
				  f->sig->function_name(),
				  &f->sig->parameters);

   linker_error(prog, "function `%s' has static recursion.\n", proto);
   ralloc_free(proto);
   prog->LinkStatus = false;
}

void
detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
			  exec_list *instructions)
{
   has_recursion_visitor v;

   /* Collect all of the information about which functions call which other
    * functions.
    */
   v.run(instructions);

   /* Remove from the set all of the functions that either have no caller or
    * call no other functions.  Repeat until no functions are removed.
    */
   do {
      v.progress = false;
      hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
   } while (v.progress);

   /* At this point any functions still in the hash must be part of a cycle.
    */
   hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state);
}

void
detect_recursion_linked(struct gl_shader_program *prog,
			exec_list *instructions)
{
   has_recursion_visitor v;

   /* Collect all of the information about which functions call which other
    * functions.
    */
   v.run(instructions);

   /* Remove from the set all of the functions that either have no caller or
    * call no other functions.  Repeat until no functions are removed.
    */
   do {
      v.progress = false;
      hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
   } while (v.progress);

   /* At this point any functions still in the hash must be part of a cycle.
    */
   hash_table_call_foreach(v.function_hash, emit_errors_linked, prog);
}
<commit_msg>glsl: fix uninitialised variable from constructor<commit_after>/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_function_detect_recursion.cpp
 * Determine whether a shader contains static recursion.
 *
 * Consider the (possibly disjoint) graph of function calls in a shader.  If a
 * program contains recursion, this graph will contain a cycle.  If a function
 * is part of a cycle, it will have a caller and it will have a callee (it
 * calls another function).
 *
 * To detect recursion, the function call graph is constructed.  The graph is
 * repeatedly reduced by removing any function that either has no callees
 * (leaf functions) or has no caller.  Eventually the only functions that
 * remain will be the functions in the cycles.
 *
 * The GLSL spec is a bit wishy-washy about recursion.
 *
 * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
 *
 *     "Behavior is undefined if recursion is used. Recursion means having any
 *     function appearing more than once at any one time in the run-time stack
 *     of function calls. That is, a function may not call itself either
 *     directly or indirectly. Compilers may give diagnostic messages when
 *     this is detectable at compile time, but not all such cases can be
 *     detected at compile time."
 *
 * From page 79 (page 85 of the PDF):
 *
 *     "22) Should recursion be supported?
 *
 *      DISCUSSION: Probably not necessary, but another example of limiting
 *      the language based on how it would directly map to hardware. One
 *      thought is that recursion would benefit ray tracing shaders. On the
 *      other hand, many recursion operations can also be implemented with the
 *      user managing the recursion through arrays. RenderMan doesn't support
 *      recursion. This could be added at a later date, if it proved to be
 *      necessary.
 *
 *      RESOLVED on September 10, 2002: Implementations are not required to
 *      support recursion.
 *
 *      CLOSED on September 10, 2002."
 *
 * From page 79 (page 85 of the PDF):
 *
 *     "56) Is it an error for an implementation to support recursion if the
 *     specification says recursion is not supported?
 *
 *     ADDED on September 10, 2002.
 *
 *     DISCUSSION: This issues is related to Issue (22). If we say that
 *     recursion (or some other piece of functionality) is not supported, is
 *     it an error for an implementation to support it? Perhaps the
 *     specification should remain silent on these kind of things so that they
 *     could be gracefully added later as an extension or as part of the
 *     standard.
 *
 *     RESOLUTION: Languages, in general, have programs that are not
 *     well-formed in ways a compiler cannot detect. Portability is only
 *     ensured for well-formed programs. Detecting recursion is an example of
 *     this. The language will say a well-formed program may not recurse, but
 *     compilers are not forced to detect that recursion may happen.
 *
 *     CLOSED: November 29, 2002."
 *
 * In GLSL 1.10 the behavior of recursion is undefined.  Compilers don't have
 * to reject shaders (at compile-time or link-time) that contain recursion.
 * Instead they could work, or crash, or kill a kitten.
 *
 * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec:
 *
 *     "Recursion is not allowed, not even statically. Static recursion is
 *     present if the static function call graph of the program contains
 *     cycles."
 *
 * This langauge clears things up a bit, but it still leaves a lot of
 * questions unanswered.
 *
 *     - Is the error generated at compile-time or link-time?
 *
 *     - Is it an error to have a recursive function that is never statically
 *       called by main or any function called directly or indirectly by main?
 *       Technically speaking, such a function is not in the "static function
 *       call graph of the program" at all.
 *
 * \bug
 * If a shader has multiple cycles, this algorithm may erroneously complain
 * about functions that aren't in any cycle, but are in the part of the call
 * tree that connects them.  For example, if the call graph consists of a
 * cycle between A and B, and a cycle between D and E, and B also calls C
 * which calls D, then this algorithm will report C as a function which "has
 * static recursion" even though it is not part of any cycle.
 *
 * A better algorithm for cycle detection that doesn't have this drawback can
 * be found here:
 *
 * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm
 *
 * \author Ian Romanick <ian.d.romanick@intel.com>
 */
#include "main/core.h"
#include "ir.h"
#include "glsl_parser_extras.h"
#include "linker.h"
#include "program/hash_table.h"
#include "program.h"

struct call_node : public exec_node {
   class function *func;
};

class function {
public:
   function(ir_function_signature *sig)
      : sig(sig)
   {
      /* empty */
   }

   /* Callers of this ralloc-based new need not call delete. It's
    * easier to just ralloc_free 'ctx' (or any of its ancestors). */
   static void* operator new(size_t size, void *ctx)
   {
      void *node;

      node = ralloc_size(ctx, size);
      assert(node != NULL);

      return node;
   }

   /* If the user *does* call delete, that's OK, we will just
    * ralloc_free in that case. */
   static void operator delete(void *node)
   {
      ralloc_free(node);
   }

   ir_function_signature *sig;

   /** List of functions called by this function. */
   exec_list callees;

   /** List of functions that call this function. */
   exec_list callers;
};

class has_recursion_visitor : public ir_hierarchical_visitor {
public:
   has_recursion_visitor()
      : current(NULL)
   {
      progress = false;
      this->mem_ctx = ralloc_context(NULL);
      this->function_hash = hash_table_ctor(0, hash_table_pointer_hash,
					    hash_table_pointer_compare);
   }

   ~has_recursion_visitor()
   {
      hash_table_dtor(this->function_hash);
      ralloc_free(this->mem_ctx);
   }

   function *get_function(ir_function_signature *sig)
   {
      function *f = (function *) hash_table_find(this->function_hash, sig);
      if (f == NULL) {
	 f = new(mem_ctx) function(sig);
	 hash_table_insert(this->function_hash, f, sig);
      }

      return f;
   }

   virtual ir_visitor_status visit_enter(ir_function_signature *sig)
   {
      this->current = this->get_function(sig);
      return visit_continue;
   }

   virtual ir_visitor_status visit_leave(ir_function_signature *sig)
   {
      (void) sig;
      this->current = NULL;
      return visit_continue;
   }

   virtual ir_visitor_status visit_enter(ir_call *call)
   {
      /* At global scope this->current will be NULL.  Since there is no way to
       * call global scope, it can never be part of a cycle.  Don't bother
       * adding calls from global scope to the graph.
       */
      if (this->current == NULL)
	 return visit_continue;

      function *const target = this->get_function(call->callee);

      /* Create a link from the caller to the callee.
       */
      call_node *node = new(mem_ctx) call_node;
      node->func = target;
      this->current->callees.push_tail(node);

      /* Create a link from the callee to the caller.
       */
      node = new(mem_ctx) call_node;
      node->func = this->current;
      target->callers.push_tail(node);
      return visit_continue;
   }

   function *current;
   struct hash_table *function_hash;
   void *mem_ctx;
   bool progress;
};

static void
destroy_links(exec_list *list, function *f)
{
   foreach_list_safe(node, list) {
      struct call_node *n = (struct call_node *) node;

      /* If this is the right function, remove it.  Note that the loop cannot
       * terminate now.  There can be multiple links to a function if it is
       * either called multiple times or calls multiple times.
       */
      if (n->func == f)
	 n->remove();
   }
}

/**
 * Remove a function if it has either no in or no out links
 */
static void
remove_unlinked_functions(const void *key, void *data, void *closure)
{
   has_recursion_visitor *visitor = (has_recursion_visitor *) closure;
   function *f = (function *) data;

   if (f->callers.is_empty() || f->callees.is_empty()) {
      while (!f->callers.is_empty()) {
	 struct call_node *n = (struct call_node *) f->callers.pop_head();
	 destroy_links(& n->func->callees, f);
      }

      while (!f->callees.is_empty()) {
	 struct call_node *n = (struct call_node *) f->callees.pop_head();
	 destroy_links(& n->func->callers, f);
      }

      hash_table_remove(visitor->function_hash, key);
      visitor->progress = true;
   }
}

static void
emit_errors_unlinked(const void *key, void *data, void *closure)
{
   struct _mesa_glsl_parse_state *state =
      (struct _mesa_glsl_parse_state *) closure;
   function *f = (function *) data;
   YYLTYPE loc;

   (void) key;

   char *proto = prototype_string(f->sig->return_type,
				  f->sig->function_name(),
				  &f->sig->parameters);

   memset(&loc, 0, sizeof(loc));
   _mesa_glsl_error(&loc, state,
		    "function `%s' has static recursion.",
		    proto);
   ralloc_free(proto);
}

static void
emit_errors_linked(const void *key, void *data, void *closure)
{
   struct gl_shader_program *prog =
      (struct gl_shader_program *) closure;
   function *f = (function *) data;

   (void) key;

   char *proto = prototype_string(f->sig->return_type,
				  f->sig->function_name(),
				  &f->sig->parameters);

   linker_error(prog, "function `%s' has static recursion.\n", proto);
   ralloc_free(proto);
   prog->LinkStatus = false;
}

void
detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
			  exec_list *instructions)
{
   has_recursion_visitor v;

   /* Collect all of the information about which functions call which other
    * functions.
    */
   v.run(instructions);

   /* Remove from the set all of the functions that either have no caller or
    * call no other functions.  Repeat until no functions are removed.
    */
   do {
      v.progress = false;
      hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
   } while (v.progress);

   /* At this point any functions still in the hash must be part of a cycle.
    */
   hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state);
}

void
detect_recursion_linked(struct gl_shader_program *prog,
			exec_list *instructions)
{
   has_recursion_visitor v;

   /* Collect all of the information about which functions call which other
    * functions.
    */
   v.run(instructions);

   /* Remove from the set all of the functions that either have no caller or
    * call no other functions.  Repeat until no functions are removed.
    */
   do {
      v.progress = false;
      hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
   } while (v.progress);

   /* At this point any functions still in the hash must be part of a cycle.
    */
   hash_table_call_foreach(v.function_hash, emit_errors_linked, prog);
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * pxgsettings - A helper binary to query gsettings
 * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
 * Copyright (C) 2011 Dominique Leuenberger <dominique@leuenberger.net>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 ******************************************************************************/

#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

using namespace std;

static GMainLoop* loop = NULL;

static int print_value(GVariant *value, const char *suffix) {

	if (!value) return 0;
	if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
		return printf("%s%s", g_variant_get_string(value, NULL), suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
		return printf("%d%s", g_variant_get_int32(value), suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
		gboolean result;
		result = g_variant_get_boolean(value);
		return printf("%s%s", result ? "true" : "false",  suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) {
		int count;
		const gchar** items;
		items = g_variant_get_strv(value, NULL);
		for (count=0; items[count]; count++) {
			printf("%s%s", count < 2 ? "" : ",",  items[count]);
		}
		printf("%s", suffix);
		return count;
	}
	else {
		throw exception();
	}

	return 0;
}

static void on_value_change(GSettings *settings, const gchar *key, gpointer user_data) {
	printf("%s/%s\t", (gchar *)user_data, key);
	print_value(g_settings_get_value(settings, key), "\n");
}

static void on_sig(int /*signal*/) {
	g_main_loop_quit(loop);
}

static gboolean err(GIOChannel* /*source*/, GIOCondition /*condition*/, gpointer /*data*/) {
	g_main_loop_quit(loop);
	return false;
}

static gboolean in(GIOChannel *source, GIOCondition condition, gpointer data) {
	gchar *key, *val;
	GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL);

	// Remove the trailing '\n'
	for (int i=0 ; key && key[i] ; i++)
		if (key[i] == '\n')
			key[i] = '\0';

	// If we were successful
	if (key && st == G_IO_STATUS_NORMAL) {
		if (!g_strrstr(key, "\t"))
			goto exit;

		val = g_strrstr(key, "\t") + 1;
		*(val-1) = '\0';

		g_free(key);
		return true;
	}
	else if (key && st == G_IO_STATUS_AGAIN) {
		g_free(key);
		return in(source, condition, data);
	}

exit:
	g_free(key);
	return err(source, condition, data);
}

int main(int argc, char **argv) {
	if (argc < 2) return 1;

	// Register sighup handler
	if (signal(SIGHUP, on_sig) == SIG_ERR || signal(SIGPIPE, on_sig) == SIG_ERR || signal(SIGABRT, on_sig) == SIG_ERR) {
		fprintf(stderr, "Unable to trap signals!");
		return 2;
	}

	// Switch stdout to line buffering
	if (setvbuf(stdout, NULL, _IOLBF, 0)) {
		fprintf(stderr, "Unable to switch stdout to line buffering!");
		return 3;
	}

	// Switch stdin to line buffering
	if (setvbuf(stdin, NULL, _IOLBF, 0)) {
		fprintf(stderr, "Unable to switch stdin to line buffering!");
		return 4;
	}

	// Init
	g_type_init();

	// Get the main loop
	loop = g_main_loop_new(NULL, false);

	// Setup our GIO Channels
	GIOChannel* inchan  = g_io_channel_unix_new(fileno(stdin));
	GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout));
	g_io_add_watch(inchan,  G_IO_IN,  in, NULL);
	g_io_add_watch(inchan,  G_IO_PRI, in, NULL);
	g_io_add_watch(inchan,  G_IO_ERR, err, NULL);
	g_io_add_watch(inchan,  G_IO_HUP, err, NULL);
	g_io_add_watch(outchan, G_IO_ERR, err, NULL);
	g_io_add_watch(outchan, G_IO_HUP, err, NULL);

	// Get GConf client
	GSettings* client;

	for (int i=1; i<argc; i++) {
		client = g_settings_new(argv[i]);
		gchar** keys = g_settings_list_keys(client);
		for (int j=0; keys[j]; on_value_change(client, keys[j++],argv[i] ));
		g_signal_connect(client, "changed::", (GCallback) on_value_change, argv[i]);
	}

	g_main_loop_run(loop);

	// Cleanup
	while (G_IS_OBJECT(client)) {
		g_object_unref(client);
	}
	g_io_channel_shutdown(inchan,  FALSE, NULL);
	g_io_channel_shutdown(outchan, FALSE, NULL);
	g_io_channel_unref(inchan);
	g_io_channel_unref(outchan);
	g_main_loop_unref(loop);
}
<commit_msg>pxgsettings: =/-1.. counting can be so hard<commit_after>/*******************************************************************************
 * pxgsettings - A helper binary to query gsettings
 * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
 * Copyright (C) 2011 Dominique Leuenberger <dominique@leuenberger.net>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 ******************************************************************************/

#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

using namespace std;

static GMainLoop* loop = NULL;

static int print_value(GVariant *value, const char *suffix) {

	if (!value) return 0;
	if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
		return printf("%s%s", g_variant_get_string(value, NULL), suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
		return printf("%d%s", g_variant_get_int32(value), suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
		gboolean result;
		result = g_variant_get_boolean(value);
		return printf("%s%s", result ? "true" : "false",  suffix);
	}
	else if(g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) {
		int count;
		const gchar** items;
		items = g_variant_get_strv(value, NULL);
		for (count=0; items[count]; count++) {
			printf("%s%s", count < 1 ? "" : ",",  items[count]);
		}
		printf("%s", suffix);
		return count;
	}
	else {
		throw exception();
	}

	return 0;
}

static void on_value_change(GSettings *settings, const gchar *key, gpointer user_data) {
	printf("%s/%s\t", (gchar *)user_data, key);
	print_value(g_settings_get_value(settings, key), "\n");
}

static void on_sig(int /*signal*/) {
	g_main_loop_quit(loop);
}

static gboolean err(GIOChannel* /*source*/, GIOCondition /*condition*/, gpointer /*data*/) {
	g_main_loop_quit(loop);
	return false;
}

static gboolean in(GIOChannel *source, GIOCondition condition, gpointer data) {
	gchar *key, *val;
	GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL);

	// Remove the trailing '\n'
	for (int i=0 ; key && key[i] ; i++)
		if (key[i] == '\n')
			key[i] = '\0';

	// If we were successful
	if (key && st == G_IO_STATUS_NORMAL) {
		if (!g_strrstr(key, "\t"))
			goto exit;

		val = g_strrstr(key, "\t") + 1;
		*(val-1) = '\0';

		g_free(key);
		return true;
	}
	else if (key && st == G_IO_STATUS_AGAIN) {
		g_free(key);
		return in(source, condition, data);
	}

exit:
	g_free(key);
	return err(source, condition, data);
}

int main(int argc, char **argv) {
	if (argc < 2) return 1;

	// Register sighup handler
	if (signal(SIGHUP, on_sig) == SIG_ERR || signal(SIGPIPE, on_sig) == SIG_ERR || signal(SIGABRT, on_sig) == SIG_ERR) {
		fprintf(stderr, "Unable to trap signals!");
		return 2;
	}

	// Switch stdout to line buffering
	if (setvbuf(stdout, NULL, _IOLBF, 0)) {
		fprintf(stderr, "Unable to switch stdout to line buffering!");
		return 3;
	}

	// Switch stdin to line buffering
	if (setvbuf(stdin, NULL, _IOLBF, 0)) {
		fprintf(stderr, "Unable to switch stdin to line buffering!");
		return 4;
	}

	// Init
	g_type_init();

	// Get the main loop
	loop = g_main_loop_new(NULL, false);

	// Setup our GIO Channels
	GIOChannel* inchan  = g_io_channel_unix_new(fileno(stdin));
	GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout));
	g_io_add_watch(inchan,  G_IO_IN,  in, NULL);
	g_io_add_watch(inchan,  G_IO_PRI, in, NULL);
	g_io_add_watch(inchan,  G_IO_ERR, err, NULL);
	g_io_add_watch(inchan,  G_IO_HUP, err, NULL);
	g_io_add_watch(outchan, G_IO_ERR, err, NULL);
	g_io_add_watch(outchan, G_IO_HUP, err, NULL);

	// Get GConf client
	GSettings* client;

	for (int i=1; i<argc; i++) {
		client = g_settings_new(argv[i]);
		gchar** keys = g_settings_list_keys(client);
		for (int j=0; keys[j]; on_value_change(client, keys[j++],argv[i] ));
		g_signal_connect(client, "changed::", (GCallback) on_value_change, argv[i]);
	}

	g_main_loop_run(loop);

	// Cleanup
	while (G_IS_OBJECT(client)) {
		g_object_unref(client);
	}
	g_io_channel_shutdown(inchan,  FALSE, NULL);
	g_io_channel_shutdown(outchan, FALSE, NULL);
	g_io_channel_unref(inchan);
	g_io_channel_unref(outchan);
	g_main_loop_unref(loop);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Kai Luo <gluokai@gmail.com>. All rights reserved.
// Use of this source code is governed by the BSD license that can be found in
// the LICENSE file.
#include <sys/time.h>

#include "logger.h"

namespace kl {
namespace logging {
const char *kLogLevelString[5] = {"INFO", "DEBUG", "WARN", "ERROR", "FATAL"};

Logger::Logger(std::function<void(const std::string &)> &&output)
    : log_level_(kInfo), output_(std::move(output)) {}

Logger::Logger(int log_level, std::function<void(const std::string &)> &&output)
    : log_level_(log_level), output_(std::move(output)) {}

std::unique_ptr<Logger>
Logger::default_logger_(new Logger([](const std::string &message) {
  std::fprintf(stderr, "%s\n", message.c_str());
}));

void Logger::Logging(int log_level, const char *file, const char *func,
                     int line, const char *fmt, ...) {
  if (log_level < log_level_) {
    return;
  }
  va_list ap;
  va_start(ap, fmt);
  Logging(log_level, file, func, line, fmt, ap);
  va_end(ap);
}

void Logger::Logging(int log_level, const char *file, const char *func,
                     int line, const char *fmt, va_list ap) {
  if (log_level < log_level_) {
    return;
  }
  // [<log_level> yy/mm/dd-hr:min:sec.usec file:func:line]
  static const char *kPrefixFormat =
      "[%s %04d/%02d/%02d-%02d:%02d:%02d.%06ld %s:%s:%d] ";
  struct timeval now;
  ::gettimeofday(&now, nullptr);
  struct tm t;
  ::localtime_r(&now.tv_sec, &t);
  int prefix_size =
      std::snprintf(nullptr, 0, kPrefixFormat, kLogLevelString[log_level],
                    t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
                    t.tm_min, t.tm_sec, now.tv_usec, file, func, line);
  va_list backup_ap;
  va_copy(backup_ap, ap);
  int msg_size = std::vsnprintf(nullptr, 0, fmt, backup_ap);
  va_end(backup_ap);

  int buf_size = prefix_size + msg_size + 1;
  char *buf = new char[buf_size];
  const char *base = buf;
  prefix_size =
      std::snprintf(buf, buf_size, kPrefixFormat, kLogLevelString[log_level],
                    t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
                    t.tm_min, t.tm_sec, now.tv_usec, file, func, line);
  buf += prefix_size;
  assert(buf_size >= prefix_size);
  std::vsnprintf(buf, buf_size - prefix_size, fmt, ap);
  output_(base);
  delete[] base;
}

Logger &Logger::DefaultLogger() {
  assert(default_logger_);
  return *default_logger_;
}

void Logger::SetDefaultLogger(Logger &&logger) {
  default_logger_ = std::make_unique<Logger>(std::move(logger));
}

void Logger::SetLogLevel(int log_level) { log_level_ = log_level; }

}  // namespace logging
}  // namespace kl
<commit_msg>minir fix<commit_after>// Copyright (c) 2017 Kai Luo <gluokai@gmail.com>. All rights reserved.
// Use of this source code is governed by the BSD license that can be found in
// the LICENSE file.
#include <sys/time.h>

#include "logger.h"

namespace kl {
namespace logging {
const char *kLogLevelString[5] = {"INFO", "DEBUG", "WARN", "ERROR", "FATAL"};

Logger::Logger(std::function<void(const std::string &)> &&output)
    : log_level_(kInfo), output_(std::move(output)) {}

Logger::Logger(int log_level, std::function<void(const std::string &)> &&output)
    : log_level_(log_level), output_(std::move(output)) {}

std::unique_ptr<Logger>
Logger::default_logger_(new Logger([](const std::string &message) {
  std::fprintf(stderr, "%s\n", message.c_str());
}));

void Logger::Logging(int log_level, const char *file, const char *func,
                     int line, const char *fmt, ...) {
  if (log_level < log_level_) {
    return;
  }
  va_list ap;
  va_start(ap, fmt);
  Logging(log_level, file, func, line, fmt, ap);
  va_end(ap);
}

void Logger::Logging(int log_level, const char *file, const char *func,
                     int line, const char *fmt, va_list ap) {
  if (log_level < log_level_) {
    return;
  }
  // [<log_level> yy/mm/dd-hr:min:sec.usec file:func:line]
  static const char *kPrefixFormat =
      "[%s %04d/%02d/%02d-%02d:%02d:%02d.%06ld %s:%s:%d] ";
  struct timeval now;
  ::gettimeofday(&now, nullptr);
  struct tm t;
  ::localtime_r(&now.tv_sec, &t);
  int prefix_size =
      std::snprintf(nullptr, 0, kPrefixFormat, kLogLevelString[log_level],
                    t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
                    t.tm_min, t.tm_sec, now.tv_usec, file, func, line);
  va_list backup_ap;
  va_copy(backup_ap, ap);
  int msg_size = std::vsnprintf(nullptr, 0, fmt, backup_ap);
  va_end(backup_ap);

  int buf_size = prefix_size + msg_size + 1;
  char *buf = new char[buf_size + 1];  // to contain '\n'
  const char *base = buf;
  prefix_size =
      std::snprintf(buf, buf_size, kPrefixFormat, kLogLevelString[log_level],
                    t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
                    t.tm_min, t.tm_sec, now.tv_usec, file, func, line);
  buf += prefix_size;
  assert(buf_size >= prefix_size);
  std::vsnprintf(buf, buf_size - prefix_size, fmt, ap);
  buf[buf_size - 1] = '\n';
  buf[buf_size] = 0;
  output_(base);
  delete[] base;
}

Logger &Logger::DefaultLogger() {
  assert(default_logger_);
  return *default_logger_;
}

void Logger::SetDefaultLogger(Logger &&logger) {
  default_logger_ = std::make_unique<Logger>(std::move(logger));
}

void Logger::SetLogLevel(int log_level) { log_level_ = log_level; }

}  // namespace logging
}  // namespace kl
<|endoftext|>


<commit_before>/*
 *  ChordNode.cpp
 *  iPhone_p2p_engine
 *
 *  Created by LogNet team 2010 - INRIA
 *  Mediteranee - Sophia Antipolis - France
 *
 */

#include "ChordNode.h"
#include "Stabilization.h"
#include "CheckPred.h"
#include "FixFinger.h"
#include "TransportHTTP.h"
#include "callbacks.h"
#include "sha1.h";
#include <sstream>
#include <iostream>
#include <assert.h>
#include <math.h>

/* Constructor */
ChordNode::ChordNode(const string &ip, int port, const string &overlayIdentifier, const string &rootDirectory) {

	// Define the address space size
	spacesize = 9;

	// Create the id
	std::ostringstream oss;
	oss << ip << port;
	int id = getSHA1(oss.str());

	// check if the idE[0, 2^(spacesize - 1)]
	assert(!(id > pow(2, spacesize)) && !(id < 0));

	//create our stabilizer threads instance.
	stableThread = new Stabilization(this);

	//Initialize the transport layer.
	transport = new TransportHTTP(port, rootDirectory);

	//set the overlay identifier.
	this->overlayIdentifier = overlayIdentifier;

	// not yet notified
	notified = false;

	//Call our parent's initializer
	initialise(ip, id, port);

	//We start-up our stabilizer thread.
	checkStable();
}

/* Destructor */
ChordNode::~ChordNode() {
	stableThread->kill();
	delete stableThread;
	delete transport;
}

/* Override from AbstractChord */
void ChordNode::notify(Node *n) {
	Node *pred = predecessor;
	((AbstractChord *) this)->notify(n);
	// If the predecessor as changed, update the DHT table
	if (pred != predecessor) {
		notified = true;
	}
}

void ChordNode::stabilize() {
	((AbstractChord *) this)->stabilize();
	// If the predecessor as changed, update the DHT table
	if (notified && predecessor->getId() != thisNode->getId()) {
		for (dataMap::iterator it = table.begin(); it != table.end(); ++it) {
			Request *request = new Request(this->getIdentifier(), PUT);
			int id = atoi(it->first.c_str());
			if (!insideRange(id, predecessor->getId(), thisNode->getId())) {
				request->addArg("key", it->first);
				request->addArg("value", it->second);
				// Send the Put request
				sendRequest(request, predecessor);
				// remove the key from my table
				table.erase(it);
			}
		}
		notified = false;
	}
}

/* DHT Put */
void ChordNode::put(string key, string value) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		stringstream ss;
		ss << table[key] << "*******";
		table[key]=ss.str();
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), PUT);
		request->addArg("key", key);
		request->addArg("value", value);
		// Send the Put request
		sendRequest(request, responsible);
	}
}

/* DHT Get */
string ChordNode::get(string key) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		dataMap::iterator it = table.find(key);
		if (it != table.end()) {
			return (it->second);
		} else {
			string err = "no result";
			return err;
		}
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), GET);
		request->addArg("key", key);
		// Send the Put request
		return sendRequest(request, responsible);
	}
}

/* DHT Remove */
void ChordNode::removekey(string key) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		dataMap::iterator it = table.find(key);
		if (it != table.end()) {
			table.erase(it);
		}
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), REMOVEKEY);
		request->addArg("key", key);
		// Send the Put request
		sendRequest(request, responsible);
	}
}

/* Convert a string to an integer (using MD5) */
unsigned int ChordNode::getSHA1(string str) {
	SHA1 *sha1 = new SHA1();
	sha1->addBytes( str.c_str(), strlen( str.c_str() ));
	unsigned char* digest = sha1->getDigest();
	unsigned int res = sha1->shaToInteger(digest, 20, pow(2, spacesize));
	delete sha1;
	free( digest );
	return res;
}

/* Forward a message to a peer, the message is in the format: "<IP+PORT>,TRANSPORT_CODE" */
string ChordNode::sendRequest(Request *request, Node* destination) {
	char *response = transport->sendRequest(request, destination);
	// response received
	if (response) {
		stringstream ss;
		ss << response;
		free(response); // we must free the initial char* response, to avoid leaks.
		return ss.str();
	} else {
		// Fix the broken pointers of the node
		fixBrokenPointers(destination);
		// time to fix the chord
		sleep(1);
		// The node is completely disconnected of the backbone
		if (isAlone()) { // there is only one response possible
			return getThisNode()->toString();
		}
		// try again the request with a new destination
		return sendRequest(request, findSuccessor(destination->getId()));
	}
}

/* Fix broken pointers algorithm */
void ChordNode::fixBrokenPointers(Node *node) {
	for (int i = 0; i < fingerTable.size() - 1; i++) {
		if (fingerTable[i]->getId() == node->getId()) {
			fingerTable[i] = new Node(thisNode->toString());
		}
	}
	if (predecessor->getId() == node->getId()) {
		predecessor = new Node(thisNode->toString());
	}
	if (successor->getId() == node->getId()) {
		successor = new Node(thisNode->toString());
	}
}

/* return true if the node is completely disconnected of the chord */
bool ChordNode::isAlone(){
	for (int i = 0; i < fingerTable.size() - 1; i++) {
		if (fingerTable[i]->getId() != thisNode->getId()){
			return false;
		}
	}
	return predecessor->getId() == thisNode->getId() && successor->getId() == thisNode->getId();
}

/* Starts up the "stabilizer thread" for this peer. */
void ChordNode::checkStable() {
	stableThread->start();
}

/* Stop the stabilization, distribute the key and shutDown the peer */
void ChordNode::shutDown() {
	// kill the stabilization Threads
	stableThread->kill();

	// notify predecessor
	Request *request = new Request(this->getIdentifier(), SETSUCC);
	request->addArg("successor", successor->toString());
	sendRequest(request, predecessor);

	// notify successor
	request = new Request(this->getIdentifier(), SETPRED);
	request->addArg("predecessor", predecessor->toString());
	sendRequest(request, successor);

	// give the part of the DHT to the successor
	for (dataMap::iterator it = table.begin(); it != table.end(); ++it) {
		request = new Request(this->getIdentifier(), PUT);
		request->addArg("key", it->first);
		request->addArg("value", it->second);
		sendRequest(request, successor);
		// remove the key from my table
		table.erase(it);
	}
	cout << "bye bye...\n";
	sleep(1);
	exit(0);
}

/* print node status */
string ChordNode::printTable() {
	stringstream ss(stringstream::in | stringstream::out);
	ss << "data:\n";
	for (dataMap::const_iterator it = table.begin(); it != table.end(); ++it) {
		ss << "\t[" << it->first << "]";
		ss << " - " << it->second << '\n';
	}
	return ss.str();
}
<commit_msg>    FIX: 	- concate...<commit_after>/*
 *  ChordNode.cpp
 *  iPhone_p2p_engine
 *
 *  Created by LogNet team 2010 - INRIA
 *  Mediteranee - Sophia Antipolis - France
 *
 */

#include "ChordNode.h"
#include "Stabilization.h"
#include "CheckPred.h"
#include "FixFinger.h"
#include "TransportHTTP.h"
#include "callbacks.h"
#include "sha1.h";
#include <sstream>
#include <iostream>
#include <assert.h>
#include <math.h>

/* Constructor */
ChordNode::ChordNode(const string &ip, int port, const string &overlayIdentifier, const string &rootDirectory) {

	// Define the address space size
	spacesize = 9;

	// Create the id
	std::ostringstream oss;
	oss << ip << port;
	int id = getSHA1(oss.str());

	// check if the idE[0, 2^(spacesize - 1)]
	assert(!(id > pow(2, spacesize)) && !(id < 0));

	//create our stabilizer threads instance.
	stableThread = new Stabilization(this);

	//Initialize the transport layer.
	transport = new TransportHTTP(port, rootDirectory);

	//set the overlay identifier.
	this->overlayIdentifier = overlayIdentifier;

	// not yet notified
	notified = false;

	//Call our parent's initializer
	initialise(ip, id, port);

	//We start-up our stabilizer thread.
	checkStable();
}

/* Destructor */
ChordNode::~ChordNode() {
	stableThread->kill();
	delete stableThread;
	delete transport;
}

/* Override from AbstractChord */
void ChordNode::notify(Node *n) {
	Node *pred = predecessor;
	((AbstractChord *) this)->notify(n);
	// If the predecessor as changed, update the DHT table
	if (pred != predecessor) {
		notified = true;
	}
}

void ChordNode::stabilize() {
	((AbstractChord *) this)->stabilize();
	// If the predecessor as changed, update the DHT table
	if (notified && predecessor->getId() != thisNode->getId()) {
		for (dataMap::iterator it = table.begin(); it != table.end(); ++it) {
			Request *request = new Request(this->getIdentifier(), PUT);
			int id = atoi(it->first.c_str());
			if (!insideRange(id, predecessor->getId(), thisNode->getId())) {
				request->addArg("key", it->first);
				request->addArg("value", it->second);
				// Send the Put request
				sendRequest(request, predecessor);
				// remove the key from my table
				table.erase(it);
			}
		}
		notified = false;
	}
}

/* DHT Put */
void ChordNode::put(string key, string value) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		stringstream ss;
		ss << table[key] << value;
		table[key]=ss.str();
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), PUT);
		request->addArg("key", key);
		request->addArg("value", value);
		// Send the Put request
		sendRequest(request, responsible);
	}
}

/* DHT Get */
string ChordNode::get(string key) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		dataMap::iterator it = table.find(key);
		if (it != table.end()) {
			return (it->second);
		} else {
			string err = "no result";
			return err;
		}
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), GET);
		request->addArg("key", key);
		// Send the Put request
		return sendRequest(request, responsible);
	}
}

/* DHT Remove */
void ChordNode::removekey(string key) {
	// Convert the key in a hash integer
	int hKey = getSHA1(key);
	if (insideRange(hKey, predecessor->getId() + 1, thisNode->getId())) {
		// I'm responsible for this key
		dataMap::iterator it = table.find(key);
		if (it != table.end()) {
			table.erase(it);
		}
	} else {
		// Find the node responsible for this key
		Node *responsible = findSuccessor(hKey);
		// Create a Put request.
		Request *request = new Request(this->getIdentifier(), REMOVEKEY);
		request->addArg("key", key);
		// Send the Put request
		sendRequest(request, responsible);
	}
}

/* Convert a string to an integer (using MD5) */
unsigned int ChordNode::getSHA1(string str) {
	SHA1 *sha1 = new SHA1();
	sha1->addBytes( str.c_str(), strlen( str.c_str() ));
	unsigned char* digest = sha1->getDigest();
	unsigned int res = sha1->shaToInteger(digest, 20, pow(2, spacesize));
	delete sha1;
	free( digest );
	return res;
}

/* Forward a message to a peer, the message is in the format: "<IP+PORT>,TRANSPORT_CODE" */
string ChordNode::sendRequest(Request *request, Node* destination) {
	char *response = transport->sendRequest(request, destination);
	// response received
	if (response) {
		stringstream ss;
		ss << response;
		free(response); // we must free the initial char* response, to avoid leaks.
		return ss.str();
	} else {
		// Fix the broken pointers of the node
		fixBrokenPointers(destination);
		// time to fix the chord
		sleep(1);
		// The node is completely disconnected of the backbone
		if (isAlone()) { // there is only one response possible
			return getThisNode()->toString();
		}
		// try again the request with a new destination
		return sendRequest(request, findSuccessor(destination->getId()));
	}
}

/* Fix broken pointers algorithm */
void ChordNode::fixBrokenPointers(Node *node) {
	for (int i = 0; i < fingerTable.size() - 1; i++) {
		if (fingerTable[i]->getId() == node->getId()) {
			fingerTable[i] = new Node(thisNode->toString());
		}
	}
	if (predecessor->getId() == node->getId()) {
		predecessor = new Node(thisNode->toString());
	}
	if (successor->getId() == node->getId()) {
		successor = new Node(thisNode->toString());
	}
}

/* return true if the node is completely disconnected of the chord */
bool ChordNode::isAlone(){
	for (int i = 0; i < fingerTable.size() - 1; i++) {
		if (fingerTable[i]->getId() != thisNode->getId()){
			return false;
		}
	}
	return predecessor->getId() == thisNode->getId() && successor->getId() == thisNode->getId();
}

/* Starts up the "stabilizer thread" for this peer. */
void ChordNode::checkStable() {
	stableThread->start();
}

/* Stop the stabilization, distribute the key and shutDown the peer */
void ChordNode::shutDown() {
	// kill the stabilization Threads
	stableThread->kill();

	// notify predecessor
	Request *request = new Request(this->getIdentifier(), SETSUCC);
	request->addArg("successor", successor->toString());
	sendRequest(request, predecessor);

	// notify successor
	request = new Request(this->getIdentifier(), SETPRED);
	request->addArg("predecessor", predecessor->toString());
	sendRequest(request, successor);

	// give the part of the DHT to the successor
	for (dataMap::iterator it = table.begin(); it != table.end(); ++it) {
		request = new Request(this->getIdentifier(), PUT);
		request->addArg("key", it->first);
		request->addArg("value", it->second);
		sendRequest(request, successor);
		// remove the key from my table
		table.erase(it);
	}
	cout << "bye bye...\n";
	sleep(1);
	exit(0);
}

/* print node status */
string ChordNode::printTable() {
	stringstream ss(stringstream::in | stringstream::out);
	ss << "data:\n";
	for (dataMap::const_iterator it = table.begin(); it != table.end(); ++it) {
		ss << "\t[" << it->first << "]";
		ss << " - " << it->second << '\n';
	}
	return ss.str();
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/atom_download_manager_delegate.h"

#include <string>
#include <vector>

#include "atom/browser/native_window.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "vendor/brightray/browser/inspectable_web_contents.h"

namespace atom {

namespace {

const DownloadPathReservationTracker::FilenameConflictAction
    kDefaultPlatformConflictAction = DownloadPathReservationTracker::UNIQUIFY;

}  // namespace

AtomDownloadManagerDelegate::AtomDownloadManagerDelegate(
    content::DownloadManager* manager)
    : download_manager_(manager),
      weak_ptr_factory_(this) {}

AtomDownloadManagerDelegate::~AtomDownloadManagerDelegate() {
  if (download_manager_) {
    DCHECK_EQ(static_cast<content::DownloadManagerDelegate*>(this),
              download_manager_->GetDelegate());
    download_manager_->SetDelegate(nullptr);
    download_manager_ = nullptr;
  }
}

void AtomDownloadManagerDelegate::GetItemSavePath(content::DownloadItem* item,
                                                  base::FilePath* path) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download = api::DownloadItem::FromWrappedClass(isolate,
                                                                    item);
  if (download && !download->GetSavePath().empty())
    *path = download->GetSavePath();
}

bool AtomDownloadManagerDelegate::GetItemExtension(
    content::DownloadItem* item,
    base::FilePath::StringType* extension) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download = api::DownloadItem::FromWrappedClass(isolate,
                                                                    item);
  if (download && !download->GetMimeType().empty())
      return net::GetPreferredExtensionForMimeType(
            download->GetMimeType(), extension);
  return false;
}

void AtomDownloadManagerDelegate:: OnDownloadItemSelected(
    const content::DownloadTargetCallback& callback,
    api::DownloadItem* download_item,
    const std::vector<base::FilePath>& paths) {
  DCHECK(!paths.empty());
  // Remember the last selected download directory.
  Profile* profile = static_cast<Profile*>(
      download_manager_->GetBrowserContext());
  profile->GetPrefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
                                   paths[0].DirName());
  if (download_item)
    download_item->SetSavePath(paths[0]);

  callback.Run(paths[0],
               content::DownloadItem::TARGET_DISPOSITION_PROMPT,
               content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, paths[0],
               content::DOWNLOAD_INTERRUPT_REASON_NONE);
}

void AtomDownloadManagerDelegate::OnDownloadItemSelectionCancelled(
    const content::DownloadTargetCallback& callback,
    content::DownloadItem* item) {
  item->Remove();
  base::FilePath path;
  callback.Run(path,
               content::DownloadItem::TARGET_DISPOSITION_PROMPT,
               content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
               content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
}

void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
    int32_t download_id,
    const content::DownloadTargetCallback& callback,
    PathValidationResult result,
    const base::FilePath& target_path) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  auto item = download_manager_->GetDownload(download_id);
  if (!item)
    return;

  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass(
      isolate, item);

  if (!download_item)
    download_item = atom::api::DownloadItem::Create(isolate, item).get();

  base::FilePath path;
  if (result == PathValidationResult::SUCCESS &&
      !download_item->ShouldPrompt()) {
    path = target_path;
  }

  NativeWindow* window = nullptr;
  content::WebContents* web_contents = item->GetWebContents();
  auto relay = web_contents ? NativeWindowRelay::FromWebContents(web_contents)
                            : nullptr;
  if (relay)
    window = relay->window.get();

  GetItemSavePath(item, &path);

  // Show save dialog if save path was not set already on item
  ui::SelectFileDialog::FileTypeInfo file_type_info;
  if (path.empty()) {
    std::vector<base::FilePath::StringType> extensions;
    base::FilePath::StringType extension;
    if (GetItemExtension(item, &extension)) {
      extensions.push_back(extension);
      file_type_info.extensions.push_back(extensions);
    }
    file_type_info.include_all_files = true;
    new extensions::FileEntryPicker(
      window->inspectable_web_contents()->GetWebContents(),
      target_path,
      file_type_info,
      ui::SelectFileDialog::SELECT_SAVEAS_FILE,
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadItemSelected,
                 base::Unretained(this), callback, download_item),
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadItemSelectionCancelled,
                 base::Unretained(this), callback, item));
  } else {
    if (download_item)
      download_item->SetSavePath(path);

    callback.Run(path,
                 content::DownloadItem::TARGET_DISPOSITION_PROMPT,
                 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
                 content::DOWNLOAD_INTERRUPT_REASON_NONE);
  }
}

void AtomDownloadManagerDelegate::Shutdown() {
  weak_ptr_factory_.InvalidateWeakPtrs();
  download_manager_ = nullptr;
}

bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
    content::DownloadItem* download,
    const content::DownloadTargetCallback& callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  Profile* browser_context = static_cast<Profile*>(
      download_manager_->GetBrowserContext());
  base::FilePath default_download_path(browser_context->GetPrefs()->GetFilePath(
      prefs::kDownloadDefaultDirectory));

  DownloadPathReservationTracker::FilenameConflictAction conflict_action =
      DownloadPathReservationTracker::OVERWRITE;
  base::FilePath virtual_path = download->GetForcedFilePath();

  if (virtual_path.empty()) {
    std::string suggested_filename(download->GetSuggestedFilename());
    if (suggested_filename.empty() &&
        download->GetMimeType() == "application/x-x509-user-cert") {
      suggested_filename = "user.crt";
    }

    base::FilePath generated_filename = net::GenerateFileName(
        download->GetURL(),
        download->GetContentDisposition(),
        std::string(),
        suggested_filename,
        download->GetMimeType(),
        std::string());

    conflict_action = kDefaultPlatformConflictAction;
    virtual_path = default_download_path.Append(generated_filename);
  }

  DownloadPathReservationTracker::GetReservedPath(
      download,
      virtual_path,
      default_download_path,
      true,
      conflict_action,
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
                 weak_ptr_factory_.GetWeakPtr(),
                 download->GetId(),
                 callback));
  return true;
}

bool AtomDownloadManagerDelegate::ShouldOpenDownload(
    content::DownloadItem* download,
    const content::DownloadOpenDelayedCallback& callback) {
  return true;
}

void AtomDownloadManagerDelegate::GetNextId(
    const content::DownloadIdCallback& callback) {
  static uint32_t next_id = content::DownloadItem::kInvalidId + 1;
  callback.Run(next_id++);
}

}  // namespace atom
<commit_msg>Obtain extension from path when no mime type available fix https://github.com/brave/browser-laptop/issues/13230 fix https://github.com/brave/browser-laptop/issues/13228<commit_after>// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/atom_download_manager_delegate.h"

#include <string>
#include <vector>

#include "atom/browser/native_window.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "vendor/brightray/browser/inspectable_web_contents.h"

namespace atom {

namespace {

const DownloadPathReservationTracker::FilenameConflictAction
    kDefaultPlatformConflictAction = DownloadPathReservationTracker::UNIQUIFY;

}  // namespace

AtomDownloadManagerDelegate::AtomDownloadManagerDelegate(
    content::DownloadManager* manager)
    : download_manager_(manager),
      weak_ptr_factory_(this) {}

AtomDownloadManagerDelegate::~AtomDownloadManagerDelegate() {
  if (download_manager_) {
    DCHECK_EQ(static_cast<content::DownloadManagerDelegate*>(this),
              download_manager_->GetDelegate());
    download_manager_->SetDelegate(nullptr);
    download_manager_ = nullptr;
  }
}

void AtomDownloadManagerDelegate::GetItemSavePath(content::DownloadItem* item,
                                                  base::FilePath* path) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download = api::DownloadItem::FromWrappedClass(isolate,
                                                                    item);
  if (download && !download->GetSavePath().empty())
    *path = download->GetSavePath();
}

bool AtomDownloadManagerDelegate::GetItemExtension(
    content::DownloadItem* item,
    base::FilePath::StringType* extension) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download = api::DownloadItem::FromWrappedClass(isolate,
                                                                    item);
  if (download && !download->GetMimeType().empty())
      return net::GetPreferredExtensionForMimeType(
            download->GetMimeType(), extension);
  return false;
}

void AtomDownloadManagerDelegate:: OnDownloadItemSelected(
    const content::DownloadTargetCallback& callback,
    api::DownloadItem* download_item,
    const std::vector<base::FilePath>& paths) {
  DCHECK(!paths.empty());
  // Remember the last selected download directory.
  Profile* profile = static_cast<Profile*>(
      download_manager_->GetBrowserContext());
  profile->GetPrefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
                                   paths[0].DirName());
  if (download_item)
    download_item->SetSavePath(paths[0]);

  callback.Run(paths[0],
               content::DownloadItem::TARGET_DISPOSITION_PROMPT,
               content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, paths[0],
               content::DOWNLOAD_INTERRUPT_REASON_NONE);
}

void AtomDownloadManagerDelegate::OnDownloadItemSelectionCancelled(
    const content::DownloadTargetCallback& callback,
    content::DownloadItem* item) {
  item->Remove();
  base::FilePath path;
  callback.Run(path,
               content::DownloadItem::TARGET_DISPOSITION_PROMPT,
               content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
               content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
}

void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
    int32_t download_id,
    const content::DownloadTargetCallback& callback,
    PathValidationResult result,
    const base::FilePath& target_path) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  auto item = download_manager_->GetDownload(download_id);
  if (!item)
    return;

  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::Locker locker(isolate);
  v8::HandleScope handle_scope(isolate);
  api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass(
      isolate, item);

  if (!download_item)
    download_item = atom::api::DownloadItem::Create(isolate, item).get();

  base::FilePath path;
  if (result == PathValidationResult::SUCCESS &&
      !download_item->ShouldPrompt()) {
    path = target_path;
  }

  NativeWindow* window = nullptr;
  content::WebContents* web_contents = item->GetWebContents();
  auto relay = web_contents ? NativeWindowRelay::FromWebContents(web_contents)
                            : nullptr;
  if (relay)
    window = relay->window.get();

  GetItemSavePath(item, &path);

  // Show save dialog if save path was not set already on item
  ui::SelectFileDialog::FileTypeInfo file_type_info;
  if (path.empty()) {
    std::vector<base::FilePath::StringType> extensions;
    base::FilePath::StringType extension;
    if (!GetItemExtension(item, &extension)) {
      extension = target_path.Extension();
      if (!extension.empty())
        extension.erase(extension.begin());  // Erase preceding '.'.
    }
    if (!extension.empty()) {
      extensions.push_back(extension);
      file_type_info.extensions.push_back(extensions);
    }
    file_type_info.include_all_files = true;
    new extensions::FileEntryPicker(
      window->inspectable_web_contents()->GetWebContents(),
      target_path,
      file_type_info,
      ui::SelectFileDialog::SELECT_SAVEAS_FILE,
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadItemSelected,
                 base::Unretained(this), callback, download_item),
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadItemSelectionCancelled,
                 base::Unretained(this), callback, item));
  } else {
    if (download_item)
      download_item->SetSavePath(path);

    callback.Run(path,
                 content::DownloadItem::TARGET_DISPOSITION_PROMPT,
                 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
                 content::DOWNLOAD_INTERRUPT_REASON_NONE);
  }
}

void AtomDownloadManagerDelegate::Shutdown() {
  weak_ptr_factory_.InvalidateWeakPtrs();
  download_manager_ = nullptr;
}

bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
    content::DownloadItem* download,
    const content::DownloadTargetCallback& callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  Profile* browser_context = static_cast<Profile*>(
      download_manager_->GetBrowserContext());
  base::FilePath default_download_path(browser_context->GetPrefs()->GetFilePath(
      prefs::kDownloadDefaultDirectory));

  DownloadPathReservationTracker::FilenameConflictAction conflict_action =
      DownloadPathReservationTracker::OVERWRITE;
  base::FilePath virtual_path = download->GetForcedFilePath();

  if (virtual_path.empty()) {
    std::string suggested_filename(download->GetSuggestedFilename());
    if (suggested_filename.empty() &&
        download->GetMimeType() == "application/x-x509-user-cert") {
      suggested_filename = "user.crt";
    }

    base::FilePath generated_filename = net::GenerateFileName(
        download->GetURL(),
        download->GetContentDisposition(),
        std::string(),
        suggested_filename,
        download->GetMimeType(),
        std::string());

    conflict_action = kDefaultPlatformConflictAction;
    virtual_path = default_download_path.Append(generated_filename);
  }

  DownloadPathReservationTracker::GetReservedPath(
      download,
      virtual_path,
      default_download_path,
      true,
      conflict_action,
      base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
                 weak_ptr_factory_.GetWeakPtr(),
                 download->GetId(),
                 callback));
  return true;
}

bool AtomDownloadManagerDelegate::ShouldOpenDownload(
    content::DownloadItem* download,
    const content::DownloadOpenDelayedCallback& callback) {
  return true;
}

void AtomDownloadManagerDelegate::GetNextId(
    const content::DownloadIdCallback& callback) {
  static uint32_t next_id = content::DownloadItem::kInvalidId + 1;
  callback.Run(next_id++);
}

}  // namespace atom
<|endoftext|>


<commit_before>#include "Visualization.hpp"
#include <iostream>
using namespace SIPL;

int Visualization::windowCounter = 0;

Visualization::Visualization(BaseDataset * image) {
    if(images.size() == 3)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    images.push_back(image);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

Visualization::Visualization(BaseDataset * image, BaseDataset * image2) {

    // Check that both are either image or volume
    if(!(image->isVolume == image2->isVolume))
        throw SIPLException("A visualization can only contain images or volumes, not both.");
    if(image->isVectorType && image2->isVectorType)
        throw SIPLException("A visualization can not contain more than one vector image/volume.");
    if(images.size() > 1)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    if(!(image->getSize() == image2->getSize()))
        throw SIPLException("Images/volumes must be of same size to be visualized together.");

    images.push_back(image);
    images.push_back(image2);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

Visualization::Visualization(BaseDataset * image, BaseDataset * image2, BaseDataset * image3) {

    // Check that both are either image or volume
    if(!(image->isVolume == image2->isVolume && image->isVolume == image3->isVolume))
        throw SIPLException("A visualization can only contain images or volumes, not both.");
    if(image->isVectorType && image2->isVectorType && image3->isVectorType)
        throw SIPLException("A visualization can not contain more than one vector image/volume.");
    if(images.size() > 0)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    if(!(image->getSize() == image2->getSize() && image->getSize() == image3->getSize()))
        throw SIPLException("Images/volumes must be of same size to be visualized together.");

    images.push_back(image);
    images.push_back(image2);
    images.push_back(image3);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

uchar levelWindow(float value, float level, float window) {
    float result;
    if(value < level-window*0.5f) {
        result = 0.0f;
    } else if(value > level+window*0.5f) {
        result = 1.0f;
    } else {
        result = (float)(value-(level-window*0.5f)) / window;
    }
    result = SIPL::round(result*255);
    return result;
}

void Visualization::renderSlice(int imageNr, GdkPixbuf * pixBuf) {
    int3 size = images[0]->getSize();
    int xSize = this->width;
    int ySize = this->height;

    guchar * pixels = gdk_pixbuf_get_pixels(pixBuf);
    int n =  gdk_pixbuf_get_n_channels(pixBuf);
    int rowstride = gdk_pixbuf_get_rowstride(pixBuf);
    float * floatData = images[imageNr]->getFloatData();
    for(int y = 0; y < ySize; y++) {
    for(int x = 0; x < xSize; x++) {
        float intensity;
        switch(direction) {
            case X:
                intensity = floatData[slice + x*size.x + (ySize-1-y)*size.x*size.y];
                break;
            case Y:
                intensity = floatData[x + slice*size.x + (ySize-1-y)*size.x*size.y];
                break;
            case Z:
                intensity = floatData[x + y*size.x + slice*size.x*size.y];
                break;
        }
        int i = x*n+y*rowstride;
        guchar * p = pixels + i;
        if(images.size() == 1) {
            p[0] = levelWindow(intensity, level[images[imageNr]], window[images[imageNr]]);
            p[1] = p[0];
            p[2] = p[0];
        } else {
            p[imageNr] = levelWindow(intensity, level[images[imageNr]], window[images[imageNr]]);
        }
   }}
   delete[] floatData;
}

void Visualization::renderImage(int imageNr, GdkPixbuf * pixBuf) {
    guchar * pixels = gdk_pixbuf_get_pixels(pixBuf);
    int n =  gdk_pixbuf_get_n_channels(pixBuf);

    float * floatData = images[imageNr]->getFloatData();
    for(int i = 0; i < images[imageNr]->getTotalSize(); i++) {
        guchar * p = pixels + i * n;
        if(images.size() == 1) {
            p[0] = levelWindow(floatData[i], level[images[imageNr]], window[images[imageNr]]);
            p[1] = p[0];
            p[2] = p[0];
        } else {
            p[imageNr] = levelWindow(floatData[i], level[images[imageNr]], window[images[imageNr]]);
        }
    }
    delete[] floatData;
}

GdkPixbuf * Visualization::render() {
    int3 size = images[0]->getSize();
    int xSize = 0;
    int ySize = 0;
    if(isVolumeVisualization) {
        switch(direction) {
            case X:
                // x direction
                xSize = size.y;
                ySize = size.z;
                break;
            case Y:
                // y direction
                xSize = size.x;
                ySize = size.z;
                break;
            case Z:
                // z direction
                xSize = size.x;
                ySize = size.y;
                break;
        }
    } else {
        xSize = size.x;
        ySize = size.y;
    }
    this->width = xSize;
    this->height = ySize;

    gtkImage = gtk_image_new_from_pixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB, false,
			8, xSize,ySize));

    GdkPixbuf * pixBuf = gtk_image_get_pixbuf((GtkImage *) gtkImage);
    for(int i = 0; i < images.size(); i++) {
        if(isVolumeVisualization) {
            renderSlice(i, pixBuf);
        } else {
            renderImage(i, pixBuf);
        }
    }
    return pixBuf;
}

void SIPL::Visualization::setLevel(float level) {
    for(int i = 0; i < images.size(); i++) {
        setLevel(images[i], level);
    }
}

void SIPL::Visualization::setWindow(float window) {
    for(int i = 0; i < images.size(); i++) {
        setWindow(images[i], window);
    }
}

void SIPL::Visualization::setLevel(BaseDataset* image, float level) {
    this->level[image] = level;
}

void SIPL::Visualization::setWindow(BaseDataset* image, float window) {
    this->window[image] = window;
}

void SIPL::Visualization::setTitle(std::string title) {
    this->title = title;
}

void Visualization::display() {
    // For all images, get float data and then visualize it using window and level
    // Create image widget and fill up the pixbuf
    int3 size = images[0]->getSize();
    gdk_threads_enter();

    GdkPixbuf * pixBuf = render();

    // Create GUI
	GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	Visualization::windowCounter++;
	if(title == "") {
        char * title = new char[20];
        sprintf(title, "Visualization #%d", Visualization::windowCounter);
        gtk_window_set_title(GTK_WINDOW(window), title);
	} else {
	    gtk_window_set_title(GTK_WINDOW(window), this->title.c_str());
	}
	GtkWidget * toolbar = gtk_toolbar_new();
	gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Save",               /* button label */
             "Save this image",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC(saveDialog), /* a signal */
             gtk_image_new_from_pixbuf(pixBuf));
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Close",               /* button label */
             "Close this image",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC (signalDestroyWindow), /* a signal */
             window);
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Close program",               /* button label */
             "Close this program",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC (quitProgram), /* a signal */
             NULL);

	gtk_window_set_default_size(
			GTK_WINDOW(window),
			size.x,
			size.y + 35
	);
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
	g_signal_connect_swapped(
			G_OBJECT(window),
			"destroy",
			G_CALLBACK(destroyWindow),
			NULL
	);
    g_signal_connect(
            G_OBJECT(window),
            "key_press_event",
            G_CALLBACK(Visualization::keyPressed),
            this
    );

    GtkWidget * vbox = gtk_vbox_new(FALSE, 1);

	gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), toolbar,FALSE,FALSE,0);
    scaledImage = gtk_image_new_from_pixbuf(pixBuf);
    GtkWidget *  scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledWindow),
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *)scrolledWindow, scaledImage);
    gtk_box_pack_start(GTK_BOX(vbox), scrolledWindow,TRUE,TRUE,0);
	gtk_widget_show_all(window);

	gdk_threads_leave();
}

void Visualization::keyPressed(GtkWidget * widget, GdkEventKey * event, gpointer user_data) {
    Visualization * v = (Visualization *)user_data;
    switch(event->keyval) {
        case GDK_KEY_plus:
        case GDK_KEY_KP_Add:
            v->zoomIn();
            return;
            break;
        case GDK_KEY_minus:
        case GDK_KEY_KP_Subtract:
            v->zoomOut();
            return;
            break;

    }

    /*
    if(v->isVolumeVisualization) {
        switch(event->keyval) {
            case GDK_KEY_Up:
                this->currentSlice = validateSlice(this->currentSlice+1,this->currentDirection,volume->getSize());
                break;
            case GDK_KEY_Down:
                this->currentSlice = validateSlice(this->currentSlice-1,this->currentDirection,volume->getSize());
                break;
        }

    }
    */
}

void Visualization::draw() {
    GdkPixbuf * pixBuf = gtk_image_get_pixbuf(GTK_IMAGE(gtkImage));
    GdkPixbuf * newPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false,
			8, scale*width, scale*height);
    gdk_pixbuf_scale(pixBuf, newPixBuf, 0, 0, scale*width, scale*height, 0, 0, scale, scale, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(scaledImage), newPixBuf);
    gtk_widget_queue_draw(scaledImage);
}

void Visualization::zoomIn() {
    // TODO: check if image is actually displayed
    scale = scale*2;
    this->draw();
}

void Visualization::zoomOut() {
    // TODO: check if image is actually displayed
    scale = scale*0.5f;
    this->draw();
}
<commit_msg>added update function<commit_after>#include "Visualization.hpp"
#include <iostream>
using namespace SIPL;

int Visualization::windowCounter = 0;

Visualization::Visualization(BaseDataset * image) {
    if(images.size() == 3)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    images.push_back(image);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

Visualization::Visualization(BaseDataset * image, BaseDataset * image2) {

    // Check that both are either image or volume
    if(!(image->isVolume == image2->isVolume))
        throw SIPLException("A visualization can only contain images or volumes, not both.");
    if(image->isVectorType && image2->isVectorType)
        throw SIPLException("A visualization can not contain more than one vector image/volume.");
    if(images.size() > 1)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    if(!(image->getSize() == image2->getSize()))
        throw SIPLException("Images/volumes must be of same size to be visualized together.");

    images.push_back(image);
    images.push_back(image2);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

Visualization::Visualization(BaseDataset * image, BaseDataset * image2, BaseDataset * image3) {

    // Check that both are either image or volume
    if(!(image->isVolume == image2->isVolume && image->isVolume == image3->isVolume))
        throw SIPLException("A visualization can only contain images or volumes, not both.");
    if(image->isVectorType && image2->isVectorType && image3->isVectorType)
        throw SIPLException("A visualization can not contain more than one vector image/volume.");
    if(images.size() > 0)
        throw SIPLException("A visualization can only contain a maximum of 3 images/volumes.");
    if(!(image->getSize() == image2->getSize() && image->getSize() == image3->getSize()))
        throw SIPLException("Images/volumes must be of same size to be visualized together.");

    images.push_back(image);
    images.push_back(image2);
    images.push_back(image3);
    setLevel(0.5);
    setWindow(1.0);
    scale = 1.0f;
    isVolumeVisualization = image->isVolume;
    if(isVolumeVisualization) {
        direction = Z;
        slice = image->getSize().z / 2;
    }
}

uchar levelWindow(float value, float level, float window) {
    float result;
    if(value < level-window*0.5f) {
        result = 0.0f;
    } else if(value > level+window*0.5f) {
        result = 1.0f;
    } else {
        result = (float)(value-(level-window*0.5f)) / window;
    }
    result = SIPL::round(result*255);
    return result;
}

void Visualization::renderSlice(int imageNr, GdkPixbuf * pixBuf) {
    int3 size = images[0]->getSize();
    int xSize = this->width;
    int ySize = this->height;

    guchar * pixels = gdk_pixbuf_get_pixels(pixBuf);
    int n =  gdk_pixbuf_get_n_channels(pixBuf);
    int rowstride = gdk_pixbuf_get_rowstride(pixBuf);
    float * floatData = images[imageNr]->getFloatData();
    for(int y = 0; y < ySize; y++) {
    for(int x = 0; x < xSize; x++) {
        float intensity;
        switch(direction) {
            case X:
                intensity = floatData[slice + x*size.x + (ySize-1-y)*size.x*size.y];
                break;
            case Y:
                intensity = floatData[x + slice*size.x + (ySize-1-y)*size.x*size.y];
                break;
            case Z:
                intensity = floatData[x + y*size.x + slice*size.x*size.y];
                break;
        }
        int i = x*n+y*rowstride;
        guchar * p = pixels + i;
        if(images.size() == 1) {
            p[0] = levelWindow(intensity, level[images[imageNr]], window[images[imageNr]]);
            p[1] = p[0];
            p[2] = p[0];
        } else {
            p[imageNr] = levelWindow(intensity, level[images[imageNr]], window[images[imageNr]]);
        }
   }}
   delete[] floatData;
}

void Visualization::renderImage(int imageNr, GdkPixbuf * pixBuf) {
    guchar * pixels = gdk_pixbuf_get_pixels(pixBuf);
    int n =  gdk_pixbuf_get_n_channels(pixBuf);

    float * floatData = images[imageNr]->getFloatData();
    for(int i = 0; i < images[imageNr]->getTotalSize(); i++) {
        guchar * p = pixels + i * n;
        if(images.size() == 1) {
            p[0] = levelWindow(floatData[i], level[images[imageNr]], window[images[imageNr]]);
            p[1] = p[0];
            p[2] = p[0];
        } else {
            p[imageNr] = levelWindow(floatData[i], level[images[imageNr]], window[images[imageNr]]);
        }
    }
    delete[] floatData;
}

GdkPixbuf * Visualization::render() {
    int3 size = images[0]->getSize();
    int xSize = 0;
    int ySize = 0;
    if(isVolumeVisualization) {
        switch(direction) {
            case X:
                // x direction
                xSize = size.y;
                ySize = size.z;
                break;
            case Y:
                // y direction
                xSize = size.x;
                ySize = size.z;
                break;
            case Z:
                // z direction
                xSize = size.x;
                ySize = size.y;
                break;
        }
    } else {
        xSize = size.x;
        ySize = size.y;
    }
    this->width = xSize;
    this->height = ySize;

    gtkImage = gtk_image_new_from_pixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB, false,
			8, xSize,ySize));

    GdkPixbuf * pixBuf = gtk_image_get_pixbuf((GtkImage *) gtkImage);
    for(int i = 0; i < images.size(); i++) {
        if(isVolumeVisualization) {
            renderSlice(i, pixBuf);
        } else {
            renderImage(i, pixBuf);
        }
    }
    return pixBuf;
}

void SIPL::Visualization::setLevel(float level) {
    for(int i = 0; i < images.size(); i++) {
        setLevel(images[i], level);
    }
}

void SIPL::Visualization::setWindow(float window) {
    for(int i = 0; i < images.size(); i++) {
        setWindow(images[i], window);
    }
}

void SIPL::Visualization::setLevel(BaseDataset* image, float level) {
    this->level[image] = level;
}

void SIPL::Visualization::setWindow(BaseDataset* image, float window) {
    this->window[image] = window;
}

void SIPL::Visualization::setTitle(std::string title) {
    this->title = title;
}

void Visualization::display() {
    // For all images, get float data and then visualize it using window and level
    // Create image widget and fill up the pixbuf
    int3 size = images[0]->getSize();
    gdk_threads_enter();

    GdkPixbuf * pixBuf = render();

    // Create GUI
	GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	Visualization::windowCounter++;
	if(title == "") {
        char * title = new char[20];
        sprintf(title, "Visualization #%d", Visualization::windowCounter);
        gtk_window_set_title(GTK_WINDOW(window), title);
	} else {
	    gtk_window_set_title(GTK_WINDOW(window), this->title.c_str());
	}
	GtkWidget * toolbar = gtk_toolbar_new();
	gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Save",               /* button label */
             "Save this image",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC(saveDialog), /* a signal */
             gtk_image_new_from_pixbuf(pixBuf));
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Close",               /* button label */
             "Close this image",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC (signalDestroyWindow), /* a signal */
             window);
	gtk_toolbar_append_item (
			 GTK_TOOLBAR (toolbar), /* our toolbar */
             "Close program",               /* button label */
             "Close this program",     /* this button's tooltip */
             NULL,             /* tooltip private info */
             NULL,                 /* icon widget */
             GTK_SIGNAL_FUNC (quitProgram), /* a signal */
             NULL);

	gtk_window_set_default_size(
			GTK_WINDOW(window),
			size.x,
			size.y + 35
	);
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
	g_signal_connect_swapped(
			G_OBJECT(window),
			"destroy",
			G_CALLBACK(destroyWindow),
			NULL
	);
    g_signal_connect(
            G_OBJECT(window),
            "key_press_event",
            G_CALLBACK(Visualization::keyPressed),
            this
    );

    GtkWidget * vbox = gtk_vbox_new(FALSE, 1);

	gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), toolbar,FALSE,FALSE,0);
    scaledImage = gtk_image_new_from_pixbuf(pixBuf);
    GtkWidget *  scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledWindow),
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *)scrolledWindow, scaledImage);
    gtk_box_pack_start(GTK_BOX(vbox), scrolledWindow,TRUE,TRUE,0);
	gtk_widget_show_all(window);

	gdk_threads_leave();
}

void Visualization::keyPressed(GtkWidget * widget, GdkEventKey * event, gpointer user_data) {
    Visualization * v = (Visualization *)user_data;
    switch(event->keyval) {
        case GDK_KEY_plus:
        case GDK_KEY_KP_Add:
            v->zoomIn();
            return;
            break;
        case GDK_KEY_minus:
        case GDK_KEY_KP_Subtract:
            v->zoomOut();
            return;
            break;

    }

    /*
    if(v->isVolumeVisualization) {
        switch(event->keyval) {
            case GDK_KEY_Up:
                this->currentSlice = validateSlice(this->currentSlice+1,this->currentDirection,volume->getSize());
                break;
            case GDK_KEY_Down:
                this->currentSlice = validateSlice(this->currentSlice-1,this->currentDirection,volume->getSize());
                break;
        }

    }
    */
}

void Visualization::draw() {
    GdkPixbuf * pixBuf = gtk_image_get_pixbuf(GTK_IMAGE(gtkImage));
    GdkPixbuf * newPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false,
			8, scale*width, scale*height);
    gdk_pixbuf_scale(pixBuf, newPixBuf, 0, 0, scale*width, scale*height, 0, 0, scale, scale, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(scaledImage), newPixBuf);
    gtk_widget_queue_draw(scaledImage);
}

void Visualization::zoomIn() {
    // TODO: check if image is actually displayed
    scale = scale*2;
    this->draw();
}

void Visualization::zoomOut() {
    // TODO: check if image is actually displayed
    scale = scale*0.5f;
    this->draw();
}

void Visualization::update() {
    GdkPixbuf * pixBuf = render();
    gtk_image_set_from_pixbuf(GTK_IMAGE(gtkImage), pixBuf);
    draw();
}
<|endoftext|>