<commit_before>/*************************************************************************
 *
 *  $RCSfile: protocolhandlercache.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 14:10:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_
#define __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_

/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
               with solaris headers ...
*/
#include <hash_map>
#include <vector>

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#include <general.h>
#include <stdtypes.h>
#include <macros/debug.hxx>

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_UTIL_URL_HPP_
#include <com/sun/star/util/URL.hpp>
#endif

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

#include <unotools/configitem.hxx>
#include <rtl/ustring.hxx>

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  exported const
//_________________________________________________________________________________________________________________

#define PACKAGENAME_PROTOCOLHANDLER                 DECLARE_ASCII("Office.ProtocolHandler"                          )   /// name of our configuration package

#define CFG_PATH_SEPERATOR                          DECLARE_ASCII("/"                                               )   /// seperator for configuration pathes
#define CFG_ENCODING_OPEN                           DECLARE_ASCII("[\'"                                             )   /// used to start encoding of set names
#define CFG_ENCODING_CLOSE                          DECLARE_ASCII("\']"                                             )   /// used to finish encoding of set names

#define SETNAME_HANDLER                             DECLARE_ASCII("HandlerSet"                                      )   /// name of configuration set inside package
#define PROPERTY_PROTOCOLS                          DECLARE_ASCII("Protocols"                                       )   /// properties of a protocol handler

//_________________________________________________________________________________________________________________

/**
    Programmer can register his own services to handle different protocols.
    Don't forget: It doesn't mean "handling of documents" ... these services could handle protocols ...
    e.g. "mailto:*", "file://*", ".java:*
    This struct holds the information about one such registered protocol handler.
    A list of handler objects is defined as ProtocolHandlerHash. see below
*/
struct ProtocolHandler
{
    /* member */
    public:

        /// the uno implementation name of this handler
        ::rtl::OUString m_sUNOName;
        /// list of URL pattern which defines the protocols which this handler is registered for
        OUStringList m_lProtocols;
};

//_________________________________________________________________________________________________________________

/**
    This hash use registered pattern of all protocol handlers as keys and provide her
    uno implementation names as value. Overloading of the index operator makes it possible
    to search for a key by using a full qualified URL on list of all possible pattern keys.
*/
class PatternHash : public BaseHash< ::rtl::OUString >
{
    /* interface */
    public:

        PatternHash::iterator findPatternKey( const ::rtl::OUString& sURL );
};

//_________________________________________________________________________________________________________________

/**
    This hash holds protocol handler structs by her names.
*/
typedef BaseHash< ProtocolHandler > HandlerHash;

//_________________________________________________________________________________________________________________

/**
    @short          this hash makes it easy to find a protocol handler by using his uno implementation name.
    @descr          It holds two lists of informations:
                        - first holds all handler by her uno implementation names and
                          can be used to get her other properties
                        - another one maps her registered pattern to her uno names to
                          perform search on such data
                    But this lists a static for all instances of this class. So it's possible to
                    create new objects without opening configuration twice and free memory automaticly
                    if last object will gone.

    @attention      We implement a singleton concept - so we doesn't need any mutex member here.
                    Because to safe access on static member we must use a static global lock
                    here too.

    @devstatus      ready to use
    @threadsafe     yes

    @modified       30.04.2002 11:19, as96863
*/

class HandlerCFGAccess;
class HandlerCache
{
    /* member */
    private:

        /// list of all registered handler registered by her uno implementation names
        static HandlerHash* m_pHandler;
        /// maps URL pattern to handler names
        static PatternHash* m_pPattern;
        /// informs about config updates
        static HandlerCFGAccess* m_pConfig;
        /// ref count to construct/destruct internal member lists on demand by using singleton mechanism
        static sal_Int32 m_nRefCount;

    /* interface */
    public:

                 HandlerCache();
        virtual ~HandlerCache();

        sal_Bool search( const ::rtl::OUString& sURL, ProtocolHandler* pReturn ) const;
        sal_Bool search( const css::util::URL&  aURL, ProtocolHandler* pReturn ) const;
        sal_Bool exists( const ::rtl::OUString& sURL ) const;

        void takeOver(HandlerHash* pHandler, PatternHash* pPattern);
};

//_________________________________________________________________________________________________________________

/**
    @short          implements configuration access for handler configuration
    @descr          We use the ConfigItem mechanism to read/write values from/to configuration.
                    We set a data container pointer for filling or reading ... this class use it temp.
                    After successfuly calling of read(), we can use filled container directly or merge it with an existing one.
                    After successfuly calling of write() all values of given data container are flushed to our configuration -
                    but current implementation doesn't support writeing realy.

    @base           ::utl::ConfigItem
                    base mechanism for configuration access

    @devstatus      ready to use
    @threadsafe     no

    @modified       30.04.2002 09:58, as96863
*/
class HandlerCFGAccess : public ::utl::ConfigItem
{
    private:
        HandlerCache* m_pCache;

    /* interface */
    public:
                 HandlerCFGAccess( const ::rtl::OUString& sPackage  );
        void     read            (       HandlerHash**    ppHandler ,
                                         PatternHash**    ppPattern );

        void setCache(HandlerCache* pCache) {m_pCache = pCache;};
        virtual void Notify(const css::uno::Sequence< rtl::OUString >& lPropertyNames);
};

} // namespace framework

#endif // #ifndef __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.100); FILE MERGED 2005/09/05 13:04:19 rt 1.4.100.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: protocolhandlercache.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 00:07:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_
#define __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_

/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
               with solaris headers ...
*/
#include <hash_map>
#include <vector>

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#include <general.h>
#include <stdtypes.h>
#include <macros/debug.hxx>

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_UTIL_URL_HPP_
#include <com/sun/star/util/URL.hpp>
#endif

//_________________________________________________________________________________________________________________
//  other includes
//_________________________________________________________________________________________________________________

#include <unotools/configitem.hxx>
#include <rtl/ustring.hxx>

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  exported const
//_________________________________________________________________________________________________________________

#define PACKAGENAME_PROTOCOLHANDLER                 DECLARE_ASCII("Office.ProtocolHandler"                          )   /// name of our configuration package

#define CFG_PATH_SEPERATOR                          DECLARE_ASCII("/"                                               )   /// seperator for configuration pathes
#define CFG_ENCODING_OPEN                           DECLARE_ASCII("[\'"                                             )   /// used to start encoding of set names
#define CFG_ENCODING_CLOSE                          DECLARE_ASCII("\']"                                             )   /// used to finish encoding of set names

#define SETNAME_HANDLER                             DECLARE_ASCII("HandlerSet"                                      )   /// name of configuration set inside package
#define PROPERTY_PROTOCOLS                          DECLARE_ASCII("Protocols"                                       )   /// properties of a protocol handler

//_________________________________________________________________________________________________________________

/**
    Programmer can register his own services to handle different protocols.
    Don't forget: It doesn't mean "handling of documents" ... these services could handle protocols ...
    e.g. "mailto:*", "file://*", ".java:*
    This struct holds the information about one such registered protocol handler.
    A list of handler objects is defined as ProtocolHandlerHash. see below
*/
struct ProtocolHandler
{
    /* member */
    public:

        /// the uno implementation name of this handler
        ::rtl::OUString m_sUNOName;
        /// list of URL pattern which defines the protocols which this handler is registered for
        OUStringList m_lProtocols;
};

//_________________________________________________________________________________________________________________

/**
    This hash use registered pattern of all protocol handlers as keys and provide her
    uno implementation names as value. Overloading of the index operator makes it possible
    to search for a key by using a full qualified URL on list of all possible pattern keys.
*/
class PatternHash : public BaseHash< ::rtl::OUString >
{
    /* interface */
    public:

        PatternHash::iterator findPatternKey( const ::rtl::OUString& sURL );
};

//_________________________________________________________________________________________________________________

/**
    This hash holds protocol handler structs by her names.
*/
typedef BaseHash< ProtocolHandler > HandlerHash;

//_________________________________________________________________________________________________________________

/**
    @short          this hash makes it easy to find a protocol handler by using his uno implementation name.
    @descr          It holds two lists of informations:
                        - first holds all handler by her uno implementation names and
                          can be used to get her other properties
                        - another one maps her registered pattern to her uno names to
                          perform search on such data
                    But this lists a static for all instances of this class. So it's possible to
                    create new objects without opening configuration twice and free memory automaticly
                    if last object will gone.

    @attention      We implement a singleton concept - so we doesn't need any mutex member here.
                    Because to safe access on static member we must use a static global lock
                    here too.

    @devstatus      ready to use
    @threadsafe     yes

    @modified       30.04.2002 11:19, as96863
*/

class HandlerCFGAccess;
class HandlerCache
{
    /* member */
    private:

        /// list of all registered handler registered by her uno implementation names
        static HandlerHash* m_pHandler;
        /// maps URL pattern to handler names
        static PatternHash* m_pPattern;
        /// informs about config updates
        static HandlerCFGAccess* m_pConfig;
        /// ref count to construct/destruct internal member lists on demand by using singleton mechanism
        static sal_Int32 m_nRefCount;

    /* interface */
    public:

                 HandlerCache();
        virtual ~HandlerCache();

        sal_Bool search( const ::rtl::OUString& sURL, ProtocolHandler* pReturn ) const;
        sal_Bool search( const css::util::URL&  aURL, ProtocolHandler* pReturn ) const;
        sal_Bool exists( const ::rtl::OUString& sURL ) const;

        void takeOver(HandlerHash* pHandler, PatternHash* pPattern);
};

//_________________________________________________________________________________________________________________

