<commit_before>/*
 * File:   main.cpp
 * Author: janvojt
 *
 * Created on May 29, 2014, 9:53 PM
 */

#include <cstdlib>
#include <string.h>
#include <iostream>
#include <getopt.h>

#include "NetworkConfiguration.h"
#include "Network.h"
#include "activationFunctions.h"
#include "BackpropagationLearner.h"
#include "SimpleLabeledDataset.h"
#include "MseErrorComputer.h"

#include "log/LoggerFactory.h"
#include "log4cpp/Category.hh"
#include "log4cpp/Priority.hh"
#include "LabeledDatasetParser.h"
#include "SimpleInputDataset.h"
#include "InputDatasetParser.h"

// getopts constants
#define no_argument 0
#define required_argument 1
#define optional_argument 2

using namespace std;

/* Application long options. */
const struct option optsLong[] = {
    {"help", no_argument, 0, 'h'},
    {"no-bias", no_argument, 0, 'b'},
    {"mse", required_argument, 0, 'e'},
    {"max-epochs", required_argument, 0, 'm'},
    {"func", required_argument, 0, 'f'},
    {"d-func", required_argument, 0, 'g'},
    {"init", required_argument, 0, 'i'},
    {"lconf", required_argument, 0, 'l'},
    {"labels", required_argument, 0, 's'},
    {"test", required_argument, 0, 't'},
    {"random-seed", required_argument, 0, 'r'},
    {"debug", no_argument, 0, 'd'},
    {0, 0, 0, 0},
};

/* Application short options. */
const char* optsList = "hbe:m:f:g:i:l:s:t:r:d";

/* Application configuration. */
struct config {
    /* mean square error */
    double mse = .0001;
    /* use bias? */
    bool bias = true;
    /* epoch limit */
    long maxEpochs = 1000000;
    /* Weights and bias initialization. */
    bool initRandom = true;
    double initWeights = 0;
    /* Layer configuration. */
    char* layerConf;
    /* File path with labeled data. */
    char* labeledData;
    /* File path with test data. */
    char* testData;
    /* Seed for random generator. */
    int seed;
    /* activation function */
    void (*activationFnc)(double *x, double *y, int layerSize);
    /* derivative of activation function */
    void (*dActivationFnc)(double *x, double *y, int layerSize);
};

void printOutput(Network *net) {

    // print input
    cout << "[ ";
    double *in = net->getInput();
    int iNeurons = net->getInputNeurons();
    cout << *in++;
    for (int i = 1; i<iNeurons; i++) {
        cout << ", " << *in;
        in++;
    }
    cout << " ] -> ";

    // print output
    cout << "[ ";
    double *out = net->getOutput();
    int oNeurons = net->getOutputNeurons();

    cout << *out++;
    for (int i = 1; i<oNeurons; i++) {
        cout << ", " << *out;
        out++;
    }
    cout << " ]" << endl;
}

void printSeperator() {
    cout << endl;
    cout << "################################################################################" << endl;
    cout << endl;
}

/* Runs the given test dataset through given network and prints results. */
void runTest(Network *net, InputDataset *ds) {
    ds->reset();
    while (ds->hasNext()) {
        net->setInput(ds->next());
        net->run();
        printOutput(net);
    }
}

LabeledDataset* createXorDataset() {
    SimpleLabeledDataset *ds = new SimpleLabeledDataset(2, 1, 4);

    ds->addPattern((const double[2]){0, 0}, (const double[1]){0});
    ds->addPattern((const double[2]){0, 1}, (const double[1]){1});
    ds->addPattern((const double[2]){1, 0}, (const double[1]){1});
    ds->addPattern((const double[2]){1, 1}, (const double[1]){0});

    return (LabeledDataset*)ds;
}

void printHelp() {
    cout << "Usage: xoraan [OPTIONS]" << endl << endl;
    cout << "Option      GNU long option       Meaning" << endl;
    cout << "--------------------------------------------------------------------------------" << endl;
    cout << "-h          --help                This help." << endl;
    cout << "-b          --no-bias             Disables bias in neural network. Bias is enabled by default." << endl;
    cout << "-e <value>  --mse <value>         Target Mean Square Error to determine when to finish the learning." << endl;
    cout << "-m <value>  --max-epochs <value>  Sets a maximum limit for number of epochs. Learning is stopped even if MSE has not been met." << endl;
    cout << "-f <value>  --func <value>        Specifies the activation function to be used. Use 's' for sigmoid, 'h' for hyperbolic tangent. Sigmoid is the default." << endl;
    cout << "-g <value>  --d-func <value>      Specifies the derivative of activation function to be used. Use 's' for sigmoid, 'h' for hyperbolic tangent. Sigmoid is the default." << endl;
    cout << "-i <value>  --init <value>        Specifies the value all weights and biases should be initialized to. By default random initialization is used." << endl;
    cout << "-l <value>  --lconf <value>       Specifies layer configuration for the network as a comma separated list of integers." << endl;
    cout << "-s <value>  --labels <value>      File path with labeled data to be used for learning." << endl;
    cout << "-t <value>  --test <value>        File path with test data to be used for evaluating networks performance." << endl;
    cout << "-r <value>  --random-seed <value> Specifies value to be used for seeding random generator." << endl;
    cout << "-d          --debug               Enable debugging messages." << endl;
}

/* Process command line options and return generated configuration. */
config* processOptions(int argc, char *argv[]) {

    config* conf = new config;

    // set defaults
    conf->activationFnc = sigmoidFunction;
    conf->dActivationFnc = dSigmoidFunction;
    conf->layerConf = (char*) "2,2,1";

    int index;
    int iarg = 0;
    while (iarg != -1) {
        iarg = getopt_long(argc, argv, optsList, optsLong, &index);

        switch (iarg) {
            case 'h':
                printHelp();
                exit(0);
            case 'd' :
                LOG()->setPriority(log4cpp::Priority::DEBUG);
                break;
            case 'b':
                conf->bias = false;
                break;
            case 'e':
                conf->mse = atof(optarg);
                break;
            case 'm' :
                conf->maxEpochs = atoi(optarg);
                break;
            case 'i' :
                conf->initWeights = atof(optarg);
                conf->initRandom = false;
            case 'l' :
                conf->layerConf = new char[strlen(optarg)];
                strcpy(conf->layerConf, optarg);
                break;
            case 's' :
                conf->labeledData = optarg;
                break;
            case 't' :
                conf->testData = optarg;
                break;
            case 'r' :
                conf->seed = atoi(optarg);
                break;
            case 'f' :
                switch (optarg[0]) {
                    case 's' :
                        conf->activationFnc = sigmoidFunction;
                        break;
                    case 'h' :
                        conf->activationFnc = hyperbolicTangentFunction;
                        break;
                    default :
                        LOG()->warn("Unknown activation function %s, falling back to sigmoid.", optarg);
                        conf->activationFnc = sigmoidFunction;
                        break;
                }
                break;
            case 'g' :
                switch (optarg[0]) {
                    case 's' :
                        conf->dActivationFnc = dSigmoidFunction;
                        break;
                    case 'h' :
                        conf->dActivationFnc = dHyperbolicTangentFunction;
                        break;
                    default :
                        LOG()->warn("Unknown derivative of activation function %s, falling back to sigmoid derivative.", optarg);
                        conf->dActivationFnc = dSigmoidFunction;
                        break;
                }
                break;
        }
    }

    return conf;
}

/* Entry point of the application. */
int main(int argc, char *argv[]) {

    config* conf = processOptions(argc, argv);

    // Seed random generator before initializing weights.
    if (conf->seed == NULL) {
        srand(time(0));
    } else {
        srand(conf->seed);
    }

    // Setup network configuration.
    NetworkConfiguration *netConf = new NetworkConfiguration();
    netConf->parseLayerConf(conf->layerConf);
    netConf->activationFnc = conf->activationFnc;
    netConf->dActivationFnc = conf->dActivationFnc;
    netConf->setBias(conf->bias);
    netConf->setInitRandom(conf->initRandom);
    netConf->setInitWeights(conf->initWeights);

    Network *net = new Network(netConf);

    // Prepare test dataset.
    InputDataset *tds;
    if (conf->testData == NULL) {
        SimpleInputDataset *d = new SimpleInputDataset(2, 4);
        d->addInput((const double[2]){0, 0});
        d->addInput((const double[2]){0, 1});
        d->addInput((const double[2]){1, 0});
        d->addInput((const double[2]){1, 1});
        tds = (InputDataset *) d;
    } else {
        InputDatasetParser *p = new InputDatasetParser(conf->testData, netConf);
        tds = p->parse();
        delete p;
    }

    // Run network without learning.
    runTest(net, tds);
    printSeperator();

    // Prepare labeled dataset.
    // If none was provided in options use XOR dataset by default.
    LabeledDataset *ds;
    if (conf->labeledData == NULL) {
        ds = createXorDataset();
    } else {
        LabeledDatasetParser *p = new LabeledDatasetParser(conf->labeledData, netConf);
        ds = p->parse();
        delete p;
    }

    BackpropagationLearner *bp = new BackpropagationLearner(net);
    bp->setTargetMse(conf->mse);
    bp->setErrorComputer(new MseErrorComputer());
    bp->setEpochLimit(conf->maxEpochs);
    bp->train(ds);

    // Run (hopefully) learnt network.
    runTest(net, tds);

    delete bp;
    delete ds;
    delete tds;
    delete netConf;
    delete conf;
    delete net;
    return 0;
}

<commit_msg>Decreased default epoc limit (1,000,000 -> 100,000).<commit_after>/*
 * File:   main.cpp
 * Author: janvojt
 *
 * Created on May 29, 2014, 9:53 PM
 */

#include <cstdlib>
#include <string.h>
#include <iostream>
#include <getopt.h>

#include "NetworkConfiguration.h"
#include "Network.h"
#include "activationFunctions.h"
#include "BackpropagationLearner.h"
#include "SimpleLabeledDataset.h"
#include "MseErrorComputer.h"

#include "log/LoggerFactory.h"
#include "log4cpp/Category.hh"
#include "log4cpp/Priority.hh"
#include "LabeledDatasetParser.h"
#include "SimpleInputDataset.h"
#include "InputDatasetParser.h"

// getopts constants
#define no_argument 0
#define required_argument 1
#define optional_argument 2

using namespace std;

/* Application long options. */
const struct option optsLong[] = {
    {"help", no_argument, 0, 'h'},
    {"no-bias", no_argument, 0, 'b'},
    {"mse", required_argument, 0, 'e'},
    {"max-epochs", required_argument, 0, 'm'},
    {"func", required_argument, 0, 'f'},
    {"d-func", required_argument, 0, 'g'},
    {"init", required_argument, 0, 'i'},
    {"lconf", required_argument, 0, 'l'},
    {"labels", required_argument, 0, 's'},
    {"test", required_argument, 0, 't'},
    {"random-seed", required_argument, 0, 'r'},
    {"debug", no_argument, 0, 'd'},
    {0, 0, 0, 0},
};

/* Application short options. */
const char* optsList = "hbe:m:f:g:i:l:s:t:r:d";

/* Application configuration. */
struct config {
    /* mean square error */
    double mse = .0001;
    /* use bias? */
    bool bias = true;
    /* epoch limit */
    long maxEpochs = 100000;
    /* Weights and bias initialization. */
    bool initRandom = true;
    double initWeights = 0;
    /* Layer configuration. */
    char* layerConf;
    /* File path with labeled data. */
    char* labeledData;
    /* File path with test data. */
    char* testData;
    /* Seed for random generator. */
    int seed;
    /* activation function */
    void (*activationFnc)(double *x, double *y, int layerSize);
    /* derivative of activation function */
    void (*dActivationFnc)(double *x, double *y, int layerSize);
};

void printOutput(Network *net) {

    // print input
    cout << "[ ";
    double *in = net->getInput();
    int iNeurons = net->getInputNeurons();
    cout << *in++;
    for (int i = 1; i<iNeurons; i++) {
        cout << ", " << *in;
        in++;
    }
    cout << " ] -> ";

    // print output
    cout << "[ ";
    double *out = net->getOutput();
    int oNeurons = net->getOutputNeurons();

    cout << *out++;
    for (int i = 1; i<oNeurons; i++) {
        cout << ", " << *out;
        out++;
    }
    cout << " ]" << endl;
}

void printSeperator() {
    cout << endl;
    cout << "################################################################################" << endl;
    cout << endl;
}

/* Runs the given test dataset through given network and prints results. */
void runTest(Network *net, InputDataset *ds) {
    ds->reset();
    while (ds->hasNext()) {
        net->setInput(ds->next());
        net->run();
        printOutput(net);
    }
}

LabeledDataset* createXorDataset() {
    SimpleLabeledDataset *ds = new SimpleLabeledDataset(2, 1, 4);

    ds->addPattern((const double[2]){0, 0}, (const double[1]){0});
    ds->addPattern((const double[2]){0, 1}, (const double[1]){1});
    ds->addPattern((const double[2]){1, 0}, (const double[1]){1});
    ds->addPattern((const double[2]){1, 1}, (const double[1]){0});

    return (LabeledDataset*)ds;
}

void printHelp() {
    cout << "Usage: xoraan [OPTIONS]" << endl << endl;
    cout << "Option      GNU long option       Meaning" << endl;
    cout << "--------------------------------------------------------------------------------" << endl;
    cout << "-h          --help                This help." << endl;
    cout << "-b          --no-bias             Disables bias in neural network. Bias is enabled by default." << endl;
    cout << "-e <value>  --mse <value>         Target Mean Square Error to determine when to finish the learning." << endl;
    cout << "-m <value>  --max-epochs <value>  Sets a maximum limit for number of epochs. Learning is stopped even if MSE has not been met. Default is 100,000" << endl;
    cout << "-f <value>  --func <value>        Specifies the activation function to be used. Use 's' for sigmoid, 'h' for hyperbolic tangent. Sigmoid is the default." << endl;
    cout << "-g <value>  --d-func <value>      Specifies the derivative of activation function to be used. Use 's' for sigmoid, 'h' for hyperbolic tangent. Sigmoid is the default." << endl;
    cout << "-i <value>  --init <value>        Specifies the value all weights and biases should be initialized to. By default random initialization is used." << endl;
    cout << "-l <value>  --lconf <value>       Specifies layer configuration for the network as a comma separated list of integers." << endl;
    cout << "-s <value>  --labels <value>      File path with labeled data to be used for learning." << endl;
    cout << "-t <value>  --test <value>        File path with test data to be used for evaluating networks performance." << endl;
    cout << "-r <value>  --random-seed <value> Specifies value to be used for seeding random generator." << endl;
    cout << "-d          --debug               Enable debugging messages." << endl;
}

/* Process command line options and return generated configuration. */
config* processOptions(int argc, char *argv[]) {

    config* conf = new config;

    // set defaults
    conf->activationFnc = sigmoidFunction;
    conf->dActivationFnc = dSigmoidFunction;
    conf->layerConf = (char*) "2,2,1";

    int index;
    int iarg = 0;
    while (iarg != -1) {
        iarg = getopt_long(argc, argv, optsList, optsLong, &index);

        switch (iarg) {
            case 'h':
                printHelp();
                exit(0);
            case 'd' :
                LOG()->setPriority(log4cpp::Priority::DEBUG);
                break;
            case 'b':
                conf->bias = false;
                break;
            case 'e':
                conf->mse = atof(optarg);
                break;
            case 'm' :
                conf->maxEpochs = atoi(optarg);
                break;
            case 'i' :
                conf->initWeights = atof(optarg);
                conf->initRandom = false;
            case 'l' :
                conf->layerConf = new char[strlen(optarg)];
                strcpy(conf->layerConf, optarg);
                break;
            case 's' :
                conf->labeledData = optarg;
                break;
            case 't' :
                conf->testData = optarg;
                break;
            case 'r' :
                conf->seed = atoi(optarg);
                break;
            case 'f' :
                switch (optarg[0]) {
                    case 's' :
                        conf->activationFnc = sigmoidFunction;
                        break;
                    case 'h' :
                        conf->activationFnc = hyperbolicTangentFunction;
                        break;
                    default :
                        LOG()->warn("Unknown activation function %s, falling back to sigmoid.", optarg);
                        conf->activationFnc = sigmoidFunction;
                        break;
                }
                break;
            case 'g' :
                switch (optarg[0]) {
                    case 's' :
                        conf->dActivationFnc = dSigmoidFunction;
                        break;
                    case 'h' :
                        conf->dActivationFnc = dHyperbolicTangentFunction;
                        break;
                    default :
                        LOG()->warn("Unknown derivative of activation function %s, falling back to sigmoid derivative.", optarg);
                        conf->dActivationFnc = dSigmoidFunction;
                        break;
                }
                break;
        }
    }

    return conf;
}

/* Entry point of the application. */
int main(int argc, char *argv[]) {

    config* conf = processOptions(argc, argv);

    // Seed random generator before initializing weights.
    if (conf->seed == NULL) {
        srand(time(0));
    } else {
        srand(conf->seed);
    }

    // Setup network configuration.
    NetworkConfiguration *netConf = new NetworkConfiguration();
    netConf->parseLayerConf(conf->layerConf);
    netConf->activationFnc = conf->activationFnc;
    netConf->dActivationFnc = conf->dActivationFnc;
    netConf->setBias(conf->bias);
    netConf->setInitRandom(conf->initRandom);
    netConf->setInitWeights(conf->initWeights);

    Network *net = new Network(netConf);

    // Prepare test dataset.
    InputDataset *tds;
    if (conf->testData == NULL) {
        SimpleInputDataset *d = new SimpleInputDataset(2, 4);
        d->addInput((const double[2]){0, 0});
        d->addInput((const double[2]){0, 1});
        d->addInput((const double[2]){1, 0});
        d->addInput((const double[2]){1, 1});
        tds = (InputDataset *) d;
    } else {
        InputDatasetParser *p = new InputDatasetParser(conf->testData, netConf);
        tds = p->parse();
        delete p;
    }

    // Run network without learning.
    runTest(net, tds);
    printSeperator();

    // Prepare labeled dataset.
    // If none was provided in options use XOR dataset by default.
    LabeledDataset *ds;
    if (conf->labeledData == NULL) {
        ds = createXorDataset();
    } else {
        LabeledDatasetParser *p = new LabeledDatasetParser(conf->labeledData, netConf);
        ds = p->parse();
        delete p;
    }

    BackpropagationLearner *bp = new BackpropagationLearner(net);
    bp->setTargetMse(conf->mse);
    bp->setErrorComputer(new MseErrorComputer());
    bp->setEpochLimit(conf->maxEpochs);
    bp->train(ds);

    // Run (hopefully) learnt network.
    runTest(net, tds);

    delete bp;
    delete ds;
    delete tds;
    delete netConf;
    delete conf;
    delete net;
    return 0;
}

<|endoftext|>


<commit_before>#ifndef VENTURA_RUN_PROCESS_HPP
#define VENTURA_RUN_PROCESS_HPP

#include <ventura/async_process.hpp>
#include <silicium/write.hpp>
#include <silicium/sink/multi_sink.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/sink/copy.hpp>
#include <silicium/source/range_source.hpp>
#include <silicium/source/transforming_source.hpp>
#include <boost/range/algorithm/transform.hpp>

namespace ventura
{
	template <class T>
	bool extract(T &destination, Si::optional<T> &&source)
	{
		if (source)
		{
			destination = std::forward<T>(*source);
			return true;
		}
		return false;
	}
}

#define VENTURA_HAS_RUN_PROCESS                                                                                \
	(SILICIUM_HAS_EXCEPTIONS && VENTURA_HAS_EXPERIMENTAL_READ_FROM_ANONYMOUS_PIPE && VENTURA_HAS_LAUNCH_PROCESS)

#if VENTURA_HAS_RUN_PROCESS
#include <future>

namespace ventura
{
	namespace detail
	{
		inline Si::error_or<Si::pipe> make_pipe() BOOST_NOEXCEPT
		{
#ifdef _WIN32
			SECURITY_ATTRIBUTES security = {};
			security.nLength = sizeof(security);
			security.bInheritHandle = FALSE;
			HANDLE read, write;
			if (!CreatePipe(&read, &write, &security, 0))
			{
				return Si::get_last_error();
			}
			Si::pipe result;
			result.read = Si::file_handle(read);
			result.write = Si::file_handle(write);
			return std::move(result);
#else
			return Si::make_pipe();
#endif
		}