/**
    @short          implements configuration access for handler configuration
    @descr          We use the ConfigItem mechanism to read/write values from/to configuration.
                    We set a data container pointer for filling or reading ... this class use it temp.
                    After successfuly calling of read(), we can use filled container directly or merge it with an existing one.
                    After successfuly calling of write() all values of given data container are flushed to our configuration -
                    but current implementation doesn't support writeing realy.

    @base           ::utl::ConfigItem
                    base mechanism for configuration access

    @devstatus      ready to use
    @threadsafe     no

    @modified       30.04.2002 09:58, as96863
*/
class HandlerCFGAccess : public ::utl::ConfigItem
{
    private:
        HandlerCache* m_pCache;

    /* interface */
    public:
                 HandlerCFGAccess( const ::rtl::OUString& sPackage  );
        void     read            (       HandlerHash**    ppHandler ,
                                         PatternHash**    ppPattern );

        void setCache(HandlerCache* pCache) {m_pCache = pCache;};
        virtual void Notify(const css::uno::Sequence< rtl::OUString >& lPropertyNames);
};

} // namespace framework

#endif // #ifndef __FRAMEWORK_CLASSES_PROTOCOLHANDLERCACHE_HXX_
<|endoftext|>


<commit_before>#include <systemlib/mixer/mixer.h>
#include <systemlib/err.h>
#include "../../src/systemcmds/tests/tests.h"

int main(int argc, char *argv[]) {
	warnx("Host execution started");

	char* args[] = {argv[0], "../../ROMFS/px4fmu_common/mixers/IO_pass.mix",
				 "../../ROMFS/px4fmu_common/mixers/FMU_quad_w.mix"};

	test_mixer(3, args);

	test_conv(1, args);
}
<commit_msg>Improve mixer test, no firm checks yet<commit_after>#include <systemlib/mixer/mixer.h>
#include <systemlib/err.h>
#include "../../src/systemcmds/tests/tests.h"

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

	int ret;

	warnx("Host execution started");

	char* args[] = {argv[0], "../ROMFS/px4fmu_common/mixers/IO_pass.mix",
				 "../ROMFS/px4fmu_common/mixers/FMU_quad_w.mix"};

	if (ret = test_mixer(3, args));

	test_conv(1, args);

	return 0;
}
<|endoftext|>


<commit_before>// -----------------------------------------------------------------------------
// Local Search Non-negative Matrix Factorization
// By Twan van Laarhoven
// License: BSD style, see file LICENSE
// -----------------------------------------------------------------------------

#ifndef HEADER_NMF_CLUSTERING
#define HEADER_NMF_CLUSTERING

#include "util.hpp"
#include "sparse_matrix.hpp"
#include "sparse_vector.hpp"
#include <vector>
#include <iomanip>
#include <stdexcept>

namespace nmf_cluster {

using namespace lso_cluster;
using namespace std;

// -----------------------------------------------------------------------------
// Data type storing a clustering
// -----------------------------------------------------------------------------

// An NMF clustering gives for each node the clusters of which it is a member
struct NMFClustering {
  private:
	std::vector<SparseVector> clustering; // which clusters is each node in?
	std::vector<int>    cluster_size;     // size of each cluster
	std::vector<double> cluster_weight;   // total weight of each cluster
	friend struct IndirectClustering;
	friend void swap(NMFClustering&,NMFClustering&);

  public:
	NMFClustering() {}
	NMFClustering(int num_node, int max_num_clus)
		: clustering(num_node)
		, cluster_size  (max_num_clus, 0)
		, cluster_weight(max_num_clus, 0.)
	{}
	NMFClustering(std::vector<SparseVector> const& clustering, int max_num_clus)
		: clustering(clustering)
		, cluster_size  (max_num_clus, 0)
		, cluster_weight(max_num_clus, 0.)
	{
		recalc_internal_data();
	}

	// An upport bound on cluster ids
	inline clus_t max_num_clus() const {
		return (clus_t)cluster_size.size();
	}
	// Number of nodes
	inline node_t num_nodes() const {
		return (node_t)clustering.size();
	}
	inline int clus_size(clus_t k) const {
		return cluster_size[k];
	}
	inline double clus_weight(clus_t k) const {
		return cluster_weight[k];
	}
	int nnz() const {
		int nnz = 0;
		for (node_t i = 0 ; i < num_nodes() ; ++i) {
			nnz += clustering[i].nnz();
		}
		return nnz;
	}
	int total_size() const {
		return num_nodes() * max_num_clus();
	}
	int number_of_zeros() const {
		return total_size() - nnz();
	}
	bool empty() {
		return clustering.empty();
	}

	// iteration over the nodes
	typedef std::vector<SparseVector>::const_iterator const_iterator;
	inline const_iterator begin() const {
		return clustering.begin();
	}
	inline const_iterator end() const {
		return clustering.end();
	}
	inline SparseVector const& operator [] (node_t i) const {
		return clustering[i];
	}

	// Convert to a sparse matrix
	SparseMatrix to_sparse_matrix() const;
	// Convert from a sparse matrix
	NMFClustering(SparseMatrix const&);
	void operator = (SparseMatrix const&);

	// Convert to a hard clustering: cluster with highest membership for each node
	vector<clus_t> to_hard_clustering() const;
	clus_t best_cluster(node_t i) const;

	// Modification
	void add(node_t i, clus_t clus, double weight) {
		clustering[i].insert(clus, weight);
		cluster_size[clus]++;
		cluster_weight[clus] += weight;
	}
	void remove(node_t i, clus_t clus) {
		cluster_weight[clus] -= clustering[i].remove(clus);
		cluster_size[clus]--;
	}
	void clear() {
		std::fill(cluster_size.begin(),   cluster_size.end(),   0.);
		std::fill(cluster_weight.begin(), cluster_weight.end(), 0.);
		for (node_t i = 0 ; i < num_nodes() ; ++i) {
			clustering[i].clear();
		}
	}
	void clear_node(node_t i) {
		for (SparseVector::const_iterator it = clustering[i].begin() ; it != clustering[i].end() ; ++it) {
			cluster_size[it->clus]--;
			cluster_weight[it->clus] -= it->weight;
		}
		clustering[i].clear();
	}
	void set(node_t i, SparseVector const& new_clustering) {
		clear_node(i);
		for (SparseVector::const_iterator it = new_clustering.begin() ; it != new_clustering.end() ; ++it) {
			cluster_size[it->clus]++;
			cluster_weight[it->clus] += it->weight;
		}
		clustering[i] = new_clustering;
	}
  private:
	void recalc_internal_data() {
		std::fill(cluster_size.begin(),   cluster_size.end(),   0.);
		std::fill(cluster_weight.begin(), cluster_weight.end(), 0.);
		for (std::vector<SparseVector>::const_iterator clus_it = clustering.begin() ; clus_it != clustering.end() ; ++clus_it) {
			for (SparseVector::const_iterator it = clus_it->begin() ; it != clus_it->end() ; ++it) {
				assert((size_t)it->clus < cluster_size.size());
				assert((size_t)it->clus < cluster_weight.size());
				cluster_size[it->clus]++;
				cluster_weight[it->clus] += it->weight;
			}
		}
	}
};

SparseMatrix NMFClustering::to_sparse_matrix() const {
	// find number of non-empty clusters, and remap them to [0..]
	std::vector<int> clus_id(max_num_clus(), -1); // mapping cluster id to compressed cluster id
	size_t num_clus = 0;   // number of non-empty clusters
	size_t num_inclus = 0; // number of non-zeros
	for (NMFClustering::const_iterator it = clustering.begin() ; it != clustering.end() ; ++it) {
		for (SparseVector::const_iterator it2 = it->begin() ; it2 != it->end() ; ++it2) {
			if (clus_id[it2->clus] == -1) {
				clus_id[it2->clus] = num_clus;
				num_clus++;
			}
			num_inclus++;
		}
	}

	// build clustering matrix
	// transpose of the usual notation, i.e. here columns=nodes, rows=clusters
	SparseMatrix out((int)num_clus, (int)clustering.size(), (int)num_inclus);
	int k = 0;
	out.cidx(0) = k;
	for (size_t j = 0 ; j < clustering.size() ; ++j) {
		for (SparseVector::const_iterator it2 = clustering[j].begin() ; it2 != clustering[j].end() ; ++it2) {
			out.ridx(k) = clus_id[it2->clus];
			out.data(k) = it2->weight;
			k++;
		}
		out.cidx(j+1) = k;
	}
	return out;
}

vector<clus_t> NMFClustering::to_hard_clustering() const {
	std::vector<clus_t> best_clus(num_nodes());
	for (node_t i = 0 ; i < num_nodes() ; ++i) {
		best_clus[i] = best_cluster(i);
	}
	compress_assignments(best_clus);
	return best_clus;
}

clus_t NMFClustering::best_cluster(node_t i) const {
	clus_t best = i;
	double max_weight = -1;
	for (SparseVector::const_iterator it = clustering[i].begin() ; it != clustering[i].end() ; ++it) {
		if (it->weight > max_weight) {
			best = it->clus;
			max_weight = it->weight;
		}
	}
	return best;
}

void NMFClustering::operator = (SparseMatrix const& mat) {
	NMFClustering that(mat);
	swap(*this,that);
}
NMFClustering::NMFClustering(SparseMatrix const& mat)
	: clustering(mat.cols())
	, cluster_size(mat.rows())
	, cluster_weight(mat.rows())
{
	for (int i = 0 ; i < mat.cols() ; ++i) {
		clustering[i] = ColumnIterator(mat, i);
	}
	recalc_internal_data();
}

void swap(NMFClustering& a, NMFClustering& b) {
	swap(a.clustering,     b.clustering);
	swap(a.cluster_size,   b.cluster_size);
	swap(a.cluster_weight, b.cluster_weight);
}

// -----------------------------------------------------------------------------
// A clustering of a clustering
// -----------------------------------------------------------------------------

// each cluster in the indirect clustering is a linear combination of clusters in the base clustering
// in other words, I=B*R
struct IndirectClustering {
	vector<vector<node_t> > nodes_in_cluster; // which base nodes are in which base cluster?
	NMFClustering const& base;
	NMFClustering refined;

	IndirectClustering(NMFClustering const& base, int max_num_clus)
		: base(base)
		, refined(base.max_num_clus(), max_num_clus)
	{}

	NMFClustering to_clustering() const {
		return NMFClustering(base.clustering * refined.clustering, refined.max_num_clus());
	}
};

// -----------------------------------------------------------------------------
}
#endif
<commit_msg>Fix NMFClustering::to_sparse_matrix: make sure row indices (cluster ids) are sorted<commit_after>// -----------------------------------------------------------------------------
// Local Search Non-negative Matrix Factorization
// By Twan van Laarhoven
// License: BSD style, see file LICENSE
// -----------------------------------------------------------------------------

#ifndef HEADER_NMF_CLUSTERING
#define HEADER_NMF_CLUSTERING

#include "util.hpp"
#include "sparse_matrix.hpp"
#include "sparse_vector.hpp"
#include <vector>
#include <iomanip>
#include <stdexcept>

namespace nmf_cluster {

using namespace lso_cluster;
using namespace std;

// -----------------------------------------------------------------------------
// Data type storing a clustering
// -----------------------------------------------------------------------------

// An NMF clustering gives for each node the clusters of which it is a member
struct NMFClustering {
  private:
	std::vector<SparseVector> clustering; // which clusters is each node in?
	std::vector<int>    cluster_size;     // size of each cluster
	std::vector<double> cluster_weight;   // total weight of each cluster
	friend struct IndirectClustering;
	friend void swap(NMFClustering&,NMFClustering&);

  public:
	NMFClustering() {}
	NMFClustering(int num_node, int max_num_clus)
		: clustering(num_node)
		, cluster_size  (max_num_clus, 0)
		, cluster_weight(max_num_clus, 0.)
	{}
	NMFClustering(std::vector<SparseVector> const& clustering, int max_num_clus)
		: clustering(clustering)
		, cluster_size  (max_num_clus, 0)
		, cluster_weight(max_num_clus, 0.)
	{
		recalc_internal_data();
	}

	// An upport bound on cluster ids
	inline clus_t max_num_clus() const {
		return (clus_t)cluster_size.size();
	}
	// Number of nodes
	inline node_t num_nodes() const {
		return (node_t)clustering.size();
	}
	inline int clus_size(clus_t k) const {
		return cluster_size[k];
	}
	inline double clus_weight(clus_t k) const {
		return cluster_weight[k];
	}
	int nnz() const {
		int nnz = 0;
		for (node_t i = 0 ; i < num_nodes() ; ++i) {
			nnz += clustering[i].nnz();
		}
		return nnz;
	}
	int total_size() const {
		return num_nodes() * max_num_clus();
	}
	int number_of_zeros() const {
		return total_size() - nnz();
	}
	bool empty() {
		return clustering.empty();
	}

	// iteration over the nodes
	typedef std::vector<SparseVector>::const_iterator const_iterator;
	inline const_iterator begin() const {
		return clustering.begin();
	}
	inline const_iterator end() const {
		return clustering.end();
	}
	inline SparseVector const& operator [] (node_t i) const {
		return clustering[i];
	}

	// Convert to a sparse matrix
	SparseMatrix to_sparse_matrix() const;
	// Convert from a sparse matrix
	NMFClustering(SparseMatrix const&);
	void operator = (SparseMatrix const&);

	// Convert to a hard clustering: cluster with highest membership for each node
	vector<clus_t> to_hard_clustering() const;
	clus_t best_cluster(node_t i) const;

	// Modification
	void add(node_t i, clus_t clus, double weight) {
		clustering[i].insert(clus, weight);
		cluster_size[clus]++;
		cluster_weight[clus] += weight;
	}
	void remove(node_t i, clus_t clus) {
		cluster_weight[clus] -= clustering[i].remove(clus);
		cluster_size[clus]--;
	}
	void clear() {
		std::fill(cluster_size.begin(),   cluster_size.end(),   0.);
		std::fill(cluster_weight.begin(), cluster_weight.end(), 0.);
		for (node_t i = 0 ; i < num_nodes() ; ++i) {
			clustering[i].clear();
		}
	}
	void clear_node(node_t i) {
		for (SparseVector::const_iterator it = clustering[i].begin() ; it != clustering[i].end() ; ++it) {
			cluster_size[it->clus]--;
			cluster_weight[it->clus] -= it->weight;
		}
		clustering[i].clear();
	}
	void set(node_t i, SparseVector const& new_clustering) {
		clear_node(i);
		for (SparseVector::const_iterator it = new_clustering.begin() ; it != new_clustering.end() ; ++it) {
			cluster_size[it->clus]++;
			cluster_weight[it->clus] += it->weight;
		}
		clustering[i] = new_clustering;
	}
  private:
	void recalc_internal_data() {
		std::fill(cluster_size.begin(),   cluster_size.end(),   0.);
		std::fill(cluster_weight.begin(), cluster_weight.end(), 0.);
		for (std::vector<SparseVector>::const_iterator clus_it = clustering.begin() ; clus_it != clustering.end() ; ++clus_it) {
			for (SparseVector::const_iterator it = clus_it->begin() ; it != clus_it->end() ; ++it) {
				assert((size_t)it->clus < cluster_size.size());
				assert((size_t)it->clus < cluster_weight.size());
				cluster_size[it->clus]++;
				cluster_weight[it->clus] += it->weight;
			}
		}
	}
};

SparseMatrix NMFClustering::to_sparse_matrix() const {
	// find the non-empty clusters, and the number of nonzeros
	std::vector<int> clus_id(max_num_clus(), -1); // mapping cluster id to compressed cluster id, or -1
	size_t num_inclus = 0; // number of non-zeros
	for (NMFClustering::const_iterator it = clustering.begin() ; it != clustering.end() ; ++it) {
		for (SparseVector::const_iterator it2 = it->begin() ; it2 != it->end() ; ++it2) {
			clus_id[it2->clus] = 1;
			num_inclus++;
		}
	}
	// label the clusters [0..]
	size_t num_clus = 0;   // number of non-empty clusters
	for (std::vector<int>::iterator it = clus_id.begin() ; it != clus_id.end() ; ++it) {
		if (*it != -1) {
			*it = num_clus++;
		}
	}

	// build clustering matrix
	// transpose of the usual notation, i.e. here columns=nodes, rows=clusters
	SparseMatrix out((int)num_clus, (int)clustering.size(), (int)num_inclus);
	int k = 0;
	out.cidx(0) = k;
	for (size_t j = 0 ; j < clustering.size() ; ++j) {
		for (SparseVector::const_iterator it2 = clustering[j].begin() ; it2 != clustering[j].end() ; ++it2) {
			out.ridx(k) = clus_id[it2->clus];
			out.data(k) = it2->weight;
			k++;
		}
		out.cidx(j+1) = k;
	}
	return out;
}

vector<clus_t> NMFClustering::to_hard_clustering() const {
	std::vector<clus_t> best_clus(num_nodes());
	for (node_t i = 0 ; i < num_nodes() ; ++i) {
		best_clus[i] = best_cluster(i);
	}
	compress_assignments(best_clus);
	return best_clus;
}

clus_t NMFClustering::best_cluster(node_t i) const {
	clus_t best = i;
	double max_weight = -1;
	for (SparseVector::const_iterator it = clustering[i].begin() ; it != clustering[i].end() ; ++it) {
		if (it->weight > max_weight) {
			best = it->clus;
			max_weight = it->weight;
		}
	}
	return best;
}

void NMFClustering::operator = (SparseMatrix const& mat) {
	NMFClustering that(mat);
	swap(*this,that);
}
NMFClustering::NMFClustering(SparseMatrix const& mat)
	: clustering(mat.cols())
	, cluster_size(mat.rows())
	, cluster_weight(mat.rows())
{
	for (int i = 0 ; i < mat.cols() ; ++i) {
		clustering[i] = ColumnIterator(mat, i);
	}
	recalc_internal_data();
}

void swap(NMFClustering& a, NMFClustering& b) {
	swap(a.clustering,     b.clustering);
	swap(a.cluster_size,   b.cluster_size);
	swap(a.cluster_weight, b.cluster_weight);
}

// -----------------------------------------------------------------------------
// A clustering of a clustering
// -----------------------------------------------------------------------------

// each cluster in the indirect clustering is a linear combination of clusters in the base clustering
// in other words, I=B*R
struct IndirectClustering {
	vector<vector<node_t> > nodes_in_cluster; // which base nodes are in which base cluster?
	NMFClustering const& base;
	NMFClustering refined;

	IndirectClustering(NMFClustering const& base, int max_num_clus)
		: base(base)
		, refined(base.max_num_clus(), max_num_clus)
	{}

	NMFClustering to_clustering() const {
		return NMFClustering(base.clustering * refined.clustering, refined.max_num_clus());
	}
};

// -----------------------------------------------------------------------------
}
#endif
<|endoftext|>


<commit_before>#include <ros.h>
#include <string.h>

#include "MS5837.h"
#include "Adafruit_BNO055.h"
#include "Adafruit_Sensor.h"
#include "DallasTemperature.h"
#include <Wire.h>