		inline Si::file_handle enable_inheritance(Si::file_handle original)
		{
#ifdef _WIN32
			HANDLE enabled = INVALID_HANDLE_VALUE;
			if (!DuplicateHandle(GetCurrentProcess(), original.release(), GetCurrentProcess(), &enabled, 0, TRUE,
			                     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
			{
				assert(enabled == INVALID_HANDLE_VALUE);
				Si::throw_last_error();
			}
			return Si::file_handle(enabled);
#else
			return original;
#endif
		}
	}

	inline Si::error_or<int> run_process(process_parameters const &parameters)
	{
		async_process_parameters async_parameters;
		async_parameters.executable = parameters.executable;
		async_parameters.arguments = parameters.arguments;
		async_parameters.current_path = parameters.current_path;
		auto input = detail::make_pipe().move_value();
		auto std_output = detail::make_pipe().move_value();
		auto std_error = detail::make_pipe().move_value();

		Si::file_handle inheritable_stdin_read = detail::enable_inheritance(std::move(input.read));
		Si::file_handle inheritable_stdout_write = detail::enable_inheritance(std::move(std_output.write));
		Si::file_handle inheritable_stderr_write = detail::enable_inheritance(std::move(std_error.write));
		async_process process =
		    launch_process(async_parameters, inheritable_stdin_read.handle, inheritable_stdout_write.handle,
		                   inheritable_stderr_write.handle, parameters.additional_environment, parameters.inheritance)
		        .move_value();

		inheritable_stdin_read.close();
		inheritable_stdout_write.close();
		inheritable_stderr_write.close();

		boost::asio::io_service io;

		boost::promise<void> stop_polling;
		boost::shared_future<void> stopped_polling = stop_polling.get_future().share();

		auto std_output_consumer = Si::make_multi_sink<char, Si::success>(
		    [&parameters]()
		    {
			    return Si::make_iterator_range(&parameters.out, &parameters.out + (parameters.out != nullptr));
			});
		auto stdout_finished = experimental::read_from_anonymous_pipe(io, std_output_consumer,
		                                                              std::move(std_output.read), stopped_polling);

		auto std_error_consumer = Si::make_multi_sink<char, Si::success>(
		    [&parameters]()
		    {
			    return Si::make_iterator_range(&parameters.err, &parameters.err + (parameters.err != nullptr));
			});
		auto stderr_finished =
		    experimental::read_from_anonymous_pipe(io, std_error_consumer, std::move(std_error.read), stopped_polling);

		auto copy_input = std::async(std::launch::async, [&input, &parameters]()
		                             {
			                             if (!parameters.in)
			                             {
				                             return;
			                             }
			                             for (;;)
			                             {
				                             Si::optional<char> const c = Si::get(*parameters.in);
				                             if (!c)
				                             {
					                             break;
				                             }
				                             Si::error_or<size_t> written =
				                                 write(input.write.handle, Si::make_memory_range(&*c, 1));
				                             if (written.is_error())
				                             {
					                             // process must have exited
					                             break;
				                             }
				                             assert(written.get() == 1);
			                             }
#ifdef _WIN32
			                             // do not know whether this is necessary
			                             BOOL flushed = FlushFileBuffers(input.write.handle);
#endif
			                             input.write.close();
			                         });

		io.run();
		copy_input.get();
		stdout_finished.get();
		stderr_finished.get();
		return process.wait_for_exit();
	}

#ifdef _WIN32
	SILICIUM_USE_RESULT
	inline Si::error_or<int>
	run_process(absolute_path executable, std::vector<Si::os_string> arguments, absolute_path current_directory,
	            Si::Sink<char, Si::success>::interface &output,
	            std::vector<std::pair<Si::os_char const *, Si::os_char const *>> additional_environment,
	            environment_inheritance inheritance)
	{
		process_parameters parameters;
		parameters.executable = std::move(executable);
		parameters.arguments = std::move(arguments);
		parameters.current_path = std::move(current_directory);
		parameters.out = &output;
		parameters.err = &output;
		parameters.additional_environment = std::move(additional_environment);
		parameters.inheritance = inheritance;
		return run_process(parameters);
	}
#endif

	SILICIUM_USE_RESULT
	inline std::vector<Si::os_string> arguments_to_os_strings(std::vector<Si::noexcept_string> const &arguments)
	{
		std::vector<Si::os_string> new_arguments;
		{
			auto new_arguments_sink = Si::make_container_sink(new_arguments);
			auto arguments_encoder =
			    Si::make_transforming_source(Si::make_range_source(Si::make_contiguous_range(arguments)),
			                                 [](Si::noexcept_string const &in) -> Si::os_string
			                                 {
				                                 // TODO: mvoe the string if possible
				                                 return Si::to_os_string(in);
				                             });
			Si::copy(arguments_encoder, new_arguments_sink);
		}
		return new_arguments;
	}

	SILICIUM_USE_RESULT
	inline Si::error_or<int>
	run_process(absolute_path executable, std::vector<Si::noexcept_string> arguments, absolute_path current_directory,
	            Si::Sink<char, Si::success>::interface &output,
	            std::vector<std::pair<Si::os_char const *, Si::os_char const *>> additional_environment,
	            environment_inheritance inheritance)
	{
		process_parameters parameters;
		parameters.executable = std::move(executable);
		std::vector<Si::os_string> new_arguments = arguments_to_os_strings(arguments);
		parameters.arguments = std::move(new_arguments);
		parameters.current_path = std::move(current_directory);
		parameters.out = &output;
		parameters.err = &output;
		parameters.additional_environment = std::move(additional_environment);
		parameters.inheritance = inheritance;
		return run_process(parameters);
	}
}
#endif

#endif
<commit_msg>FlushFileBuffers is probably not necessary<commit_after>#ifndef VENTURA_RUN_PROCESS_HPP
#define VENTURA_RUN_PROCESS_HPP

#include <ventura/async_process.hpp>
#include <silicium/write.hpp>
#include <silicium/sink/multi_sink.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/sink/copy.hpp>
#include <silicium/source/range_source.hpp>
#include <silicium/source/transforming_source.hpp>
#include <boost/range/algorithm/transform.hpp>

namespace ventura
{
	template <class T>
	bool extract(T &destination, Si::optional<T> &&source)
	{
		if (source)
		{
			destination = std::forward<T>(*source);
			return true;
		}
		return false;
	}
}

#define VENTURA_HAS_RUN_PROCESS                                                                                \
	(SILICIUM_HAS_EXCEPTIONS && VENTURA_HAS_EXPERIMENTAL_READ_FROM_ANONYMOUS_PIPE && VENTURA_HAS_LAUNCH_PROCESS)

#if VENTURA_HAS_RUN_PROCESS
#include <future>

namespace ventura
{
	namespace detail
	{
		inline Si::error_or<Si::pipe> make_pipe() BOOST_NOEXCEPT
		{
#ifdef _WIN32
			SECURITY_ATTRIBUTES security = {};
			security.nLength = sizeof(security);
			security.bInheritHandle = FALSE;
			HANDLE read, write;
			if (!CreatePipe(&read, &write, &security, 0))
			{
				return Si::get_last_error();
			}
			Si::pipe result;
			result.read = Si::file_handle(read);
			result.write = Si::file_handle(write);
			return std::move(result);
#else
			return Si::make_pipe();
#endif
		}

		inline Si::file_handle enable_inheritance(Si::file_handle original)
		{
#ifdef _WIN32
			HANDLE enabled = INVALID_HANDLE_VALUE;
			if (!DuplicateHandle(GetCurrentProcess(), original.release(), GetCurrentProcess(), &enabled, 0, TRUE,
			                     DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
			{
				assert(enabled == INVALID_HANDLE_VALUE);
				Si::throw_last_error();
			}
			return Si::file_handle(enabled);
#else
			return original;
#endif
		}
	}

	inline Si::error_or<int> run_process(process_parameters const &parameters)
	{
		async_process_parameters async_parameters;
		async_parameters.executable = parameters.executable;
		async_parameters.arguments = parameters.arguments;
		async_parameters.current_path = parameters.current_path;
		auto input = detail::make_pipe().move_value();
		auto std_output = detail::make_pipe().move_value();
		auto std_error = detail::make_pipe().move_value();

		Si::file_handle inheritable_stdin_read = detail::enable_inheritance(std::move(input.read));
		Si::file_handle inheritable_stdout_write = detail::enable_inheritance(std::move(std_output.write));
		Si::file_handle inheritable_stderr_write = detail::enable_inheritance(std::move(std_error.write));
		async_process process =
		    launch_process(async_parameters, inheritable_stdin_read.handle, inheritable_stdout_write.handle,
		                   inheritable_stderr_write.handle, parameters.additional_environment, parameters.inheritance)
		        .move_value();

		inheritable_stdin_read.close();
		inheritable_stdout_write.close();
		inheritable_stderr_write.close();

		boost::asio::io_service io;

		boost::promise<void> stop_polling;
		boost::shared_future<void> stopped_polling = stop_polling.get_future().share();

		auto std_output_consumer = Si::make_multi_sink<char, Si::success>(
		    [&parameters]()
		    {
			    return Si::make_iterator_range(&parameters.out, &parameters.out + (parameters.out != nullptr));
			});
		auto stdout_finished = experimental::read_from_anonymous_pipe(io, std_output_consumer,
		                                                              std::move(std_output.read), stopped_polling);

		auto std_error_consumer = Si::make_multi_sink<char, Si::success>(
		    [&parameters]()
		    {
			    return Si::make_iterator_range(&parameters.err, &parameters.err + (parameters.err != nullptr));
			});
		auto stderr_finished =
		    experimental::read_from_anonymous_pipe(io, std_error_consumer, std::move(std_error.read), stopped_polling);

		auto copy_input = std::async(std::launch::async, [&input, &parameters]()
		                             {
			                             if (!parameters.in)
			                             {
				                             return;
			                             }
			                             for (;;)
			                             {
				                             Si::optional<char> const c = Si::get(*parameters.in);
				                             if (!c)
				                             {
					                             break;
				                             }
				                             Si::error_or<size_t> written =
				                                 write(input.write.handle, Si::make_memory_range(&*c, 1));
				                             if (written.is_error())
				                             {
					                             // process must have exited
					                             break;
				                             }
				                             assert(written.get() == 1);
			                             }
			                             input.write.close();
			                         });

		io.run();
		copy_input.get();
		stdout_finished.get();
		stderr_finished.get();
		return process.wait_for_exit();
	}

#ifdef _WIN32
	SILICIUM_USE_RESULT
	inline Si::error_or<int>
	run_process(absolute_path executable, std::vector<Si::os_string> arguments, absolute_path current_directory,
	            Si::Sink<char, Si::success>::interface &output,
	            std::vector<std::pair<Si::os_char const *, Si::os_char const *>> additional_environment,
	            environment_inheritance inheritance)
	{
		process_parameters parameters;
		parameters.executable = std::move(executable);
		parameters.arguments = std::move(arguments);
		parameters.current_path = std::move(current_directory);
		parameters.out = &output;
		parameters.err = &output;
		parameters.additional_environment = std::move(additional_environment);
		parameters.inheritance = inheritance;
		return run_process(parameters);
	}
#endif

	SILICIUM_USE_RESULT
	inline std::vector<Si::os_string> arguments_to_os_strings(std::vector<Si::noexcept_string> const &arguments)
	{
		std::vector<Si::os_string> new_arguments;
		{
			auto new_arguments_sink = Si::make_container_sink(new_arguments);
			auto arguments_encoder =
			    Si::make_transforming_source(Si::make_range_source(Si::make_contiguous_range(arguments)),
			                                 [](Si::noexcept_string const &in) -> Si::os_string
			                                 {
				                                 // TODO: mvoe the string if possible
				                                 return Si::to_os_string(in);
				                             });
			Si::copy(arguments_encoder, new_arguments_sink);
		}
		return new_arguments;
	}

	SILICIUM_USE_RESULT
	inline Si::error_or<int>
	run_process(absolute_path executable, std::vector<Si::noexcept_string> arguments, absolute_path current_directory,
	            Si::Sink<char, Si::success>::interface &output,
	            std::vector<std::pair<Si::os_char const *, Si::os_char const *>> additional_environment,
	            environment_inheritance inheritance)
	{
		process_parameters parameters;
		parameters.executable = std::move(executable);
		std::vector<Si::os_string> new_arguments = arguments_to_os_strings(arguments);
		parameters.arguments = std::move(new_arguments);
		parameters.current_path = std::move(current_directory);
		parameters.out = &output;
		parameters.err = &output;
		parameters.additional_environment = std::move(additional_environment);
		parameters.inheritance = inheritance;
		return run_process(parameters);
	}
}
#endif

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/events/event.h"

#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#if defined(HAVE_XINPUT2)
#include <X11/extensions/XInput2.h>
#endif
#include <X11/Xlib.h>

#include "base/utf_string_conversions.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"
#include "views/widget/root_view.h"

#if defined(HAVE_XINPUT2)
#include "views/touchui/touch_factory.h"
#endif

namespace views {

namespace {

// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
static int kWheelScrollAmount = 53;

int GetEventFlagsFromXState(unsigned int state) {
  int flags = 0;
  if (state & ControlMask)
    flags |= ui::EF_CONTROL_DOWN;
  if (state & ShiftMask)
    flags |= ui::EF_SHIFT_DOWN;
  if (state & Mod1Mask)
    flags |= ui::EF_ALT_DOWN;
  if (state & LockMask)
    flags |= ui::EF_CAPS_LOCK_DOWN;
  if (state & Button1Mask)
    flags |= ui::EF_LEFT_BUTTON_DOWN;
  if (state & Button2Mask)
    flags |= ui::EF_MIDDLE_BUTTON_DOWN;
  if (state & Button3Mask)
    flags |= ui::EF_RIGHT_BUTTON_DOWN;

  return flags;
}

// Get the event flag for the button in XButtonEvent. During a ButtonPress
// event, |state| in XButtonEvent does not include the button that has just been
// pressed. Instead |state| contains flags for the buttons (if any) that had
// already been pressed before the current button, and |button| stores the most
// current pressed button. So, if you press down left mouse button, and while
// pressing it down, press down the right mouse button, then for the latter
// event, |state| would have Button1Mask set but not Button3Mask, and |button|
// would be 3.
int GetEventFlagsForButton(int button) {
  switch (button) {
    case 1:
      return ui::EF_LEFT_BUTTON_DOWN;
    case 2:
      return ui::EF_MIDDLE_BUTTON_DOWN;
    case 3:
      return ui::EF_RIGHT_BUTTON_DOWN;
  }

  DLOG(WARNING) << "Unexpected button (" << button << ") received.";
  return 0;
}

#if defined(HAVE_XINPUT2)
int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
  int buttonflags = 0;

  for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
    if (XIMaskIsSet(xievent->buttons.mask, i)) {
      buttonflags |= GetEventFlagsForButton(i);
    }
  }

  return buttonflags;
}

ui::EventType GetTouchEventType(XEvent* xev) {
  XGenericEventCookie* cookie = &xev->xcookie;
  DCHECK_EQ(cookie->evtype, XI_Motion);

  // Note: We will not generate a _STATIONARY event here. It will be created,
  // when necessary, by a RWHVV.
  // TODO(sad): When should _CANCELLED be generated?

  TouchFactory* factory = TouchFactory::GetInstance();
  float slot;
  if (!factory->ExtractTouchParam(*xev, TouchFactory::TP_SLOT_ID, &slot))
    return ui::ET_UNKNOWN;

  if (!factory->IsSlotUsed(slot)) {
    // This is a new touch point.
    return ui::ET_TOUCH_PRESSED;
  }

  float tracking;
  if (!factory->ExtractTouchParam(*xev, TouchFactory::TP_TRACKING_ID,
        &tracking))
    return ui::ET_UNKNOWN;

  if (tracking == 0l) {
    // The touch point has been released.
    return ui::ET_TOUCH_RELEASED;
  }

  return ui::ET_TOUCH_MOVED;
}

int GetTouchIDFromXEvent(XEvent* xev) {
  float slot = 0;
  if (!TouchFactory::GetInstance()->ExtractTouchParam(
        *xev, TouchFactory::TP_SLOT_ID, &slot))
    LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
  return slot;
}

#endif  // HAVE_XINPUT2

ui::EventType EventTypeFromNative(NativeEvent2 native_event) {
  switch (native_event->type) {
    case KeyPress:
      return ui::ET_KEY_PRESSED;
    case KeyRelease:
      return ui::ET_KEY_RELEASED;
    case ButtonPress:
      if (native_event->xbutton.button == 4 ||
          native_event->xbutton.button == 5)
        return ui::ET_MOUSEWHEEL;
      return ui::ET_MOUSE_PRESSED;
    case ButtonRelease:
      if (native_event->xbutton.button == 4 ||
          native_event->xbutton.button == 5)
        return ui::ET_MOUSEWHEEL;
      return ui::ET_MOUSE_RELEASED;
    case MotionNotify:
      if (native_event->xmotion.state &
          (Button1Mask | Button2Mask | Button3Mask))
        return ui::ET_MOUSE_DRAGGED;
      return ui::ET_MOUSE_MOVED;
#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
      if (TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid))
        return GetTouchEventType(native_event);
      switch (xievent->evtype) {
        case XI_ButtonPress:
          return (xievent->detail == 4 || xievent->detail == 5) ?
              ui::ET_MOUSEWHEEL : ui::ET_MOUSE_PRESSED;
        case XI_ButtonRelease:
          return (xievent->detail == 4 || xievent->detail == 5) ?
              ui::ET_MOUSEWHEEL : ui::ET_MOUSE_RELEASED;
        case XI_Motion:
          return GetButtonMaskForX2Event(xievent) ? ui::ET_MOUSE_DRAGGED :
              ui::ET_MOUSE_MOVED;
      }
    }
#endif
    default:
      NOTREACHED();
      break;
  }
  return ui::ET_UNKNOWN;
}

int GetMouseWheelOffset(XEvent* xev) {
#if defined(HAVE_XINPUT2)
  if (xev->type == GenericEvent) {
    XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    return xiev->detail == 4 ? kWheelScrollAmount : -kWheelScrollAmount;
  }
#endif
  return xev->xbutton.button == 4 ? kWheelScrollAmount : -kWheelScrollAmount;
}

gfx::Point GetEventLocation(XEvent* xev) {
  switch (xev->type) {
    case ButtonPress:
    case ButtonRelease:
      return gfx::Point(xev->xbutton.x, xev->xbutton.y);

    case MotionNotify:
      return gfx::Point(xev->xmotion.x, xev->xmotion.y);

#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(xev->xcookie.data);
      return gfx::Point(static_cast<int>(xievent->event_x),
                        static_cast<int>(xievent->event_y));
    }
#endif
  }

  return gfx::Point();
}

int GetLocatedEventFlags(XEvent* xev) {
  switch (xev->type) {
    case ButtonPress:
    case ButtonRelease:
      return GetEventFlagsFromXState(xev->xbutton.state) |
             GetEventFlagsForButton(xev->xbutton.button);

    case MotionNotify:
      return GetEventFlagsFromXState(xev->xmotion.state);

#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
      bool touch =
          TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
      switch (xievent->evtype) {
        case XI_ButtonPress:
        case XI_ButtonRelease:
          return GetButtonMaskForX2Event(xievent) |
                 GetEventFlagsFromXState(xievent->mods.effective) |
                 (touch ? 0 : GetEventFlagsForButton(xievent->detail));

        case XI_Motion:
           return GetButtonMaskForX2Event(xievent) |
                  GetEventFlagsFromXState(xievent->mods.effective);
      }
    }
#endif
  }

  return 0;
}

uint16 GetCharacterFromXKeyEvent(XKeyEvent* key) {
  char buf[6];
  int bytes_written = XLookupString(key, buf, 6, NULL, NULL);
  DCHECK_LE(bytes_written, 6);

  string16 result;
  return (bytes_written > 0 && UTF8ToUTF16(buf, bytes_written, &result) &&
          result.length() == 1) ? result[0] : 0;
}