#include "std_msgs/String.h"
#include <geometry_msgs/Vector3.h>
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/MagneticField.h"
#include "sensor_msgs/Temperature.h"
#include "sensor_msgs/FluidPressure.h"

#define STANDARD_GRAVITY 9.08665      // [m/s^2]
#define RAD_PER_DEG 0.01745329252     // [1/deg]
#define PASCAL_PER_MILLIBAR 0.01      // [Pa/mbar]
#define MICROTESLA_PER_TESLA 0.000001 // [uT/T]

int id = -1;

ros::NodeHandle nh;

sensor_msgs::Imu imu_raw_msg;
sensor_msgs::MagneticField compass_msg;

sensor_msgs::Temperature imu_temperature_msg;
sensor_msgs::Temperature sensor_temperature_msg;
sensor_msgs::FluidPressure pressure_msg;

std_msgs::String calibration;

ros::Publisher pub_imu("imu/data", &imu_raw_msg);
ros::Publisher pub_mag("imu/mag", &compass_msg);

ros::Publisher pub_pressure("imu/pressure", &pressure_msg);
ros::Publisher pub_imu_temperature("imu/temperature", &imu_temperature_msg);
ros::Publisher pub_sensor_temperature("sensor/temperature", &sensor_temperature_msg);

ros::Publisher pub_calibration("imu/calibration", &calibration);

float DBG_AXIS_SIGN_VALUE = -1.0;

const int SensorReadDelay = 40;
unsigned long PrevoiusSensorReadMillis = 0;

int dbg_count = 0;

MS5837 barometer;
Adafruit_BNO055 bno055 = Adafruit_BNO055(55);

#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

// double GyroLsbSens, AccelLsbSens;
void setupIMU();

void setup() {

    //start ROS-node
    nh.initNode();

    // nh.advertise(pub_dbg);
    nh.advertise(pub_imu_temperature);
    nh.advertise(pub_sensor_temperature);

    nh.advertise(pub_pressure);
    nh.advertise(pub_imu);
    nh.advertise(pub_mag);
    nh.advertise(pub_calibration);

    // Initialize the 'Wire' class for communicating over i2c
    Wire.begin();
    barometer.init();
    barometer.read();

    setupIMU();
    // nh.advertise(pub_mag);
}

void setupIMU() {

    /*
        Sets opmode to NDOF by default

        From Adafruit_BNO055.h:

        OPERATION_MODE_CONFIG                                   = 0X00,
        OPERATION_MODE_ACCONLY                                  = 0X01,
        OPERATION_MODE_MAGONLY                                  = 0X02,
        OPERATION_MODE_GYRONLY                                  = 0X03,
        OPERATION_MODE_ACCMAG                                   = 0X04,
        OPERATION_MODE_ACCGYRO                                  = 0X05,
        OPERATION_MODE_MAGGYRO                                  = 0X06,
        OPERATION_MODE_AMG                                      = 0X07,
        OPERATION_MODE_IMUPLUS                                  = 0X08,
        OPERATION_MODE_COMPASS                                  = 0X09,
        OPERATION_MODE_M4G                                      = 0X0A,
        OPERATION_MODE_NDOF_FMC_OFF                             = 0X0B,
        OPERATION_MODE_NDOF                                     = 0X0C

                    ACCEL   MAG     GYRO    RELATIVE        ABSOLUTE
                                            ORIENTATION     ORIENTATION
        ---------------------------------------------------------------
        IMU     |    X    |   -    |   X  |       X        |     -
        COMPASS |    X    |   X    |   -  |       -        |     X
        M4G     |    X    |   X    |   -  |       X        |     -
        NDOF    |    X    |   X    |   X  |       -        |     X
    */

    id = bno055.begin(bno055.OPERATION_MODE_CONFIG);
    bno055.setAxisSign(bno055.REMAP_SIGN_P4);
    bno055.setMode(bno055.OPERATION_MODE_IMUPLUS);
}

void getPressure() {

    // float pressure = barometer.pressure();
    float pressure = barometer.pressure();
    pressure_msg.fluid_pressure = pressure * 100;
    pub_pressure.publish(&pressure_msg);

}

#define BARO 10
int baro_counter = 0;
void getBarometerTemp() {

    if(baro_counter < BARO){
        baro_counter++;
        return;
    }
    else{
        baro_counter = 0;
    }

    float temp = barometer.temperature();
    imu_temperature_msg.temperature = DBG_AXIS_SIGN_VALUE;

    pub_imu_temperature.publish(&imu_temperature_msg);

}

#define DALL 10
int dallas_counter = 50;
void getDallasTemp() {

    if(dallas_counter < DALL){
        dallas_counter++;
        return;
    }
    else{
        dallas_counter = 0;
    }

    sensors.requestTemperatures();
    float temp = sensors.getTempCByIndex(0);
    sensor_temperature_msg.temperature = temp;

    pub_sensor_temperature.publish(&sensor_temperature_msg);

}

void getRawIMU() {

    // sensors_event_t event;
    // bno055.getEvent(&event);

    imu::Vector<3> gyro = bno055.getVector(bno055.VECTOR_GYROSCOPE);
    imu_raw_msg.linear_acceleration.x = gyro[0];
    imu_raw_msg.linear_acceleration.y = gyro[1];
    imu_raw_msg.linear_acceleration.z = gyro[2];

    imu::Vector<3> lin_acc = bno055.getVector(bno055.VECTOR_LINEARACCEL);
    imu_raw_msg.angular_velocity.x = lin_acc[0];
    imu_raw_msg.angular_velocity.y = lin_acc[1];
    imu_raw_msg.angular_velocity.z = lin_acc[2];

    imu::Quaternion qs = bno055.getQuat();
    imu_raw_msg.orientation.x = qs.x();
    imu_raw_msg.orientation.y = qs.y();
    imu_raw_msg.orientation.z = qs.z();
    imu_raw_msg.orientation.w = qs.w();

    imu_raw_msg.header.stamp = ros::Time(millis()/1000.0, 0);
    pub_imu.publish(&imu_raw_msg);

}

bool calibrated = false;

void getCalibrationStatus(){

    // lol
    uint8_t sys, gyro, accel, mag;
    sys = gyro = accel = mag = 0;
    bno055.getCalibration(&sys, &gyro, &accel, &mag);
    char buffer[128] = { '\0' };

    if (sys == 3 && gyro == 3 && accel == 3 && mag == 3){
        if(!calibrated){
            sprintf(buffer, "\n All systems go\n");
            calibrated = true;
        }
        return;
    }

    calibrated = false;
    sprintf(buffer, "\nSys: %d, Gyro: %d, Acc: %d, mag: %d\n", sys, gyro, accel, mag);
    String s = String(buffer);
    calibration.data = s.c_str();
    pub_calibration.publish(&calibration);

}

void loop(){

    nh.spinOnce();

    if( millis() - PrevoiusSensorReadMillis >= SensorReadDelay ) {

        PrevoiusSensorReadMillis = millis();

        barometer.read();
        nh.spinOnce();

        getPressure();
        nh.spinOnce();

        getBarometerTemp();
        nh.spinOnce();

        getDallasTemp();
        nh.spinOnce();

        getRawIMU();
        nh.spinOnce();

        getCalibrationStatus();
        nh.spinOnce();

    }
}

<commit_msg>forgot to read sign<commit_after>#include <ros.h>
#include <string.h>

#include "MS5837.h"
#include "Adafruit_BNO055.h"
#include "Adafruit_Sensor.h"
#include "DallasTemperature.h"
#include <Wire.h>

#include "std_msgs/String.h"
#include <geometry_msgs/Vector3.h>
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/MagneticField.h"
#include "sensor_msgs/Temperature.h"
#include "sensor_msgs/FluidPressure.h"

#define STANDARD_GRAVITY 9.08665      // [m/s^2]
#define RAD_PER_DEG 0.01745329252     // [1/deg]
#define PASCAL_PER_MILLIBAR 0.01      // [Pa/mbar]
#define MICROTESLA_PER_TESLA 0.000001 // [uT/T]

int id = -1;

ros::NodeHandle nh;

sensor_msgs::Imu imu_raw_msg;
sensor_msgs::MagneticField compass_msg;

sensor_msgs::Temperature imu_temperature_msg;
sensor_msgs::Temperature sensor_temperature_msg;
sensor_msgs::FluidPressure pressure_msg;

std_msgs::String calibration;

ros::Publisher pub_imu("imu/data", &imu_raw_msg);
ros::Publisher pub_mag("imu/mag", &compass_msg);

ros::Publisher pub_pressure("imu/pressure", &pressure_msg);
ros::Publisher pub_imu_temperature("imu/temperature", &imu_temperature_msg);
ros::Publisher pub_sensor_temperature("sensor/temperature", &sensor_temperature_msg);

ros::Publisher pub_calibration("imu/calibration", &calibration);

float DBG_AXIS_SIGN_VALUE = -1.0;

const int SensorReadDelay = 40;
unsigned long PrevoiusSensorReadMillis = 0;

int dbg_count = 0;

MS5837 barometer;
Adafruit_BNO055 bno055 = Adafruit_BNO055(55);

#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

// double GyroLsbSens, AccelLsbSens;
void setupIMU();

void setup() {

    //start ROS-node
    nh.initNode();

    // nh.advertise(pub_dbg);
    nh.advertise(pub_imu_temperature);
    nh.advertise(pub_sensor_temperature);

    nh.advertise(pub_pressure);
    nh.advertise(pub_imu);
    nh.advertise(pub_mag);
    nh.advertise(pub_calibration);

    // Initialize the 'Wire' class for communicating over i2c
    Wire.begin();
    barometer.init();
    barometer.read();

    setupIMU();
    // nh.advertise(pub_mag);
}