float GetTouchRadiusFromXEvent(XEvent* xev) {
  float diameter = 0.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  touch_factory->ExtractTouchParam(*xev, TouchFactory::TP_TOUCH_MAJOR,
                                   &diameter);
#endif

  return diameter / 2.0;
}

float GetTouchAngleFromXEvent(XEvent* xev) {
  float angle = 0.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  touch_factory->ExtractTouchParam(*xev, TouchFactory::TP_ORIENTATION,
                                   &angle);
#endif

  return angle;
}

float GetTouchRatioFromXEvent(XEvent* xev) {
  float ratio = 1.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  float major_v = -1.0;
  float minor_v = -1.0;

  if (!touch_factory->ExtractTouchParam(*xev,
                                        TouchFactory::TP_TOUCH_MAJOR,
                                        &major_v) ||
      !touch_factory->ExtractTouchParam(*xev,
                                        TouchFactory::TP_TOUCH_MINOR,
                                        &minor_v))
    return ratio;

  // In case minor axis exists but is zero.
  if (minor_v > 0.0)
    ratio = major_v / minor_v;
#endif

  return ratio;
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// Event, private:

void Event::InitWithNativeEvent2(NativeEvent2 native_event_2,
                                 FromNativeEvent2) {
  native_event_ = NULL;
  // TODO(beng): remove once we rid views of Gtk/Gdk.
  native_event_2_ = native_event_2;
}

////////////////////////////////////////////////////////////////////////////////
// LocatedEvent, protected:

LocatedEvent::LocatedEvent(NativeEvent2 native_event_2,
                           FromNativeEvent2 from_native)
    : Event(native_event_2,
            EventTypeFromNative(native_event_2),
            GetLocatedEventFlags(native_event_2),
            from_native),
      location_(GetEventLocation(native_event_2)) {
}

////////////////////////////////////////////////////////////////////////////////
// KeyEvent, public:

KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native)
    : Event(native_event_2,
            EventTypeFromNative(native_event_2),
            GetEventFlagsFromXState(native_event_2->xkey.state),
            from_native),
      key_code_(ui::KeyboardCodeFromXKeyEvent(native_event_2)) {
}

uint16 KeyEvent::GetCharacter() const {
  if (!native_event_2())
    return GetCharacterFromKeyCode(key_code_, flags());

  DCHECK(native_event_2()->type == KeyPress ||
         native_event_2()->type == KeyRelease);

  uint16 ch = GetCharacterFromXKeyEvent(&native_event_2()->xkey);
  return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
}

uint16 KeyEvent::GetUnmodifiedCharacter() const {
  if (!native_event_2())
    return GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN);

  DCHECK(native_event_2()->type == KeyPress ||
         native_event_2()->type == KeyRelease);

  XKeyEvent key = native_event_2()->xkey;

  static const unsigned int kIgnoredModifiers = ControlMask | LockMask |
      Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask;

  // We can't use things like (key.state & ShiftMask), as it may mask out bits
  // used by X11 internally.
  key.state &= ~kIgnoredModifiers;
  uint16 ch = GetCharacterFromXKeyEvent(&key);
  return ch ? ch :
      GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN);
}

////////////////////////////////////////////////////////////////////////////////
// MouseEvent, public:

MouseEvent::MouseEvent(NativeEvent2 native_event_2,
                       FromNativeEvent2 from_native)
    : LocatedEvent(native_event_2, from_native) {
}

MouseEvent::MouseEvent(const TouchEvent& touch,
                       FromNativeEvent2 from_native)
    : LocatedEvent(touch.native_event_2(), from_native) {
  // The location of the event is correctly extracted from the native event. But
  // it is necessary to update the event type.
  ui::EventType mtype = ui::ET_UNKNOWN;
  switch (touch.type()) {
    case ui::ET_TOUCH_RELEASED:
      mtype = ui::ET_MOUSE_RELEASED;
      break;
    case ui::ET_TOUCH_PRESSED:
      mtype = ui::ET_MOUSE_PRESSED;
      break;
    case ui::ET_TOUCH_MOVED:
      mtype = ui::ET_MOUSE_MOVED;
      break;
    default:
      NOTREACHED() << "Invalid mouse event.";
  }
  set_type(mtype);

  // It may not be possible to extract the button-information necessary for a
  // MouseEvent from the native event for a TouchEvent, so the flags are
  // explicitly updated as well. The button is approximated from the touchpoint
  // identity.
  int new_flags = flags() & ~(ui::EF_LEFT_BUTTON_DOWN |
                              ui::EF_RIGHT_BUTTON_DOWN |
                              ui::EF_MIDDLE_BUTTON_DOWN);
  int button = ui::EF_LEFT_BUTTON_DOWN;
  if (touch.identity() == 1)
    button = ui::EF_RIGHT_BUTTON_DOWN;
  else if (touch.identity() == 2)
    button = ui::EF_MIDDLE_BUTTON_DOWN;
  set_flags(new_flags | button);
}

////////////////////////////////////////////////////////////////////////////////
// MouseWheelEvent, public:

MouseWheelEvent::MouseWheelEvent(NativeEvent2 native_event_2,
                                 FromNativeEvent2 from_native)
    : MouseEvent(native_event_2, from_native),
      offset_(GetMouseWheelOffset(native_event_2)) {
}

////////////////////////////////////////////////////////////////////////////////
// TouchEvent, public:

#if defined(HAVE_XINPUT2)
TouchEvent::TouchEvent(NativeEvent2 native_event_2,
                       FromNativeEvent2 from_native)
    : LocatedEvent(native_event_2, from_native),
      touch_id_(GetTouchIDFromXEvent(native_event_2)),
      radius_(GetTouchRadiusFromXEvent(native_event_2)),
      angle_(GetTouchAngleFromXEvent(native_event_2)),
      ratio_(GetTouchRatioFromXEvent(native_event_2)) {
  if (type() == ui::ET_TOUCH_PRESSED || type() == ui::ET_TOUCH_RELEASED) {
    TouchFactory* factory = TouchFactory::GetInstance();
    float slot;
    if (factory->ExtractTouchParam(*native_event_2,
                                   TouchFactory::TP_SLOT_ID, &slot)) {
      factory->SetSlotUsed(slot, type() == ui::ET_TOUCH_PRESSED);
    }
  }
}
#endif

}  // namespace views
<commit_msg>Added logging include.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/events/event.h"

#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#if defined(HAVE_XINPUT2)
#include <X11/extensions/XInput2.h>
#endif
#include <X11/Xlib.h>

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"
#include "views/widget/root_view.h"

#if defined(HAVE_XINPUT2)
#include "views/touchui/touch_factory.h"
#endif

namespace views {

namespace {

// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
static int kWheelScrollAmount = 53;

int GetEventFlagsFromXState(unsigned int state) {
  int flags = 0;
  if (state & ControlMask)
    flags |= ui::EF_CONTROL_DOWN;
  if (state & ShiftMask)
    flags |= ui::EF_SHIFT_DOWN;
  if (state & Mod1Mask)
    flags |= ui::EF_ALT_DOWN;
  if (state & LockMask)
    flags |= ui::EF_CAPS_LOCK_DOWN;
  if (state & Button1Mask)
    flags |= ui::EF_LEFT_BUTTON_DOWN;
  if (state & Button2Mask)
    flags |= ui::EF_MIDDLE_BUTTON_DOWN;
  if (state & Button3Mask)
    flags |= ui::EF_RIGHT_BUTTON_DOWN;

  return flags;
}

// Get the event flag for the button in XButtonEvent. During a ButtonPress
// event, |state| in XButtonEvent does not include the button that has just been
// pressed. Instead |state| contains flags for the buttons (if any) that had
// already been pressed before the current button, and |button| stores the most
// current pressed button. So, if you press down left mouse button, and while
// pressing it down, press down the right mouse button, then for the latter
// event, |state| would have Button1Mask set but not Button3Mask, and |button|
// would be 3.
int GetEventFlagsForButton(int button) {
  switch (button) {
    case 1:
      return ui::EF_LEFT_BUTTON_DOWN;
    case 2:
      return ui::EF_MIDDLE_BUTTON_DOWN;
    case 3:
      return ui::EF_RIGHT_BUTTON_DOWN;
  }

  DLOG(WARNING) << "Unexpected button (" << button << ") received.";
  return 0;
}

#if defined(HAVE_XINPUT2)
int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
  int buttonflags = 0;

  for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
    if (XIMaskIsSet(xievent->buttons.mask, i)) {
      buttonflags |= GetEventFlagsForButton(i);
    }
  }

  return buttonflags;
}

ui::EventType GetTouchEventType(XEvent* xev) {
  XGenericEventCookie* cookie = &xev->xcookie;
  DCHECK_EQ(cookie->evtype, XI_Motion);

  // Note: We will not generate a _STATIONARY event here. It will be created,
  // when necessary, by a RWHVV.
  // TODO(sad): When should _CANCELLED be generated?

  TouchFactory* factory = TouchFactory::GetInstance();
  float slot;
  if (!factory->ExtractTouchParam(*xev, TouchFactory::TP_SLOT_ID, &slot))
    return ui::ET_UNKNOWN;

  if (!factory->IsSlotUsed(slot)) {
    // This is a new touch point.
    return ui::ET_TOUCH_PRESSED;
  }

  float tracking;
  if (!factory->ExtractTouchParam(*xev, TouchFactory::TP_TRACKING_ID,
        &tracking))
    return ui::ET_UNKNOWN;

  if (tracking == 0l) {
    // The touch point has been released.
    return ui::ET_TOUCH_RELEASED;
  }

  return ui::ET_TOUCH_MOVED;
}

int GetTouchIDFromXEvent(XEvent* xev) {
  float slot = 0;
  if (!TouchFactory::GetInstance()->ExtractTouchParam(
        *xev, TouchFactory::TP_SLOT_ID, &slot))
    LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
  return slot;
}

#endif  // HAVE_XINPUT2

ui::EventType EventTypeFromNative(NativeEvent2 native_event) {
  switch (native_event->type) {
    case KeyPress:
      return ui::ET_KEY_PRESSED;
    case KeyRelease:
      return ui::ET_KEY_RELEASED;
    case ButtonPress:
      if (native_event->xbutton.button == 4 ||
          native_event->xbutton.button == 5)
        return ui::ET_MOUSEWHEEL;
      return ui::ET_MOUSE_PRESSED;
    case ButtonRelease:
      if (native_event->xbutton.button == 4 ||
          native_event->xbutton.button == 5)
        return ui::ET_MOUSEWHEEL;
      return ui::ET_MOUSE_RELEASED;
    case MotionNotify:
      if (native_event->xmotion.state &
          (Button1Mask | Button2Mask | Button3Mask))
        return ui::ET_MOUSE_DRAGGED;
      return ui::ET_MOUSE_MOVED;
#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
      if (TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid))
        return GetTouchEventType(native_event);
      switch (xievent->evtype) {
        case XI_ButtonPress:
          return (xievent->detail == 4 || xievent->detail == 5) ?
              ui::ET_MOUSEWHEEL : ui::ET_MOUSE_PRESSED;
        case XI_ButtonRelease:
          return (xievent->detail == 4 || xievent->detail == 5) ?
              ui::ET_MOUSEWHEEL : ui::ET_MOUSE_RELEASED;
        case XI_Motion:
          return GetButtonMaskForX2Event(xievent) ? ui::ET_MOUSE_DRAGGED :
              ui::ET_MOUSE_MOVED;
      }
    }
#endif
    default:
      NOTREACHED();
      break;
  }
  return ui::ET_UNKNOWN;
}

int GetMouseWheelOffset(XEvent* xev) {
#if defined(HAVE_XINPUT2)
  if (xev->type == GenericEvent) {
    XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    return xiev->detail == 4 ? kWheelScrollAmount : -kWheelScrollAmount;
  }
#endif
  return xev->xbutton.button == 4 ? kWheelScrollAmount : -kWheelScrollAmount;
}

gfx::Point GetEventLocation(XEvent* xev) {
  switch (xev->type) {
    case ButtonPress:
    case ButtonRelease:
      return gfx::Point(xev->xbutton.x, xev->xbutton.y);

    case MotionNotify:
      return gfx::Point(xev->xmotion.x, xev->xmotion.y);

#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(xev->xcookie.data);
      return gfx::Point(static_cast<int>(xievent->event_x),
                        static_cast<int>(xievent->event_y));
    }
#endif
  }

  return gfx::Point();
}

int GetLocatedEventFlags(XEvent* xev) {
  switch (xev->type) {
    case ButtonPress:
    case ButtonRelease:
      return GetEventFlagsFromXState(xev->xbutton.state) |
             GetEventFlagsForButton(xev->xbutton.button);

    case MotionNotify:
      return GetEventFlagsFromXState(xev->xmotion.state);

#if defined(HAVE_XINPUT2)
    case GenericEvent: {
      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
      bool touch =
          TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
      switch (xievent->evtype) {
        case XI_ButtonPress:
        case XI_ButtonRelease:
          return GetButtonMaskForX2Event(xievent) |
                 GetEventFlagsFromXState(xievent->mods.effective) |
                 (touch ? 0 : GetEventFlagsForButton(xievent->detail));

        case XI_Motion:
           return GetButtonMaskForX2Event(xievent) |
                  GetEventFlagsFromXState(xievent->mods.effective);
      }
    }
#endif
  }

  return 0;
}

uint16 GetCharacterFromXKeyEvent(XKeyEvent* key) {
  char buf[6];
  int bytes_written = XLookupString(key, buf, 6, NULL, NULL);
  DCHECK_LE(bytes_written, 6);

  string16 result;
  return (bytes_written > 0 && UTF8ToUTF16(buf, bytes_written, &result) &&
          result.length() == 1) ? result[0] : 0;
}

float GetTouchRadiusFromXEvent(XEvent* xev) {
  float diameter = 0.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  touch_factory->ExtractTouchParam(*xev, TouchFactory::TP_TOUCH_MAJOR,
                                   &diameter);
#endif

  return diameter / 2.0;
}

float GetTouchAngleFromXEvent(XEvent* xev) {
  float angle = 0.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  touch_factory->ExtractTouchParam(*xev, TouchFactory::TP_ORIENTATION,
                                   &angle);
#endif

  return angle;
}

float GetTouchRatioFromXEvent(XEvent* xev) {
  float ratio = 1.0;

#if defined(HAVE_XINPUT2)
  TouchFactory* touch_factory = TouchFactory::GetInstance();
  float major_v = -1.0;
  float minor_v = -1.0;

  if (!touch_factory->ExtractTouchParam(*xev,
                                        TouchFactory::TP_TOUCH_MAJOR,
                                        &major_v) ||
      !touch_factory->ExtractTouchParam(*xev,
                                        TouchFactory::TP_TOUCH_MINOR,
                                        &minor_v))
    return ratio;

  // In case minor axis exists but is zero.
  if (minor_v > 0.0)
    ratio = major_v / minor_v;
#endif

  return ratio;
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// Event, private:

void Event::InitWithNativeEvent2(NativeEvent2 native_event_2,
                                 FromNativeEvent2) {
  native_event_ = NULL;
  // TODO(beng): remove once we rid views of Gtk/Gdk.
  native_event_2_ = native_event_2;
}

////////////////////////////////////////////////////////////////////////////////
// LocatedEvent, protected:

LocatedEvent::LocatedEvent(NativeEvent2 native_event_2,
                           FromNativeEvent2 from_native)
    : Event(native_event_2,
            EventTypeFromNative(native_event_2),
            GetLocatedEventFlags(native_event_2),
            from_native),
      location_(GetEventLocation(native_event_2)) {
}

////////////////////////////////////////////////////////////////////////////////
// KeyEvent, public:

KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native)
    : Event(native_event_2,
            EventTypeFromNative(native_event_2),
            GetEventFlagsFromXState(native_event_2->xkey.state),
            from_native),
      key_code_(ui::KeyboardCodeFromXKeyEvent(native_event_2)) {
}

uint16 KeyEvent::GetCharacter() const {
  if (!native_event_2())
    return GetCharacterFromKeyCode(key_code_, flags());

  DCHECK(native_event_2()->type == KeyPress ||
         native_event_2()->type == KeyRelease);

  uint16 ch = GetCharacterFromXKeyEvent(&native_event_2()->xkey);
  return ch ? ch : GetCharacterFromKeyCode(key_code_, flags());
}

uint16 KeyEvent::GetUnmodifiedCharacter() const {
  if (!native_event_2())
    return GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN);

  DCHECK(native_event_2()->type == KeyPress ||
         native_event_2()->type == KeyRelease);

  XKeyEvent key = native_event_2()->xkey;

  static const unsigned int kIgnoredModifiers = ControlMask | LockMask |
      Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask;

  // We can't use things like (key.state & ShiftMask), as it may mask out bits
  // used by X11 internally.
  key.state &= ~kIgnoredModifiers;
  uint16 ch = GetCharacterFromXKeyEvent(&key);
  return ch ? ch :
      GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN);
}

////////////////////////////////////////////////////////////////////////////////
// MouseEvent, public:

MouseEvent::MouseEvent(NativeEvent2 native_event_2,
                       FromNativeEvent2 from_native)
    : LocatedEvent(native_event_2, from_native) {
}

MouseEvent::MouseEvent(const TouchEvent& touch,
                       FromNativeEvent2 from_native)
    : LocatedEvent(touch.native_event_2(), from_native) {
  // The location of the event is correctly extracted from the native event. But
  // it is necessary to update the event type.
  ui::EventType mtype = ui::ET_UNKNOWN;
  switch (touch.type()) {
    case ui::ET_TOUCH_RELEASED:
      mtype = ui::ET_MOUSE_RELEASED;
      break;
    case ui::ET_TOUCH_PRESSED:
      mtype = ui::ET_MOUSE_PRESSED;
      break;
    case ui::ET_TOUCH_MOVED:
      mtype = ui::ET_MOUSE_MOVED;
      break;
    default:
      NOTREACHED() << "Invalid mouse event.";
  }
  set_type(mtype);

  // It may not be possible to extract the button-information necessary for a
  // MouseEvent from the native event for a TouchEvent, so the flags are
  // explicitly updated as well. The button is approximated from the touchpoint
  // identity.
  int new_flags = flags() & ~(ui::EF_LEFT_BUTTON_DOWN |
                              ui::EF_RIGHT_BUTTON_DOWN |
                              ui::EF_MIDDLE_BUTTON_DOWN);
  int button = ui::EF_LEFT_BUTTON_DOWN;
  if (touch.identity() == 1)
    button = ui::EF_RIGHT_BUTTON_DOWN;
  else if (touch.identity() == 2)
    button = ui::EF_MIDDLE_BUTTON_DOWN;
  set_flags(new_flags | button);
}

////////////////////////////////////////////////////////////////////////////////
// MouseWheelEvent, public:

MouseWheelEvent::MouseWheelEvent(NativeEvent2 native_event_2,
                                 FromNativeEvent2 from_native)
    : MouseEvent(native_event_2, from_native),
      offset_(GetMouseWheelOffset(native_event_2)) {
}

////////////////////////////////////////////////////////////////////////////////
// TouchEvent, public:

#if defined(HAVE_XINPUT2)
TouchEvent::TouchEvent(NativeEvent2 native_event_2,
                       FromNativeEvent2 from_native)
    : LocatedEvent(native_event_2, from_native),
      touch_id_(GetTouchIDFromXEvent(native_event_2)),
      radius_(GetTouchRadiusFromXEvent(native_event_2)),
      angle_(GetTouchAngleFromXEvent(native_event_2)),
      ratio_(GetTouchRatioFromXEvent(native_event_2)) {
  if (type() == ui::ET_TOUCH_PRESSED || type() == ui::ET_TOUCH_RELEASED) {
    TouchFactory* factory = TouchFactory::GetInstance();
    float slot;
    if (factory->ExtractTouchParam(*native_event_2,
                                   TouchFactory::TP_SLOT_ID, &slot)) {
      factory->SetSlotUsed(slot, type() == ui::ET_TOUCH_PRESSED);
    }
  }
}
#endif

}  // namespace views
<|endoftext|>


<commit_before>#include <cstdint>
#include <string>
#include <iostream>
#include <mutex>

#define UINT24_MAX 16777215
#define INDEX_MASK (uint32_t) 0x00FFFFFF
#define NEGATIVE_THRESH -100 // Latencies smaller than this threshold are ignored