void setupIMU() {

    /*
        Sets opmode to NDOF by default

        From Adafruit_BNO055.h:

        OPERATION_MODE_CONFIG                                   = 0X00,
        OPERATION_MODE_ACCONLY                                  = 0X01,
        OPERATION_MODE_MAGONLY                                  = 0X02,
        OPERATION_MODE_GYRONLY                                  = 0X03,
        OPERATION_MODE_ACCMAG                                   = 0X04,
        OPERATION_MODE_ACCGYRO                                  = 0X05,
        OPERATION_MODE_MAGGYRO                                  = 0X06,
        OPERATION_MODE_AMG                                      = 0X07,
        OPERATION_MODE_IMUPLUS                                  = 0X08,
        OPERATION_MODE_COMPASS                                  = 0X09,
        OPERATION_MODE_M4G                                      = 0X0A,
        OPERATION_MODE_NDOF_FMC_OFF                             = 0X0B,
        OPERATION_MODE_NDOF                                     = 0X0C

                    ACCEL   MAG     GYRO    RELATIVE        ABSOLUTE
                                            ORIENTATION     ORIENTATION
        ---------------------------------------------------------------
        IMU     |    X    |   -    |   X  |       X        |     -
        COMPASS |    X    |   X    |   -  |       -        |     X
        M4G     |    X    |   X    |   -  |       X        |     -
        NDOF    |    X    |   X    |   X  |       -        |     X
    */

    id = bno055.begin(bno055.OPERATION_MODE_CONFIG);
    DBG_AXIS_SIGN_VALUE = bno055.setAxisSign(bno055.REMAP_SIGN_P4);
    bno055.setMode(bno055.OPERATION_MODE_IMUPLUS);
}

void getPressure() {

    // float pressure = barometer.pressure();
    float pressure = barometer.pressure();
    pressure_msg.fluid_pressure = pressure * 100;
    pub_pressure.publish(&pressure_msg);

}

#define BARO 10
int baro_counter = 0;
void getBarometerTemp() {

    if(baro_counter < BARO){
        baro_counter++;
        return;
    }
    else{
        baro_counter = 0;
    }

    float temp = barometer.temperature();
    imu_temperature_msg.temperature = DBG_AXIS_SIGN_VALUE;

    pub_imu_temperature.publish(&imu_temperature_msg);

}

#define DALL 10
int dallas_counter = 50;
void getDallasTemp() {

    if(dallas_counter < DALL){
        dallas_counter++;
        return;
    }
    else{
        dallas_counter = 0;
    }

    sensors.requestTemperatures();
    float temp = sensors.getTempCByIndex(0);
    sensor_temperature_msg.temperature = temp;

    pub_sensor_temperature.publish(&sensor_temperature_msg);

}

void getRawIMU() {

    // sensors_event_t event;
    // bno055.getEvent(&event);

    imu::Vector<3> gyro = bno055.getVector(bno055.VECTOR_GYROSCOPE);
    imu_raw_msg.linear_acceleration.x = gyro[0];
    imu_raw_msg.linear_acceleration.y = gyro[1];
    imu_raw_msg.linear_acceleration.z = gyro[2];

    imu::Vector<3> lin_acc = bno055.getVector(bno055.VECTOR_LINEARACCEL);
    imu_raw_msg.angular_velocity.x = lin_acc[0];
    imu_raw_msg.angular_velocity.y = lin_acc[1];
    imu_raw_msg.angular_velocity.z = lin_acc[2];

    imu::Quaternion qs = bno055.getQuat();
    imu_raw_msg.orientation.x = qs.x();
    imu_raw_msg.orientation.y = qs.y();
    imu_raw_msg.orientation.z = qs.z();
    imu_raw_msg.orientation.w = qs.w();

    imu_raw_msg.header.stamp = ros::Time(millis()/1000.0, 0);
    pub_imu.publish(&imu_raw_msg);

}

bool calibrated = false;

void getCalibrationStatus(){

    // lol
    uint8_t sys, gyro, accel, mag;
    sys = gyro = accel = mag = 0;
    bno055.getCalibration(&sys, &gyro, &accel, &mag);
    char buffer[128] = { '\0' };

    if (sys == 3 && gyro == 3 && accel == 3 && mag == 3){
        if(!calibrated){
            sprintf(buffer, "\n All systems go\n");
            calibrated = true;
        }
        return;
    }

    calibrated = false;
    sprintf(buffer, "\nSys: %d, Gyro: %d, Acc: %d, mag: %d\n", sys, gyro, accel, mag);
    String s = String(buffer);
    calibration.data = s.c_str();
    pub_calibration.publish(&calibration);

}

void loop(){

    nh.spinOnce();

    if( millis() - PrevoiusSensorReadMillis >= SensorReadDelay ) {

        PrevoiusSensorReadMillis = millis();

        barometer.read();
        nh.spinOnce();

        getPressure();
        nh.spinOnce();

        getBarometerTemp();
        nh.spinOnce();

        getDallasTemp();
        nh.spinOnce();

        getRawIMU();
        nh.spinOnce();

        getCalibrationStatus();
        nh.spinOnce();

    }
}

<|endoftext|>


<commit_before><commit_msg>Fix Windows build<commit_after><|endoftext|>


<commit_before>#ifndef TICKTIMER_SUBSYSTEM_HPP
#define TICKTIMER_SUBSYSTEM_HPP

#include <ge/subsystem.hpp>
#include <ge/actor.hpp>

#include "gridtick_interface.hpp"

#include <boost/signals2.hpp>

struct ticktimer : public ge::actor {

    void initialize() {
        add_interface<ticktimer, gridtick_interface>();
    }

    std::deque<boost::signals2::signal<void()>> callbacks;

    void tick_grid() {
        // run the callbakcs
        callbacks[0]();

        callbacks.pop_front();
    }

    boost::signals2::connection addTimer(int nTicks, std::function<void()> call) {
        return callbacks[nTicks].connect(call);
    }

};

#endif // TICKTIMER_SUBSYSTEM_HPP
<commit_msg>Fix one segfault, one to go!<commit_after>#ifndef TICKTIMER_SUBSYSTEM_HPP
#define TICKTIMER_SUBSYSTEM_HPP

#include <ge/subsystem.hpp>
#include <ge/actor.hpp>

#include "gridtick_interface.hpp"

#include <boost/signals2.hpp>

struct ticktimer : public ge::actor {

    void initialize() {
        add_interface<ticktimer, gridtick_interface>();
    }

    std::deque<boost::signals2::signal<void()>> callbacks;

    void tick_grid() {
        // run the callbakcs
        callbacks[0]();

        callbacks.pop_front();
    }

    boost::signals2::connection addTimer(int nTicks, std::function<void()> call) {
        if(callbacks.size() <= nTicks) {
            callbacks.resize(nTicks + 1);
        }
        return callbacks[nTicks].connect(call);
    }

};

#endif // TICKTIMER_SUBSYSTEM_HPP
<|endoftext|>


<commit_before>// Copyright 2013-2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// PKCS#11 s11.8: Encryption functions (on asymmetric keys)
//   C_EncryptInit
//   C_Encrypt
//   C_EncryptUpdate
//   C_EncryptFinal
// PKCS#11 s11.9: Decryption functions (on asymmetric keys)
//   C_DecryptInit
//   C_Decrypt
//   C_DecryptUpdate
//   C_DecryptFinal

#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

namespace {

class KeyPairTest : public ReadWriteSessionTest {
 public:
  KeyPairTest()
    : public_attrs_({CKA_ENCRYPT, CKA_TOKEN}),
      private_attrs_({CKA_DECRYPT, CKA_TOKEN}),
      keypair_(session_, public_attrs_, private_attrs_) {}
 protected:
  vector<CK_ATTRIBUTE_TYPE> public_attrs_;
  vector<CK_ATTRIBUTE_TYPE> private_attrs_;
  KeyPair keypair_;
};

}  // namespace

TEST_F(KeyPairTest, EncryptDecrypt) {
  CK_BYTE plaintext[10];
  CK_ULONG plaintext_len = sizeof(plaintext);
  memcpy(plaintext, "0123456789", plaintext_len);
  // First encrypt the data with the public key.
  CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL_PTR, 0};
  CK_RV rv = g_fns->C_EncryptInit(session_, &mechanism, keypair_.public_handle());
  ASSERT_CKR_OK(rv);

  CK_BYTE ciphertext[1024];
  CK_ULONG ciphertext_len = sizeof(ciphertext);
  rv = g_fns->C_Encrypt(session_, plaintext, plaintext_len, ciphertext, &ciphertext_len);
  ASSERT_CKR_OK(rv);
  EXPECT_EQ(128, ciphertext_len);

  // Now decrypt the data with the private key.
  rv = g_fns->C_DecryptInit(session_, &mechanism, keypair_.private_handle());
  ASSERT_CKR_OK(rv);

  CK_BYTE recovered_plaintext[1024];
  CK_ULONG recovered_plaintext_len = sizeof(plaintext);
  rv = g_fns->C_Decrypt(session_, ciphertext, ciphertext_len, recovered_plaintext, &recovered_plaintext_len);
  EXPECT_CKR_OK(rv);
  EXPECT_EQ(plaintext_len, recovered_plaintext_len);
  EXPECT_EQ(0, memcmp(plaintext, recovered_plaintext, plaintext_len));
}