/*
 * This namespace holds functions which are used by MoonSniff's Live Mode
 *
 * Other modes are implemented in examples/moonsniff/
 */
namespace moonsniff {

	// vars for live average computation
	uint64_t count = 0;
        double m2 = 0;
        double mean = 0;
        double variance = 0;

	/**
	 * Statistics which are exposed to applications
	 */
	struct ms_stats {
		int64_t average_latency = 0;
		int64_t variance_latency = 0;
		uint32_t hits = 0;
		uint32_t misses = 0;
		uint32_t inval_ts = 0;
	} stats;

	// initialize array and as many mutexes to ensure memory order
	uint64_t hit_list[UINT24_MAX + 1] = { 0 };
	std::mutex mtx[UINT24_MAX + 1];

	/**
	 * Add a pre DUT timestamp to the array.
	 *
	 * @param identification The identifier associated with this timestamp
	 * @param timestamp The timestamp
	 */
	static void add_entry(uint32_t identification, uint64_t timestamp){
		uint32_t index = identification & INDEX_MASK;
		while(!mtx[index].try_lock());
		hit_list[index] = timestamp;
		mtx[index].unlock();
	}

	/**
	 * Check if there exists an entry in the array for the given identifier.
	 * Updates current mean and variance estimation..
	 *
	 * @param identification Identifier for which an entry is searched
	 * @param timestamp The post timestamp
	 */
	static void test_for(uint32_t identification, uint64_t timestamp){
		uint32_t index = identification & INDEX_MASK;
		while(!mtx[index].try_lock());
		uint64_t old_ts = hit_list[index];
		hit_list[index] = 0;
		mtx[index].unlock();
		if( old_ts != 0 ){
			++stats.hits;
			// diff overflow improbable (latency > 290 years)
			int64_t diff = timestamp - old_ts;
			if (diff < -NEGATIVE_THRESH){
				std::cerr << "Measured latency below " << NEGATIVE_THRESH
				<< " (Threshold). Ignoring...\n";
                	}
                	++count;
                	double delta = diff - mean;
                	mean = mean + delta / count;
                	double delta2 = diff - mean;
                	m2 = m2 + delta * delta2;
		} else {
			++stats.misses;
		}
	}

	/**
	 * Fetch statistics. Finalizes variance computation..
	 */
	static ms_stats fetch_stats(){
		if (count < 2) {
                        std::cerr << "Not enough members to calculate mean and variance\n";
                } else {
                        variance = m2 / (count - 1);
                }

		// Implicit cast from double to int64_t -> sub-nanosecond parts are discarded
		stats.average_latency = mean;
		stats.variance_latency = variance;
		return stats;
	}
}

extern "C" {
	void ms_add_entry(uint32_t identification, uint64_t timestamp){
		moonsniff::add_entry(identification, timestamp);
	}

	void ms_test_for(uint32_t identification, uint64_t timestamp){
		moonsniff::test_for(identification, timestamp);
	}

	moonsniff::ms_stats ms_fetch_stats(){
		return moonsniff::fetch_stats();
	}
}
<commit_msg>fix high rate measurements for live mode<commit_after>#include <cstdint>
#include <string>
#include <iostream>
#include <mutex>

#define UINT24_MAX 16777215
#define INDEX_MASK (uint32_t) 0x00FFFFFF
#define NEGATIVE_THRESH -100 // Latencies smaller than this threshold are ignored

/*
 * This namespace holds functions which are used by MoonSniff's Live Mode
 *
 * Other modes are implemented in examples/moonsniff/
 */
namespace moonsniff {

	// vars for live average computation
	uint64_t count = 0;
        double m2 = 0;
        double mean = 0;
        double variance = 0;

	/**
	 * Statistics which are exposed to applications
	 */
	struct ms_stats {
		int64_t average_latency = 0;
		int64_t variance_latency = 0;
		uint32_t hits = 0;
		uint32_t misses = 0;
		uint32_t inval_ts = 0;
	} stats;

	/**
	 * Entry of the hit_list which stores the pre-DUT data
	 */
	struct entry {
		uint64_t timestamp;
		uint64_t identifier;
	};

	// initialize array and as many mutexes to ensure memory order
	struct entry hit_list[UINT24_MAX + 1] = {{ 0, 0 }};
	std::mutex mtx[UINT24_MAX + 1];

	/**
	 * Add a pre DUT timestamp to the array.
	 *
	 * @param identification The identifier associated with this timestamp
	 * @param timestamp The timestamp
	 */
	static void add_entry(uint32_t identification, uint64_t timestamp){
		uint32_t index = identification & INDEX_MASK;
		while(!mtx[index].try_lock());
		hit_list[index].timestamp = timestamp;
		hit_list[index].identifier = identification;
		mtx[index].unlock();
	}

	/**
	 * Check if there exists an entry in the array for the given identifier.
	 * Updates current mean and variance estimation..
	 *
	 * @param identification Identifier for which an entry is searched
	 * @param timestamp The post timestamp
	 */
	static void test_for(uint32_t identification, uint64_t timestamp){
		uint32_t index = identification & INDEX_MASK;
		while(!mtx[index].try_lock());
		uint64_t old_ts = hit_list[index].identifier == identification ? hit_list[index].timestamp : 0;
		hit_list[index].timestamp = 0;
		hit_list[index].identifier = 0;
		mtx[index].unlock();
		if( old_ts != 0 ){
			++stats.hits;
			// diff overflow improbable
			int64_t diff = timestamp - old_ts;
			if (diff < -NEGATIVE_THRESH){
				std::cerr << "Measured latency below " << NEGATIVE_THRESH
				<< " (Threshold). Ignoring...\n";
                	}
                	++count;
                	double delta = diff - mean;
                	mean = mean + delta / count;
                	double delta2 = diff - mean;
                	m2 = m2 + delta * delta2;
		} else {
			++stats.misses;
		}
	}

	/**
	 * Fetch statistics. Finalizes variance computation..
	 */
	static ms_stats fetch_stats(){
		if (count < 2) {
                        std::cerr << "Not enough members to calculate mean and variance\n";
                } else {
                        variance = m2 / (count - 1);
                }

		// Implicit cast from double to int64_t -> sub-nanosecond parts are discarded
		stats.average_latency = mean;
		stats.variance_latency = variance;
		return stats;
	}
}

extern "C" {
	void ms_add_entry(uint32_t identification, uint64_t timestamp){
		moonsniff::add_entry(identification, timestamp);
	}

	void ms_test_for(uint32_t identification, uint64_t timestamp){
		moonsniff::test_for(identification, timestamp);
	}

	moonsniff::ms_stats ms_fetch_stats(){
		return moonsniff::fetch_stats();
	}
}
<|endoftext|>


<commit_before>// v8
#include <v8.h>

// node
#include <node.h>
#include <node_buffer.h>
#include <node_version.h>

// gdal
#include <gdal.h>

// node-gdal
#include "gdal_common.hpp"
#include "gdal.hpp"
#include "gdal_majorobject.hpp"
#include "gdal_driver.hpp"
#include "gdal_dataset.hpp"
#include "gdal_rasterband.hpp"

// std
#include <string>
#include <sstream>
#include <vector>

namespace node_gdal {

using namespace node;
using namespace v8;

extern "C" {
	static Handle<Value> QuietOutput(const Arguments &args)
	{
		CPLSetErrorHandler(CPLQuietErrorHandler);
		return Undefined();
	}

	static Handle<Value> VerboseOutput(const Arguments &args)
	{
		CPLSetErrorHandler(NULL);
		return Undefined();
	}

	static void Init(Handle<Object> target)
	{
		NODE_SET_METHOD(target, "open", node_ogr::open);
		NODE_SET_METHOD(target, "openShared", node_ogr::openShared);
		NODE_SET_METHOD(target, "getDriverByName", node_ogr::getDriverByName);
		NODE_SET_METHOD(target, "getDriverCount", node_ogr::getDriverCount);
		NODE_SET_METHOD(target, "getDriver", node_ogr::getDriver);
		NODE_SET_METHOD(target, "close", node_ogr::close);

		MajorObject::Initialize(target);
		Driver::Initialize(target);
		Dataset::Initialize(target);
		RasterBand::Initialize(target);

		Local<Object> versions = Object::New();
		versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
		versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));

		target->Set(String::NewSymbol("versions"), versions);

		NODE_SET_METHOD(target, "quiet", QuietOutput);
		NODE_SET_METHOD(target, "verbose", VerboseOutput);

		Local<Object> supports = Object::New();
		target->Set(String::NewSymbol("supports"), supports);

		GDALAllRegister();

		GDALDriverManager  *reg = GetGDALDriverManager();

		int driver_count = reg->GetDriverCount();

		Local<Array> supported_drivers = Array::New(driver_count);

		for (int i = 0; i < driver_count; ++i) {
			GDALDriver *driver = reg->GetDriver(i);
			supported_drivers->Set(Integer::New(static_cast<int>(i)), String::New(driver->GetDescription()));
		}

		target->Set(String::NewSymbol("drivers"), supported_drivers);

		NODE_DEFINE_CONSTANT(target, CPLE_OpenFailed);
		NODE_DEFINE_CONSTANT(target, CPLE_IllegalArg);
		NODE_DEFINE_CONSTANT(target, CPLE_NotSupported);
		NODE_DEFINE_CONSTANT(target, CPLE_AssertionFailed);
		NODE_DEFINE_CONSTANT(target, CPLE_NoWriteAccess);
		NODE_DEFINE_CONSTANT(target, CPLE_UserInterrupt);

		target->Set(String::NewSymbol("DMD_LONGNAME"), String::New(GDAL_DMD_LONGNAME));
		target->Set(String::NewSymbol("DMD_MIMETYPE"), String::New(GDAL_DMD_MIMETYPE));
		target->Set(String::NewSymbol("DMD_HELPTOPIC"), String::New(GDAL_DMD_HELPTOPIC));
		target->Set(String::NewSymbol("DMD_EXTENSION"), String::New(GDAL_DMD_EXTENSION));
		target->Set(String::NewSymbol("DMD_CREATIONOPTIONLIST"), String::New(GDAL_DMD_CREATIONOPTIONLIST));
		target->Set(String::NewSymbol("DMD_CREATIONDATATYPES"), String::New(GDAL_DMD_CREATIONDATATYPES));