TEST_F(ReadWriteSessionTest, PublicExponent4Bytes) {
  CK_ULONG modulus_bits = 1024;
  CK_BYTE public_exponent_value[] = {0x00, 0x1, 0x0, 0x1}; // 65537=0x00010001
  vector<CK_ATTRIBUTE> public_attrs = {
    {CKA_ENCRYPT},
    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    {CKA_PUBLIC_EXPONENT, public_exponent_value, sizeof(public_exponent_value)},
  };
  vector<CK_ATTRIBUTE> private_attrs = {
    {CKA_DECRYPT},
  };
  CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
  CK_OBJECT_HANDLE public_key = INVALID_OBJECT_HANDLE;
  CK_OBJECT_HANDLE private_key = INVALID_OBJECT_HANDLE;
  EXPECT_CKR_OK(g_fns->C_GenerateKeyPair(session_, &mechanism,
                                         public_attrs.data(), public_attrs.size(),
                                         private_attrs.data(), private_attrs.size(),
                                         &public_key, &private_key));

  // Clean up
  if (public_key != INVALID_OBJECT_HANDLE) {
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, public_key));
  }
  if (private_key != INVALID_OBJECT_HANDLE) {
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, private_key));
  }
}

TEST_F(ReadWriteSessionTest, ExtractKeys) {
  vector<CK_ATTRIBUTE_TYPE> public_attrs = {CKA_ENCRYPT};
  vector<CK_ATTRIBUTE_TYPE> private_attrs = {CKA_DECRYPT, CKA_SENSITIVE};
  KeyPair keypair(session_, public_attrs, private_attrs);

  // Should be able to retrieve the modulus and public exponent.
  CK_BYTE modulus[512];
  CK_BYTE public_exponent[16];
  CK_ATTRIBUTE get_public_attrs[] = {
    {CKA_MODULUS, modulus, sizeof(modulus)},
    {CKA_PUBLIC_EXPONENT, public_exponent, sizeof(public_exponent)},
  };
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, keypair.public_handle(), get_public_attrs, 2));

  // Should not be able to retrieve the private exponent, nor the primes.
  CK_BYTE buffer[1024];
  CK_ATTRIBUTE get_private = {CKA_PRIME_1, buffer, sizeof(buffer)};
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));
  get_private.type = CKA_PRIME_2;
  get_private.ulValueLen = sizeof(buffer);
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));
  get_private.type = CKA_PRIVATE_EXPONENT;
  get_private.ulValueLen = sizeof(buffer);
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));

}

}  // namespace test
}  // namespace pkcs11
<commit_msg>Add test of keypair with asymmetric token status<commit_after>// Copyright 2013-2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// PKCS#11 s11.8: Encryption functions (on asymmetric keys)
//   C_EncryptInit
//   C_Encrypt
//   C_EncryptUpdate
//   C_EncryptFinal
// PKCS#11 s11.9: Decryption functions (on asymmetric keys)
//   C_DecryptInit
//   C_Decrypt
//   C_DecryptUpdate
//   C_DecryptFinal

#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

namespace {

class KeyPairTest : public ReadWriteSessionTest {
 public:
  KeyPairTest()
    : public_attrs_({CKA_ENCRYPT, CKA_TOKEN}),
      private_attrs_({CKA_DECRYPT, CKA_TOKEN}),
      keypair_(session_, public_attrs_, private_attrs_) {}
 protected:
  vector<CK_ATTRIBUTE_TYPE> public_attrs_;
  vector<CK_ATTRIBUTE_TYPE> private_attrs_;
  KeyPair keypair_;
};

}  // namespace

TEST_F(KeyPairTest, EncryptDecrypt) {
  CK_BYTE plaintext[10];
  CK_ULONG plaintext_len = sizeof(plaintext);
  memcpy(plaintext, "0123456789", plaintext_len);
  // First encrypt the data with the public key.
  CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL_PTR, 0};
  CK_RV rv = g_fns->C_EncryptInit(session_, &mechanism, keypair_.public_handle());
  ASSERT_CKR_OK(rv);

  CK_BYTE ciphertext[1024];
  CK_ULONG ciphertext_len = sizeof(ciphertext);
  rv = g_fns->C_Encrypt(session_, plaintext, plaintext_len, ciphertext, &ciphertext_len);
  ASSERT_CKR_OK(rv);
  EXPECT_EQ(128, ciphertext_len);

  // Now decrypt the data with the private key.
  rv = g_fns->C_DecryptInit(session_, &mechanism, keypair_.private_handle());
  ASSERT_CKR_OK(rv);

  CK_BYTE recovered_plaintext[1024];
  CK_ULONG recovered_plaintext_len = sizeof(plaintext);
  rv = g_fns->C_Decrypt(session_, ciphertext, ciphertext_len, recovered_plaintext, &recovered_plaintext_len);
  EXPECT_CKR_OK(rv);
  EXPECT_EQ(plaintext_len, recovered_plaintext_len);
  EXPECT_EQ(0, memcmp(plaintext, recovered_plaintext, plaintext_len));
}

TEST_F(ReadWriteSessionTest, PublicExponent4Bytes) {
  CK_ULONG modulus_bits = 1024;
  CK_BYTE public_exponent_value[] = {0x00, 0x1, 0x0, 0x1}; // 65537=0x00010001
  vector<CK_ATTRIBUTE> public_attrs = {
    {CKA_ENCRYPT},
    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    {CKA_PUBLIC_EXPONENT, public_exponent_value, sizeof(public_exponent_value)},
  };
  vector<CK_ATTRIBUTE> private_attrs = {
    {CKA_DECRYPT},
  };
  CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
  CK_OBJECT_HANDLE public_key = INVALID_OBJECT_HANDLE;
  CK_OBJECT_HANDLE private_key = INVALID_OBJECT_HANDLE;
  EXPECT_CKR_OK(g_fns->C_GenerateKeyPair(session_, &mechanism,
                                         public_attrs.data(), public_attrs.size(),
                                         private_attrs.data(), private_attrs.size(),
                                         &public_key, &private_key));

  // Clean up
  if (public_key != INVALID_OBJECT_HANDLE) {
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, public_key));
  }
  if (private_key != INVALID_OBJECT_HANDLE) {
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, private_key));
  }
}

TEST_F(ReadWriteSessionTest, ExtractKeys) {
  vector<CK_ATTRIBUTE_TYPE> public_attrs = {CKA_ENCRYPT};
  vector<CK_ATTRIBUTE_TYPE> private_attrs = {CKA_DECRYPT, CKA_SENSITIVE};
  KeyPair keypair(session_, public_attrs, private_attrs);

  // Should be able to retrieve the modulus and public exponent.
  CK_BYTE modulus[512];
  CK_BYTE public_exponent[16];
  CK_ATTRIBUTE get_public_attrs[] = {
    {CKA_MODULUS, modulus, sizeof(modulus)},
    {CKA_PUBLIC_EXPONENT, public_exponent, sizeof(public_exponent)},
  };
  EXPECT_CKR_OK(g_fns->C_GetAttributeValue(session_, keypair.public_handle(), get_public_attrs, 2));

  // Should not be able to retrieve the private exponent, nor the primes.
  CK_BYTE buffer[1024];
  CK_ATTRIBUTE get_private = {CKA_PRIME_1, buffer, sizeof(buffer)};
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));
  get_private.type = CKA_PRIME_2;
  get_private.ulValueLen = sizeof(buffer);
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));
  get_private.type = CKA_PRIVATE_EXPONENT;
  get_private.ulValueLen = sizeof(buffer);
  EXPECT_CKR(CKR_ATTRIBUTE_SENSITIVE,
             g_fns->C_GetAttributeValue(session_, keypair.private_handle(), &get_private, 1));

}

TEST_F(ReadWriteSessionTest, AsymmetricTokenKeyPair) {
  // Attempt to create a keypair with the private key on the token but
  // the public key not.
  CK_ULONG modulus_bits = 1024;
  CK_BYTE public_exponent_value[] = {0x1, 0x0, 0x1}; // 65537=0x010001
  CK_ATTRIBUTE public_attrs[] = {
    {CKA_ENCRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_TOKEN, (CK_VOID_PTR)&g_ck_false, sizeof(CK_BBOOL)},
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    {CKA_PUBLIC_EXPONENT, public_exponent_value, sizeof(public_exponent_value)},
  };
  CK_ATTRIBUTE private_attrs[] = {
    {CKA_DECRYPT, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_TOKEN, (CK_VOID_PTR)&g_ck_true, sizeof(CK_BBOOL)},
    {CKA_LABEL, (CK_VOID_PTR)g_label, g_label_len},
  };
  CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
  CK_OBJECT_HANDLE public_key;
  CK_OBJECT_HANDLE private_key;
  CK_RV rv = g_fns->C_GenerateKeyPair(session_, &mechanism,
                                      public_attrs, 5,
                                      private_attrs, 3,
                                      &public_key, &private_key);
  if (rv == CKR_OK) {
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, public_key));
    EXPECT_CKR_OK(g_fns->C_DestroyObject(session_, private_key));
  } else {
    EXPECT_CKR(CKR_TEMPLATE_INCONSISTENT, rv);
  }
}

}  // namespace test
}  // namespace pkcs11
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2015 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include "png.h" // libpng

#include "bitmap/bitmap-exception.hh"
#include "formats/png/file-png.hh"
#include "geo/limits.hh"
#include "text/utf8-string.hh"

#ifdef _MSC_VER
#pragma warning(disable:4611) // _setjmp and C++-object destruction
#endif

namespace faint{

enum class PngReadResult{
  OK,
  ERROR_OPEN_FILE,
  ERROR_PNG_SIGNATURE,
  ERROR_CREATE_READ_STRUCT,
  ERROR_CREATE_INFO_STRUCT,
  ERROR_INIT_IO,
  ERROR_READ_DATA
};

static utf8_string to_string(PngReadResult result){
  // Fixme: Compare error text style with bmp-load errors etc
  using R = PngReadResult;
  if (result == R::OK){
    return "No error";
  }
  else if (result == R::ERROR_OPEN_FILE){
    return "Failed opening file for reading.";
  }
  else if (result == R::ERROR_PNG_SIGNATURE){
    return "Incorrect PNG signature.";
  }
  else if (result == R::ERROR_CREATE_READ_STRUCT){
    return "Failed creating read structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_CREATE_INFO_STRUCT){
    return "Failed creating info structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_INIT_IO){
    return "Failed initializing IO"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_READ_DATA){
    return "Failed reading image data.";
  }
  else{
    return "Unknown error.";
  }
}

PngReadResult read_with_libpng(const char* path,
  png_bytep** rowPointers,
  png_uint_32* width,
  png_uint_32* height,
  png_byte* colorType,
  png_byte* bitDepth)
{
  FILE* f = fopen(path, "rb");
  if (f == nullptr){
    return PngReadResult::ERROR_OPEN_FILE;
  }

  png_byte sig[8];
  size_t readBytes = fread(sig, 1, 8, f);
  if (readBytes != 8){
    return PngReadResult::ERROR_PNG_SIGNATURE;
  }

  if (!png_check_sig(sig, 8)){
    return PngReadResult::ERROR_PNG_SIGNATURE;
  }

  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
    nullptr, nullptr, nullptr);
  if (png_ptr == nullptr){
    return PngReadResult::ERROR_CREATE_READ_STRUCT;
  }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == nullptr){
    return PngReadResult::ERROR_CREATE_INFO_STRUCT;
  }

  if (setjmp(png_jmpbuf(png_ptr))){
    // Fixme: Pass end_info
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return PngReadResult::ERROR_INIT_IO;
  }

  png_init_io(png_ptr, f);
  png_set_sig_bytes(png_ptr, 8);
  png_read_info(png_ptr, info_ptr);

  png_textp textPtr;
  int numText;
  if (png_get_text(png_ptr, info_ptr, &textPtr, &numText) > 0){
    for (int i = 0; i != numText; i++){
      // Fixme: Store somehow
    }
  }

  *width = png_get_image_width(png_ptr, info_ptr);
  *height = png_get_image_height(png_ptr, info_ptr);

  *colorType = png_get_color_type(png_ptr, info_ptr);
  *bitDepth = png_get_bit_depth(png_ptr, info_ptr);

  png_set_interlace_handling(png_ptr); // Fixme: returned num_passes irrelevant?
  png_read_update_info(png_ptr, info_ptr);

  if (setjmp(png_jmpbuf(png_ptr))){
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return PngReadResult::ERROR_READ_DATA;
  }

  (*rowPointers) = (png_bytep*) malloc(sizeof(png_bytep) * (*height));
  for (png_uint_32 y = 0; y < (*height); y++){
    (*rowPointers)[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
  }

  png_read_image(png_ptr, *rowPointers);
  // Fixme: Read post-image-data

  fclose(f);
  png_destroy_read_struct(&png_ptr, nullptr, nullptr); // Maybe
  return PngReadResult::OK;
}

static void free_rows(png_bytep* rowPointers, png_uint_32 height){
  for (png_uint_32 y = 0; y != height; y++){
    free(rowPointers[y]);
  }
  free(rowPointers);
}

OrError<Bitmap> read_png(const FilePath& path){
  png_byte** rowPointers = nullptr;
  png_uint_32 width;
  png_uint_32 height;
  png_byte colorType;
  png_byte bitDepth;
  PngReadResult result = read_with_libpng(path.Str().c_str(),
    &rowPointers,
    &width,
    &height,
    &colorType,
    &bitDepth);

  if (result != PngReadResult::OK){
    return to_string(result);
  }

  if (bitDepth != 8){
    // Fixme: Handle different bit-depths
    free_rows(rowPointers, height);
    return {"Unsupported bit depth"};
  }
  if (colorType != PNG_COLOR_TYPE_RGB_ALPHA){
    // Fixme: Handle different byte-orders
    free_rows(rowPointers, height);
    return {"Unsuppored png color-type"};
  }

  if (!can_represent<IntSize::value_type>(width)){
    return {"Unsupported png-width"};
  }
  if (!can_represent<IntSize::value_type>(height)){
    return {"Unsupported png-height"};
  }

  try {
    Bitmap bmp(IntSize(static_cast<int>(width), static_cast<int>(height)));
    auto* p = bmp.GetRaw();
    auto stride = bmp.GetStride();
    const auto srcBpp = static_cast<png_uint_32>(faint::BPP);

    for (png_uint_32 y = 0; y < height; y++){
      for (png_uint_32 x = 0; x < width; x++){
        auto i =  y * stride + x * srcBpp;
        const auto* row = rowPointers[y];
        p[i + faint::iR] = row[x * 4];
        p[i + faint::iG] = row[x * 4 + 1];
        p[i + faint::iB] = row[x * 4 + 2];
        p[i + faint::iA] = row[x * 4 + 3];
      }
    }
    free_rows(rowPointers, height);
    return bmp;
  }
  catch (const BitmapException& e){
    free_rows(rowPointers, height);
    return {e.what()};
  }
}

enum class PngWriteResult{
  OK,
  ERROR_OPEN_FILE,
  ERROR_CREATE_WRITE_STRUCT,
  ERROR_CREATE_INFO_STRUCT,
  ERROR_INIT_IO,
  ERROR_WRITE_HEADER,
  ERROR_WRITE_DATA,
  ERROR_WRITE_END
};

const utf8_string to_string(PngWriteResult result){
  // Fixme: Compare error text style with bmp-save errors etc
  using R = PngWriteResult;
  if (result == R::OK){
    return "No error.";
  }
  else if (result == R::ERROR_OPEN_FILE){
    return "Failed opening file for writing.";
  }
  else if (result == R::ERROR_CREATE_WRITE_STRUCT){
    return "Failed creating write structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_INIT_IO){
    return "Failed failed initializing IO"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_WRITE_HEADER){
    return "Failed writing header"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_WRITE_DATA){
    return "Failed writing image data";
  }
  else if (result == R::ERROR_WRITE_END){
    return "Failed writing trailer"; // Fixme: Maybe not trailer
  }
  else{
    return "Unknown error.";
  }
}

PngWriteResult write_with_libpng(const char* path, const Bitmap& bmp){
  assert(bitmap_ok(bmp));
  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
    nullptr, nullptr, nullptr);

  if (png_ptr == nullptr){
    return PngWriteResult::ERROR_CREATE_WRITE_STRUCT;
  }

  FILE* f = fopen(path, "wb");
  if (!f){
    return PngWriteResult::ERROR_OPEN_FILE;
  }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == nullptr){
    fclose(f);
    return PngWriteResult::ERROR_CREATE_INFO_STRUCT;
  }

  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_INIT_IO;
  }

  png_init_io(png_ptr, f);

  // Write the PNG-header
  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_WRITE_HEADER;
  }

  auto size(bmp.GetSize());
  assert(size.w != 0 && size.h != 0);
  const png_uint_32 width = convert(size.w);
  const png_uint_32 height = convert(size.h);
  const png_byte bitDepth = 8;
  png_set_IHDR(png_ptr,
    info_ptr,
    width,
    height,
    bitDepth,
    PNG_COLOR_TYPE_RGBA,
    PNG_INTERLACE_NONE,
    PNG_COMPRESSION_TYPE_BASE,
    PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  // Create raw-data arrays for libpng from the Bitmap.
  png_byte** rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  const auto bytesPerRow = png_get_rowbytes(png_ptr, info_ptr);
  assert((width - 1) * 4 + 3 < bytesPerRow);

  const auto* src = bmp.GetRaw();
  const auto stride = bmp.GetStride();
  const auto srcBpp = static_cast<png_uint_32>(faint::BPP);
  for (png_uint_32 y = 0; y != height; y++){
    auto row = (png_byte*) malloc(bytesPerRow);
    rowPointers[y] = row;
    for (png_uint_32 x = 0; x != width; x++){
      // Fill in this row with bitmap-data
      int i = y * stride + x * srcBpp;
      row[x * 4] = src[i + faint::iR];
      row[x * 4 + 1] = src[i + faint::iG];
      row[x * 4 + 2] = src[i + faint::iB];
      row[x * 4 + 3] = src[i + faint::iA];
    }
  }

  //
  // Write the image data
  //
  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_WRITE_DATA;
  }

  png_write_image(png_ptr, rowPointers);

  // Write end
  if (setjmp(png_jmpbuf(png_ptr))){
    free_rows(rowPointers, height);
    return PngWriteResult::ERROR_WRITE_END;
  }
  png_write_end(png_ptr, NULL);

  free_rows(rowPointers, height);
  fclose(f);
  return PngWriteResult::OK;
}

SaveResult write_png(const FilePath& path, const Bitmap& bmp){
  PngWriteResult result = write_with_libpng(path.Str().c_str(), bmp);
  if (result != PngWriteResult::OK){
    return SaveResult::SaveFailed(to_string(result));
  }
  return SaveResult::SaveSuccessful();
}

} // namespace
<commit_msg>Compilation fix, gcc.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2015 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include "png.h" // libpng

#include "bitmap/bitmap-exception.hh"
#include "formats/png/file-png.hh"
#include "geo/limits.hh"
#include "text/utf8-string.hh"

#ifdef _MSC_VER
#pragma warning(disable:4611) // _setjmp and C++-object destruction
#endif