		target->Set(String::NewSymbol("DCAP_CREATE"), String::New(GDAL_DCAP_CREATE));
		target->Set(String::NewSymbol("DCAP_CREATECOPY"), String::New(GDAL_DCAP_CREATECOPY));
		target->Set(String::NewSymbol("DCAP_VIRTUALIO"), String::New(GDAL_DCAP_VIRTUALIO));

		NODE_DEFINE_CONSTANT(target, GA_ReadOnly);
		NODE_DEFINE_CONSTANT(target, GA_Update);
		NODE_DEFINE_CONSTANT(target, GF_Read);
		NODE_DEFINE_CONSTANT(target, GF_Write);

		NODE_DEFINE_CONSTANT(target, GDT_Unknown);
		NODE_DEFINE_CONSTANT(target, GDT_Byte);
		NODE_DEFINE_CONSTANT(target, GDT_UInt16);
		NODE_DEFINE_CONSTANT(target, GDT_Int16);
		NODE_DEFINE_CONSTANT(target, GDT_UInt32);
		NODE_DEFINE_CONSTANT(target, GDT_Int32);
		NODE_DEFINE_CONSTANT(target, GDT_Float32);
		NODE_DEFINE_CONSTANT(target, GDT_Float64);
		NODE_DEFINE_CONSTANT(target, GDT_CInt16);
		NODE_DEFINE_CONSTANT(target, GDT_CInt32);
		NODE_DEFINE_CONSTANT(target, GDT_CFloat32);
		NODE_DEFINE_CONSTANT(target, GDT_CFloat64);

		NODE_DEFINE_CONSTANT(target, GCI_Undefined);
		NODE_DEFINE_CONSTANT(target, GCI_GrayIndex);
		NODE_DEFINE_CONSTANT(target, GCI_PaletteIndex);
		NODE_DEFINE_CONSTANT(target, GCI_RedBand);
		NODE_DEFINE_CONSTANT(target, GCI_GreenBand);
		NODE_DEFINE_CONSTANT(target, GCI_BlueBand);
		NODE_DEFINE_CONSTANT(target, GCI_AlphaBand);
		NODE_DEFINE_CONSTANT(target, GCI_HueBand);
		NODE_DEFINE_CONSTANT(target, GCI_SaturationBand);
		NODE_DEFINE_CONSTANT(target, GCI_LightnessBand);
		NODE_DEFINE_CONSTANT(target, GCI_CyanBand);
		NODE_DEFINE_CONSTANT(target, GCI_MagentaBand);
		NODE_DEFINE_CONSTANT(target, GCI_YellowBand);
		NODE_DEFINE_CONSTANT(target, GCI_BlackBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_YBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_CbBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_CrBand);
		NODE_DEFINE_CONSTANT(target, GCI_Max);
	}

}

} // namespace node_gdal

NODE_MODULE(gdal, node_gdal::Init)
<commit_msg>Don't print gdal errors to stderr.<commit_after>// v8
#include <v8.h>

// node
#include <node.h>
#include <node_buffer.h>
#include <node_version.h>

// gdal
#include <gdal.h>

// node-gdal
#include "gdal_common.hpp"
#include "gdal.hpp"
#include "gdal_majorobject.hpp"
#include "gdal_driver.hpp"
#include "gdal_dataset.hpp"
#include "gdal_rasterband.hpp"

// std
#include <string>
#include <sstream>
#include <vector>

namespace node_gdal {

using namespace node;
using namespace v8;

extern "C" {
	static Handle<Value> QuietOutput(const Arguments &args)
	{
		CPLSetErrorHandler(CPLQuietErrorHandler);
		return Undefined();
	}

	static Handle<Value> VerboseOutput(const Arguments &args)
	{
		CPLSetErrorHandler(NULL);
		return Undefined();
	}

	static void Init(Handle<Object> target)
	{
		NODE_SET_METHOD(target, "open", node_ogr::open);
		NODE_SET_METHOD(target, "openShared", node_ogr::openShared);
		NODE_SET_METHOD(target, "getDriverByName", node_ogr::getDriverByName);
		NODE_SET_METHOD(target, "getDriverCount", node_ogr::getDriverCount);
		NODE_SET_METHOD(target, "getDriver", node_ogr::getDriver);
		NODE_SET_METHOD(target, "close", node_ogr::close);

		MajorObject::Initialize(target);
		Driver::Initialize(target);
		Dataset::Initialize(target);
		RasterBand::Initialize(target);

		Local<Object> versions = Object::New();
		versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
		versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));

		target->Set(String::NewSymbol("versions"), versions);

		NODE_SET_METHOD(target, "quiet", QuietOutput);
		NODE_SET_METHOD(target, "verbose", VerboseOutput);

		Local<Object> supports = Object::New();
		target->Set(String::NewSymbol("supports"), supports);

		GDALAllRegister();

		//by default don't print errors to stderr
		CPLSetErrorHandler(CPLQuietErrorHandler);

		GDALDriverManager  *reg = GetGDALDriverManager();

		int driver_count = reg->GetDriverCount();

		Local<Array> supported_drivers = Array::New(driver_count);

		for (int i = 0; i < driver_count; ++i) {
			GDALDriver *driver = reg->GetDriver(i);
			supported_drivers->Set(Integer::New(static_cast<int>(i)), String::New(driver->GetDescription()));
		}

		target->Set(String::NewSymbol("drivers"), supported_drivers);

		NODE_DEFINE_CONSTANT(target, CPLE_OpenFailed);
		NODE_DEFINE_CONSTANT(target, CPLE_IllegalArg);
		NODE_DEFINE_CONSTANT(target, CPLE_NotSupported);
		NODE_DEFINE_CONSTANT(target, CPLE_AssertionFailed);
		NODE_DEFINE_CONSTANT(target, CPLE_NoWriteAccess);
		NODE_DEFINE_CONSTANT(target, CPLE_UserInterrupt);

		target->Set(String::NewSymbol("DMD_LONGNAME"), String::New(GDAL_DMD_LONGNAME));
		target->Set(String::NewSymbol("DMD_MIMETYPE"), String::New(GDAL_DMD_MIMETYPE));
		target->Set(String::NewSymbol("DMD_HELPTOPIC"), String::New(GDAL_DMD_HELPTOPIC));
		target->Set(String::NewSymbol("DMD_EXTENSION"), String::New(GDAL_DMD_EXTENSION));
		target->Set(String::NewSymbol("DMD_CREATIONOPTIONLIST"), String::New(GDAL_DMD_CREATIONOPTIONLIST));
		target->Set(String::NewSymbol("DMD_CREATIONDATATYPES"), String::New(GDAL_DMD_CREATIONDATATYPES));

		target->Set(String::NewSymbol("DCAP_CREATE"), String::New(GDAL_DCAP_CREATE));
		target->Set(String::NewSymbol("DCAP_CREATECOPY"), String::New(GDAL_DCAP_CREATECOPY));
		target->Set(String::NewSymbol("DCAP_VIRTUALIO"), String::New(GDAL_DCAP_VIRTUALIO));

		NODE_DEFINE_CONSTANT(target, GA_ReadOnly);
		NODE_DEFINE_CONSTANT(target, GA_Update);
		NODE_DEFINE_CONSTANT(target, GF_Read);
		NODE_DEFINE_CONSTANT(target, GF_Write);

		NODE_DEFINE_CONSTANT(target, GDT_Unknown);
		NODE_DEFINE_CONSTANT(target, GDT_Byte);
		NODE_DEFINE_CONSTANT(target, GDT_UInt16);
		NODE_DEFINE_CONSTANT(target, GDT_Int16);
		NODE_DEFINE_CONSTANT(target, GDT_UInt32);
		NODE_DEFINE_CONSTANT(target, GDT_Int32);
		NODE_DEFINE_CONSTANT(target, GDT_Float32);
		NODE_DEFINE_CONSTANT(target, GDT_Float64);
		NODE_DEFINE_CONSTANT(target, GDT_CInt16);
		NODE_DEFINE_CONSTANT(target, GDT_CInt32);
		NODE_DEFINE_CONSTANT(target, GDT_CFloat32);
		NODE_DEFINE_CONSTANT(target, GDT_CFloat64);

		NODE_DEFINE_CONSTANT(target, GCI_Undefined);
		NODE_DEFINE_CONSTANT(target, GCI_GrayIndex);
		NODE_DEFINE_CONSTANT(target, GCI_PaletteIndex);
		NODE_DEFINE_CONSTANT(target, GCI_RedBand);
		NODE_DEFINE_CONSTANT(target, GCI_GreenBand);
		NODE_DEFINE_CONSTANT(target, GCI_BlueBand);
		NODE_DEFINE_CONSTANT(target, GCI_AlphaBand);
		NODE_DEFINE_CONSTANT(target, GCI_HueBand);
		NODE_DEFINE_CONSTANT(target, GCI_SaturationBand);
		NODE_DEFINE_CONSTANT(target, GCI_LightnessBand);
		NODE_DEFINE_CONSTANT(target, GCI_CyanBand);
		NODE_DEFINE_CONSTANT(target, GCI_MagentaBand);
		NODE_DEFINE_CONSTANT(target, GCI_YellowBand);
		NODE_DEFINE_CONSTANT(target, GCI_BlackBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_YBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_CbBand);
		NODE_DEFINE_CONSTANT(target, GCI_YCbCr_CrBand);
		NODE_DEFINE_CONSTANT(target, GCI_Max);
	}

}

} // namespace node_gdal

NODE_MODULE(gdal, node_gdal::Init)
<|endoftext|>


<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
#error Use Qt 4.7 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  0
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.0.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;

private:
    QString m_userAgent;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
    m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script = file.readAll();
    file.close();

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<commit_msg>phantomjs: Allow PhantomJS to build with Qt 4.5 which is available for Cygwin. [jddalton]<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
#error Use Qt 4.5 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  0
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.0.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;

private:
    QString m_userAgent;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

    #if QT_VERSION < QT_VERSION_CHECK(4, 6, 0)
      m_page.settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
    #else
      m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
      m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
      m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
    #endif

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script = file.readAll();
    file.close();

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<|endoftext|>