namespace faint{

enum class PngReadResult{
  OK,
  ERROR_OPEN_FILE,
  ERROR_PNG_SIGNATURE,
  ERROR_CREATE_READ_STRUCT,
  ERROR_CREATE_INFO_STRUCT,
  ERROR_INIT_IO,
  ERROR_READ_DATA
};

static utf8_string to_string(PngReadResult result){
  // Fixme: Compare error text style with bmp-load errors etc
  using R = PngReadResult;
  if (result == R::OK){
    return "No error";
  }
  else if (result == R::ERROR_OPEN_FILE){
    return "Failed opening file for reading.";
  }
  else if (result == R::ERROR_PNG_SIGNATURE){
    return "Incorrect PNG signature.";
  }
  else if (result == R::ERROR_CREATE_READ_STRUCT){
    return "Failed creating read structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_CREATE_INFO_STRUCT){
    return "Failed creating info structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_INIT_IO){
    return "Failed initializing IO"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_READ_DATA){
    return "Failed reading image data.";
  }
  else{
    return "Unknown error.";
  }
}

PngReadResult read_with_libpng(const char* path,
  png_bytep** rowPointers,
  png_uint_32* width,
  png_uint_32* height,
  png_byte* colorType,
  png_byte* bitDepth)
{
  FILE* f = fopen(path, "rb");
  if (f == nullptr){
    return PngReadResult::ERROR_OPEN_FILE;
  }

  png_byte sig[8];
  size_t readBytes = fread(sig, 1, 8, f);
  if (readBytes != 8){
    return PngReadResult::ERROR_PNG_SIGNATURE;
  }

  if (!png_check_sig(sig, 8)){
    return PngReadResult::ERROR_PNG_SIGNATURE;
  }

  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
    nullptr, nullptr, nullptr);
  if (png_ptr == nullptr){
    return PngReadResult::ERROR_CREATE_READ_STRUCT;
  }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == nullptr){
    return PngReadResult::ERROR_CREATE_INFO_STRUCT;
  }

  if (setjmp(png_jmpbuf(png_ptr))){
    // Fixme: Pass end_info
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return PngReadResult::ERROR_INIT_IO;
  }

  png_init_io(png_ptr, f);
  png_set_sig_bytes(png_ptr, 8);
  png_read_info(png_ptr, info_ptr);

  png_textp textPtr;
  int numText;
  if (png_get_text(png_ptr, info_ptr, &textPtr, &numText) > 0){
    for (int i = 0; i != numText; i++){
      // Fixme: Store somehow
    }
  }

  *width = png_get_image_width(png_ptr, info_ptr);
  *height = png_get_image_height(png_ptr, info_ptr);

  *colorType = png_get_color_type(png_ptr, info_ptr);
  *bitDepth = png_get_bit_depth(png_ptr, info_ptr);

  png_set_interlace_handling(png_ptr); // Fixme: returned num_passes irrelevant?
  png_read_update_info(png_ptr, info_ptr);

  if (setjmp(png_jmpbuf(png_ptr))){
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return PngReadResult::ERROR_READ_DATA;
  }

  (*rowPointers) = (png_bytep*) malloc(sizeof(png_bytep) * (*height));
  for (png_uint_32 y = 0; y < (*height); y++){
    (*rowPointers)[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
  }

  png_read_image(png_ptr, *rowPointers);
  // Fixme: Read post-image-data

  fclose(f);
  png_destroy_read_struct(&png_ptr, nullptr, nullptr); // Maybe
  return PngReadResult::OK;
}

static void free_rows(png_bytep* rowPointers, png_uint_32 height){
  for (png_uint_32 y = 0; y != height; y++){
    free(rowPointers[y]);
  }
  free(rowPointers);
}

OrError<Bitmap> read_png(const FilePath& path){
  png_byte** rowPointers = nullptr;
  png_uint_32 width;
  png_uint_32 height;
  png_byte colorType;
  png_byte bitDepth;
  PngReadResult result = read_with_libpng(path.Str().c_str(),
    &rowPointers,
    &width,
    &height,
    &colorType,
    &bitDepth);

  if (result != PngReadResult::OK){
    return to_string(result);
  }

  if (bitDepth != 8){
    // Fixme: Handle different bit-depths
    free_rows(rowPointers, height);
    return {"Unsupported bit depth"};
  }
  if (colorType != PNG_COLOR_TYPE_RGB_ALPHA){
    // Fixme: Handle different byte-orders
    free_rows(rowPointers, height);
    return {"Unsuppored png color-type"};
  }

  if (!can_represent<IntSize::value_type>(width)){
    return {"Unsupported png-width"};
  }
  if (!can_represent<IntSize::value_type>(height)){
    return {"Unsupported png-height"};
  }

  try {
    Bitmap bmp(IntSize(static_cast<int>(width), static_cast<int>(height)));
    auto* p = bmp.GetRaw();
    const png_uint_32 stride = convert(bmp.GetStride());
    const png_uint_32 srcBpp = convert(faint::BPP);

    for (png_uint_32 y = 0; y < height; y++){
      for (png_uint_32 x = 0; x < width; x++){
        auto i =  y * stride + x * srcBpp;
        const auto* row = rowPointers[y];
        p[i + faint::iR] = row[x * 4];
        p[i + faint::iG] = row[x * 4 + 1];
        p[i + faint::iB] = row[x * 4 + 2];
        p[i + faint::iA] = row[x * 4 + 3];
      }
    }
    free_rows(rowPointers, height);
    return bmp;
  }
  catch (const BitmapException& e){
    free_rows(rowPointers, height);
    return {e.what()};
  }
}

enum class PngWriteResult{
  OK,
  ERROR_OPEN_FILE,
  ERROR_CREATE_WRITE_STRUCT,
  ERROR_CREATE_INFO_STRUCT,
  ERROR_INIT_IO,
  ERROR_WRITE_HEADER,
  ERROR_WRITE_DATA,
  ERROR_WRITE_END
};

const utf8_string to_string(PngWriteResult result){
  // Fixme: Compare error text style with bmp-save errors etc
  using R = PngWriteResult;
  if (result == R::OK){
    return "No error.";
  }
  else if (result == R::ERROR_OPEN_FILE){
    return "Failed opening file for writing.";
  }
  else if (result == R::ERROR_CREATE_WRITE_STRUCT){
    return "Failed creating write structure"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_INIT_IO){
    return "Failed failed initializing IO"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_WRITE_HEADER){
    return "Failed writing header"; // Fixme: Memory? Png init?
  }
  else if (result == R::ERROR_WRITE_DATA){
    return "Failed writing image data";
  }
  else if (result == R::ERROR_WRITE_END){
    return "Failed writing trailer"; // Fixme: Maybe not trailer
  }
  else{
    return "Unknown error.";
  }
}

PngWriteResult write_with_libpng(const char* path, const Bitmap& bmp){
  assert(bitmap_ok(bmp));
  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
    nullptr, nullptr, nullptr);

  if (png_ptr == nullptr){
    return PngWriteResult::ERROR_CREATE_WRITE_STRUCT;
  }

  FILE* f = fopen(path, "wb");
  if (!f){
    return PngWriteResult::ERROR_OPEN_FILE;
  }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == nullptr){
    fclose(f);
    return PngWriteResult::ERROR_CREATE_INFO_STRUCT;
  }

  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_INIT_IO;
  }

  png_init_io(png_ptr, f);

  // Write the PNG-header
  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_WRITE_HEADER;
  }

  auto size(bmp.GetSize());
  assert(size.w != 0 && size.h != 0);
  const png_uint_32 width = convert(size.w);
  const png_uint_32 height = convert(size.h);
  const png_byte bitDepth = 8;
  png_set_IHDR(png_ptr,
    info_ptr,
    width,
    height,
    bitDepth,
    PNG_COLOR_TYPE_RGBA,
    PNG_INTERLACE_NONE,
    PNG_COMPRESSION_TYPE_BASE,
    PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  // Create raw-data arrays for libpng from the Bitmap.
  png_byte** rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  const auto bytesPerRow = png_get_rowbytes(png_ptr, info_ptr);
  assert((width - 1) * 4 + 3 < bytesPerRow);

  const auto* src = bmp.GetRaw();
  const png_uint_32 stride = convert(bmp.GetStride());
  const png_uint_32 srcBpp = convert(faint::BPP);
  for (png_uint_32 y = 0; y != height; y++){
    auto row = (png_byte*) malloc(bytesPerRow);
    rowPointers[y] = row;
    for (png_uint_32 x = 0; x != width; x++){
      // Fill in this row with bitmap-data
      auto i = y * stride + x * srcBpp;
      row[x * 4] = src[i + faint::iR];
      row[x * 4 + 1] = src[i + faint::iG];
      row[x * 4 + 2] = src[i + faint::iB];
      row[x * 4 + 3] = src[i + faint::iA];
    }
  }

  //
  // Write the image data
  //
  if (setjmp(png_jmpbuf(png_ptr))){
    fclose(f);
    return PngWriteResult::ERROR_WRITE_DATA;
  }

  png_write_image(png_ptr, rowPointers);

  // Write end
  if (setjmp(png_jmpbuf(png_ptr))){
    free_rows(rowPointers, height);
    return PngWriteResult::ERROR_WRITE_END;
  }
  png_write_end(png_ptr, NULL);

  free_rows(rowPointers, height);
  fclose(f);
  return PngWriteResult::OK;
}

SaveResult write_png(const FilePath& path, const Bitmap& bmp){
  PngWriteResult result = write_with_libpng(path.Str().c_str(), bmp);
  if (result != PngWriteResult::OK){
    return SaveResult::SaveFailed(to_string(result));
  }
  return SaveResult::SaveSuccessful();
}

} // namespace
<|endoftext|>


<commit_before><commit_msg>fdo#56776: Change in formula options should cause repaint.<commit_after><|endoftext|>