<commit_before>// Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
// Distributed under the terms of the BSD license (see the LICENSE
// file for the exact terms).
// Email: hermes1d@googlegroups.com, home page: http://hpfem.org/

#include "transforms.h"

#define N_chebyshev_max (3+2*(MAX_P-1))

typedef double ChebyshevMatrix[N_chebyshev_max][N_chebyshev_max];
typedef double TransformationMatrix[N_chebyshev_max][MAX_P+1];
// for one particular p:
TransformationMatrix transformation_matrix;
// for all p:
TransformationMatrix transformation_matrix_list[MAX_P+1];
int transformation_matrix_initialized=0;

TransformationMatrix *get_transformation_matrix(int p)
{
    return & (transformation_matrix_list[p]);
}

void fill_chebyshev_points(int n, double *chebyshev_points)
{
    for (int i=0; i < n; i++)
        chebyshev_points[i] = -cos(i*M_PI/(n-1));
    /*
    for (int i=0; i < N_chebyshev_max; i++)
        printf("%f ", chebyshev_points[i]);
    printf("\n");
    printf("done.\n");
    */
}

// transform values from (-1, 0) to (-1, 1)
#define map_left(x) (2*x+1)
// transform values from (0, 1) to (-1, 1)
#define map_right(x) (2*x-1)

double phi(int i, double x)
{
    if (x < 0) {
        if (i == 0)
            return lobatto_fn_tab_1d[0](map_left(x));
        else if (i % 2 == 0)
            return 0;
        else
            return lobatto_fn_tab_1d[(i+1)/2](map_left(x));
    } else {
        if (i == 0)
            return 0;
        else if (i == 1)
            return lobatto_fn_tab_1d[0](map_left(x));
        else if (i % 2 == 1)
            return 0;
        else {
            return lobatto_fn_tab_1d[i/2](map_left(x));
        }
    }
}

void fill_chebyshev_matrix(int n, ChebyshevMatrix *chebyshev_matrix)
{
    double chebyshev_points[N_chebyshev_max];
    fill_chebyshev_points(n, chebyshev_points);
    for (int i=0; i < n; i++) {
        for (int j=0; j < n; j++) {
            //printf("XXX %d %d %f \n", i, j, phi(j, chebyshev_points[i]));
            //printf("XXX %d %d %f \n", i, j, (*chebyshev_matrix)[i][j]);
            (*chebyshev_matrix)[i][j] = phi(j, chebyshev_points[i]);
            //printf("%f ", (*chebyshev_matrix)[i][j]);
        }
        //printf("\n");
    }
    //error("stop.");
}

void fill_transformation_matrix(int p, int p_ref, TransformationMatrix
        transformation_matrix)
{
    double chebyshev_points[N_chebyshev_max];
    ChebyshevMatrix chebyshev_matrix;
    int n = 3+2*(p_ref-1);
    fill_chebyshev_points(n, chebyshev_points);
    fill_chebyshev_matrix(n, &chebyshev_matrix);

    for (int j=0; j < p+1; j++) {
        // FIXME: don't compute the matrix all the time, e.g.  move this out of
        // the cycle and make sure the gaussian elimination doesn't overwrite
        // the _mat.
        Matrix *_mat = new DenseMatrix(n);
        _mat->zero();
        for (int _i=0; _i < n; _i++)
            for (int _j=0; _j < n; _j++)
                _mat->add(_i, _j, (chebyshev_matrix)[_i][_j]);
        double f[n];
        for (int i=0; i < n; i++)
            f[i] = lobatto_fn_tab_1d[j](chebyshev_points[i]);
        solve_linear_system(_mat, f);
        for (int i=0; i < n; i++)
            transformation_matrix[i][j] = f[i];
    }
    for (int i=0; i < n; i++) {
        for (int j=0; j < p+1; j++) {
            printf("%f ", transformation_matrix[i][j]);
        }
        printf("\n");
    }
    error("stop.");
}

void transform_element_refined(int comp, double *y_prev, double *y_prev_ref, Element
        *e, Element *e_ref_left, Element *e_ref_right, Mesh *mesh, Mesh
        *mesh_ref)
{
    printf("ELEMENT: %d %f %f\n", e->id, e->x1, e->x2);
    double y_prev_loc[MAX_P+1];
    double y_prev_loc_trans[N_chebyshev_max+1];
    if (e->dof[comp][0] == -1)
        y_prev_loc[0] = mesh->bc_left_dir_values[comp];
    else
        y_prev_loc[0] = y_prev[e->dof[comp][0]];
    if (e->dof[comp][1] == -1)
        y_prev_loc[1] = mesh->bc_right_dir_values[comp];
    else
        y_prev_loc[1] = y_prev[e->dof[comp][1]];
    for (int i=2; i < e->p + 1; i++)
        y_prev_loc[i] = y_prev[e->dof[comp][i]];
    for (int i=0; i < e->p + 1; i++)
        printf("y_prev_loc[%d] = %f\n", i, y_prev_loc[i]);
    TransformationMatrix transformation_matrix;
    fill_transformation_matrix(e->p, e_ref_left->p, transformation_matrix);
    //fill_transformation_matrix();
    //double TransformationMatrix *transformation_matrix =
    //    get_transformation_matrix(e_ref_left->p + 1);
    for (int i=0; i < 3 + 2*(e_ref_left->p - 1); i++) {
        y_prev_loc_trans[i] = 0.;
        for (int j=0; j < e->p + 1; j++)
            y_prev_loc_trans[i] += transformation_matrix[i][j] * y_prev_loc[j];
    }
    for (int i=0; i < 3 + 2*(e_ref_left->p - 1); i++)
        printf("y_prev_loc_trans[%d] = %f\n", i, y_prev_loc_trans[i]);
    printf("----------------------\n");
    // copying computed coefficients into the elements e_ref_left and
    // e_ref_right
    if (e->dof[comp][0] != -1)
        y_prev_ref[e_ref_left->dof[comp][0]] = y_prev_loc_trans[0];
    y_prev_ref[e_ref_left->dof[comp][1]] = y_prev_loc_trans[1];
    y_prev_ref[e_ref_right->dof[comp][0]] = y_prev_loc_trans[1];
    if (e->dof[comp][1] != -1)
        y_prev_ref[e_ref_right->dof[comp][1]] = y_prev_loc_trans[2];
    if (e_ref_left->p != e_ref_right->p)
        error("internal error in transform_element: the left and right elements must have the same order.");
    int counter = 0;
    for (int p=2; p < e_ref_left->p + 1; p++) {
        y_prev_ref[e_ref_left->dof[comp][p]] = y_prev_loc_trans[3+counter];
        counter++;
        y_prev_ref[e_ref_right->dof[comp][p]] = y_prev_loc_trans[3+counter];
        counter++;
    }
}

void transform_element_unrefined(int comp, double *y_prev, double *y_prev_ref, Element
        *e, Element *e_ref, Mesh *mesh, Mesh *mesh_ref)
{
    for (int p=0; p < e->p + 1; p++) {
        if (e->dof[comp][p] != -1)
            y_prev_ref[e_ref->dof[comp][p]] = y_prev[e->dof[comp][p]];
    }
    for (int p=e->p+1; p < e_ref->p + 1; p++) {
        y_prev_ref[e_ref->dof[comp][p]] = 0.;
    }
}

/* This only works after the dofs are assigned in the reference (and coarse)
 * solution. */
void transfer_solution(Mesh *mesh, Mesh *mesh_ref, double *y_prev, double *y_prev_ref)
{
    Iterator *I = new Iterator(mesh);
    Iterator *I_ref = new Iterator(mesh_ref);
    Element *e, *e_ref, *e_ref_left, *e_ref_right;
    for (int comp=0; comp < mesh->get_n_eq(); comp++) {
        I->reset();
        I_ref->reset();
        while ((e = I->next_active_element()) != NULL) {
            e_ref = I_ref->next_active_element();
            if (e->level == e_ref->level)
                transform_element_unrefined(comp, y_prev, y_prev_ref, e,
                    e_ref, mesh, mesh_ref);
            else if (e->level + 1 == e_ref->level) {
                e_ref_left = e_ref;
                e_ref_right = I_ref->next_active_element();
                transform_element_refined(comp, y_prev, y_prev_ref, e,
                    e_ref_left, e_ref_right, mesh, mesh_ref);
            }
            else
                error("internal error in transfer_solution: element orders mismatch.");
        }
    }
}
<commit_msg>works<commit_after>// Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
// Distributed under the terms of the BSD license (see the LICENSE
// file for the exact terms).
// Email: hermes1d@googlegroups.com, home page: http://hpfem.org/

#include "transforms.h"

#define N_chebyshev_max (3+2*(MAX_P-1))

typedef double ChebyshevMatrix[N_chebyshev_max][N_chebyshev_max];
typedef double TransformationMatrix[N_chebyshev_max][MAX_P+1];
// for one particular p:
TransformationMatrix transformation_matrix;
// for all p:
TransformationMatrix transformation_matrix_list[MAX_P+1];
int transformation_matrix_initialized=0;

TransformationMatrix *get_transformation_matrix(int p)
{
    return & (transformation_matrix_list[p]);
}

void fill_chebyshev_points(int n, double *chebyshev_points)
{
    for (int i=0; i < n; i++)
        chebyshev_points[i] = -cos(i*M_PI/(n-1));
    /*
    for (int i=0; i < N_chebyshev_max; i++)
        printf("%f ", chebyshev_points[i]);
    printf("\n");
    printf("done.\n");
    */
}

// transform values from (-1, 0) to (-1, 1)
#define map_left(x) (2*x+1)
// transform values from (0, 1) to (-1, 1)
#define map_right(x) (2*x-1)

double phi(int i, double x)
{
    if (x < 0) {
        if (i == 0)
            return lobatto_fn_tab_1d[0](map_left(x));
        else if (i % 2 == 0)
            return 0;
        else
            return lobatto_fn_tab_1d[(i+1)/2](map_left(x));
    } else {
        if (i == 0)
            return 0;
        else if (i == 1)
            return lobatto_fn_tab_1d[0](map_right(x));
        else if (i % 2 == 1)
            return 0;
        else {
            return lobatto_fn_tab_1d[i/2](map_right(x));
        }
    }
}

void fill_chebyshev_matrix(int n, ChebyshevMatrix *chebyshev_matrix)
{
    double chebyshev_points[N_chebyshev_max];
    fill_chebyshev_points(n, chebyshev_points);
    for (int i=0; i < n; i++) {
        for (int j=0; j < n; j++) {
            //printf("XXX %d %d %f \n", i, j, phi(j, chebyshev_points[i]));
            //printf("XXX %d %d %f \n", i, j, (*chebyshev_matrix)[i][j]);
            (*chebyshev_matrix)[i][j] = phi(j, chebyshev_points[i]);
            //printf("%f ", (*chebyshev_matrix)[i][j]);
        }
        //printf("\n");
    }
    //error("stop.");
}

void fill_transformation_matrix(int p, int p_ref, TransformationMatrix
        transformation_matrix)
{
    double chebyshev_points[N_chebyshev_max];
    ChebyshevMatrix chebyshev_matrix;
    int n = 3+2*(p_ref-1);
    fill_chebyshev_points(n, chebyshev_points);
    fill_chebyshev_matrix(n, &chebyshev_matrix);

    for (int j=0; j < p+1; j++) {
        // FIXME: don't compute the matrix all the time, e.g.  move this out of
        // the cycle and make sure the gaussian elimination doesn't overwrite
        // the _mat.
        Matrix *_mat = new DenseMatrix(n);
        _mat->zero();
        for (int _i=0; _i < n; _i++)
            for (int _j=0; _j < n; _j++)
                _mat->add(_i, _j, chebyshev_matrix[_i][_j]);
        printf("chebyshev stuff:\n");
        for (int _i=0; _i < n; _i++) {
            for (int _j=0; _j < n; _j++) {
                printf("%f ", chebyshev_matrix[_i][_j]);
            }
            printf("\n");
        }
        printf("----- END ---- \n");
        double f[n];
        for (int i=0; i < n; i++)
            f[i] = lobatto_fn_tab_1d[j](chebyshev_points[i]);
        printf("chebyshev_points\n");
        for (int i=0; i < 5; i++)
            printf("%f ", chebyshev_points[i]);
        printf("\n");
        printf("XXXXXX\n");
        for (int i=0; i < n; i++)
            printf("%f ", f[i]);
        printf("\n");
        solve_linear_system(_mat, f);
        for (int i=0; i < n; i++)
            transformation_matrix[i][j] = f[i];
    }
    for (int i=0; i < n; i++) {
        for (int j=0; j < p+1; j++) {
            printf("%f ", transformation_matrix[i][j]);
        }
        printf("\n");
    }
    error("stop.");
}

void transform_element_refined(int comp, double *y_prev, double *y_prev_ref, Element
        *e, Element *e_ref_left, Element *e_ref_right, Mesh *mesh, Mesh
        *mesh_ref)
{
    printf("ELEMENT: %d %f %f\n", e->id, e->x1, e->x2);
    double y_prev_loc[MAX_P+1];
    double y_prev_loc_trans[N_chebyshev_max+1];
    if (e->dof[comp][0] == -1)
        y_prev_loc[0] = mesh->bc_left_dir_values[comp];
    else
        y_prev_loc[0] = y_prev[e->dof[comp][0]];
    if (e->dof[comp][1] == -1)
        y_prev_loc[1] = mesh->bc_right_dir_values[comp];
    else
        y_prev_loc[1] = y_prev[e->dof[comp][1]];
    for (int i=2; i < e->p + 1; i++)
        y_prev_loc[i] = y_prev[e->dof[comp][i]];
    for (int i=0; i < e->p + 1; i++)
        printf("y_prev_loc[%d] = %f\n", i, y_prev_loc[i]);
    TransformationMatrix transformation_matrix;
    fill_transformation_matrix(e->p, e_ref_left->p, transformation_matrix);
    //fill_transformation_matrix();
    //double TransformationMatrix *transformation_matrix =
    //    get_transformation_matrix(e_ref_left->p + 1);
    for (int i=0; i < 3 + 2*(e_ref_left->p - 1); i++) {
        y_prev_loc_trans[i] = 0.;
        for (int j=0; j < e->p + 1; j++)
            y_prev_loc_trans[i] += transformation_matrix[i][j] * y_prev_loc[j];
    }
    for (int i=0; i < 3 + 2*(e_ref_left->p - 1); i++)
        printf("y_prev_loc_trans[%d] = %f\n", i, y_prev_loc_trans[i]);
    printf("----------------------\n");
    // copying computed coefficients into the elements e_ref_left and
    // e_ref_right
    if (e->dof[comp][0] != -1)
        y_prev_ref[e_ref_left->dof[comp][0]] = y_prev_loc_trans[0];
    y_prev_ref[e_ref_left->dof[comp][1]] = y_prev_loc_trans[1];
    y_prev_ref[e_ref_right->dof[comp][0]] = y_prev_loc_trans[1];
    if (e->dof[comp][1] != -1)
        y_prev_ref[e_ref_right->dof[comp][1]] = y_prev_loc_trans[2];
    if (e_ref_left->p != e_ref_right->p)
        error("internal error in transform_element: the left and right elements must have the same order.");
    int counter = 0;
    for (int p=2; p < e_ref_left->p + 1; p++) {
        y_prev_ref[e_ref_left->dof[comp][p]] = y_prev_loc_trans[3+counter];
        counter++;
        y_prev_ref[e_ref_right->dof[comp][p]] = y_prev_loc_trans[3+counter];
        counter++;
    }
}

void transform_element_unrefined(int comp, double *y_prev, double *y_prev_ref, Element
        *e, Element *e_ref, Mesh *mesh, Mesh *mesh_ref)
{
    for (int p=0; p < e->p + 1; p++) {
        if (e->dof[comp][p] != -1)
            y_prev_ref[e_ref->dof[comp][p]] = y_prev[e->dof[comp][p]];
    }
    for (int p=e->p+1; p < e_ref->p + 1; p++) {
        y_prev_ref[e_ref->dof[comp][p]] = 0.;
    }
}

/* This only works after the dofs are assigned in the reference (and coarse)
 * solution. */
void transfer_solution(Mesh *mesh, Mesh *mesh_ref, double *y_prev, double *y_prev_ref)
{
    Iterator *I = new Iterator(mesh);
    Iterator *I_ref = new Iterator(mesh_ref);
    Element *e, *e_ref, *e_ref_left, *e_ref_right;
    for (int comp=0; comp < mesh->get_n_eq(); comp++) {
        I->reset();
        I_ref->reset();
        while ((e = I->next_active_element()) != NULL) {
            e_ref = I_ref->next_active_element();
            if (e->level == e_ref->level)
                transform_element_unrefined(comp, y_prev, y_prev_ref, e,
                    e_ref, mesh, mesh_ref);
            else if (e->level + 1 == e_ref->level) {
                e_ref_left = e_ref;
                e_ref_right = I_ref->next_active_element();
                transform_element_refined(comp, y_prev, y_prev_ref, e,
                    e_ref_left, e_ref_right, mesh, mesh_ref);
            }
            else
                error("internal error in transfer_solution: element orders mismatch.");
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <system_error>
#include <cerrno>

#include <experimental/filesystem>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <array>

#include "components/searcher.hpp"
#include "components/menu.hpp"
#include "utils.hpp"

namespace fs = std::experimental::filesystem;
namespace py = pybind11;

namespace bookwyrm {

searcher::searcher(const item &wanted)
    : wanted_(wanted)
{
#ifdef DEBUG
    /* Bookwyrm must be run from build/. */
    const auto source_path = fs::canonical(fs::path("../src/sources"));
#else
    const std::array<fs::path, 2> paths = {"/etc/bookwyrm/sources",
                                           "~/.config/bookwyrm/sources"};
#endif
    /* Append source_path to Python's sys.path. */
    auto sys_path = py::reinterpret_borrow<py::list>(py::module::import("sys").attr("path"));
    sys_path.append(source_path.c_str());

    /*
     * Find all Python modules and populate the
     * list of sources by loading them.
     *
     * The first occurance of a module will be imported,
     * the latter ones will be ignored by Python. So we
     * either need to prepend the paths to sys.path, or
     * make sure that we don't clash with the many module
     * names in Python.
     */
    string module_file;
    for (const fs::path &p : fs::directory_iterator(source_path)) {
        module_file = p.filename();
        auto file_ext_pos = module_file.rfind(".py");

        if (file_ext_pos == string::npos) {
            /*
             * It's not a Python module.
             * (or at least doesn't contain ".py"
             */
            continue;
        }

        if (!utils::valid_file(p)) {
            _logger->warn("can't load module '{}': not a regular file or unreadable"
                    "; ignoring...",
                    module_file);
            continue;
        }

        module_file.resize(file_ext_pos);

        try {
            _logger->debug("loading module '{}'...", module_file);
            sources_.emplace_back(py::module::import(module_file.c_str()));
        } catch (const py::error_already_set &err) {
            // This is printed on on termbox, we might want to save these
            // until the program closes down.
            _logger->warn("{}; ignoring...", err.what());
        }
    }

    if (sources_.empty())
        throw program_error("couldn't find any sources, terminating...");
}

searcher::~searcher()
{
    /*
     * Current behaviour is that the program cannot terminate unless
     * all source threads has joined. We'll of course want do to this.
     *
     * It's not possible to end a std::thread in a smooth matter. We could
     * instead have a control variable that the source scripts check every
     * once in a while. When this is set upon quitting the curses UI, we'll
     * have to let each script handle its own termination.
     */
    py::gil_scoped_release nogil;

    for (auto &t : threads_)
        t.join();
}

searcher& searcher::async_search()
{
    for (const auto &m : sources_) {
        try {
            threads_.emplace_back([m, this]() {
                py::gil_scoped_acquire gil;
                m.attr("find")(this->wanted_, this);
            });
        } catch (const py::error_already_set &err) {
            _logger->error("module '{}' did something wrong ({}); ignoring...",
                    m.attr("__name__").cast<string>(), err.what());
            continue;
        }
    }

    /* Convenience; only to chain member functions. */
    return *this;
}

void searcher::display_menu()
{
    menu_.display();
}

void searcher::append_item(std::tuple<nonexacts_t, exacts_t> item_comps)
{
    item item(item_comps);
    /* if (!item.matches(wanted_)) */
        /* return; */

    std::lock_guard<std::mutex> guard(items_mutex_);
    items_.push_back(item);
    menu_.update();
}

/* ns bookwyrm */
}
<commit_msg>searcher: remove note about printing on tb window<commit_after>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <system_error>
#include <cerrno>

#include <experimental/filesystem>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <array>

#include "components/searcher.hpp"
#include "components/menu.hpp"
#include "utils.hpp"

namespace fs = std::experimental::filesystem;
namespace py = pybind11;

namespace bookwyrm {

searcher::searcher(const item &wanted)
    : wanted_(wanted)
{
#ifdef DEBUG
    /* Bookwyrm must be run from build/. */
    const auto source_path = fs::canonical(fs::path("../src/sources"));
#else
    const std::array<fs::path, 2> paths = {"/etc/bookwyrm/sources",
                                           "~/.config/bookwyrm/sources"};
#endif
    /* Append source_path to Python's sys.path. */
    auto sys_path = py::reinterpret_borrow<py::list>(py::module::import("sys").attr("path"));
    sys_path.append(source_path.c_str());

    /*
     * Find all Python modules and populate the
     * list of sources by loading them.
     *
     * The first occurance of a module will be imported,
     * the latter ones will be ignored by Python. So we
     * either need to prepend the paths to sys.path, or
     * make sure that we don't clash with the many module
     * names in Python.
     */
    string module_file;
    for (const fs::path &p : fs::directory_iterator(source_path)) {
        module_file = p.filename();
        auto file_ext_pos = module_file.rfind(".py");

        if (file_ext_pos == string::npos) {
            /*
             * It's not a Python module.
             * (or at least doesn't contain ".py"
             */
            continue;
        }

        if (!utils::valid_file(p)) {
            _logger->warn("can't load module '{}': not a regular file or unreadable"
                    "; ignoring...",
                    module_file);
            continue;
        }

        module_file.resize(file_ext_pos);

        try {
            _logger->debug("loading module '{}'...", module_file);
            sources_.emplace_back(py::module::import(module_file.c_str()));
        } catch (const py::error_already_set &err) {
            _logger->warn("{}; ignoring...", err.what());
        }
    }

    if (sources_.empty())
        throw program_error("couldn't find any sources, terminating...");
}

searcher::~searcher()
{
    /*
     * Current behaviour is that the program cannot terminate unless
     * all source threads has joined. We'll of course want do to this.
     *
     * It's not possible to end a std::thread in a smooth matter. We could
     * instead have a control variable that the source scripts check every
     * once in a while. When this is set upon quitting the curses UI, we'll
     * have to let each script handle its own termination.
     */
    py::gil_scoped_release nogil;

    for (auto &t : threads_)
        t.join();
}

searcher& searcher::async_search()
{
    for (const auto &m : sources_) {
        try {
            threads_.emplace_back([m, this]() {
                py::gil_scoped_acquire gil;
                m.attr("find")(this->wanted_, this);
            });
        } catch (const py::error_already_set &err) {
            _logger->error("module '{}' did something wrong ({}); ignoring...",
                    m.attr("__name__").cast<string>(), err.what());
            continue;
        }
    }

    /* Convenience; only to chain member functions. */
    return *this;
}

void searcher::display_menu()
{
    menu_.display();
}

void searcher::append_item(std::tuple<nonexacts_t, exacts_t> item_comps)
{
    item item(item_comps);
    /* if (!item.matches(wanted_)) */
        /* return; */

    std::lock_guard<std::mutex> guard(items_mutex_);
    items_.push_back(item);
    menu_.update();
}

/* ns bookwyrm */
}
<|endoftext|>


<commit_before>#include "libtorrent/udp_socket.hpp"
#include "libtorrent/connection_queue.hpp"
#include <stdlib.h>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/array.hpp>
#include <asio/read.hpp>

using namespace libtorrent;

udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c
	, connection_queue& cc)
	: m_callback(c)
	, m_ipv4_sock(ios)
	, m_ipv6_sock(ios)
	, m_bind_port(0)
	, m_socks5_sock(ios)
	, m_connection_ticket(-1)
	, m_cc(cc)
	, m_resolver(ios)
	, m_tunnel_packets(false)
{
}

void udp_socket::send(udp::endpoint const& ep, char const* p, int len)
{
	if (m_tunnel_packets)
	{
		// send udp packets through SOCKS5 server
		wrap(ep, p, len);
		return;
	}

	asio::error_code ec;
	if (ep.address().is_v4() && m_ipv4_sock.is_open())
		m_ipv4_sock.send_to(asio::buffer(p, len), ep, 0, ec);
	else
		m_ipv6_sock.send_to(asio::buffer(p, len), ep, 0, ec);
}

void udp_socket::on_read(udp::socket* s, asio::error_code const& e, std::size_t bytes_transferred)
{
	if (e) return;
	if (!m_callback) return;

	if (s == &m_ipv4_sock)
	{
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif

		if (m_tunnel_packets && m_v4_ep == m_proxy_addr)
			unwrap(m_v4_buf, bytes_transferred);
		else
			m_callback(m_v4_ep, m_v4_buf, bytes_transferred);

#ifndef BOOST_NO_EXCEPTIONS
		} catch(std::exception&) {}
#endif
		s->async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
			, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
	}
	else
	{
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif

		if (m_tunnel_packets && m_v6_ep == m_proxy_addr)
			unwrap(m_v6_buf, bytes_transferred);
		else
			m_callback(m_v6_ep, m_v6_buf, bytes_transferred);

#ifndef BOOST_NO_EXCEPTIONS
		} catch(std::exception&) {}
#endif
		s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
			, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
	}
}

void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len)
{
	using namespace libtorrent::detail;

	char header[20];
	char* h = header;

	write_uint16(0, h); // reserved
	write_uint8(0, h); // fragment
	write_uint8(ep.address().is_v4()?1:4, h); // atyp
	write_address(ep.address(), h);
	write_uint16(ep.port(), h);

	boost::array<asio::const_buffer, 2> iovec;
	iovec[0] = asio::const_buffer(header, h - header);
	iovec[1] = asio::const_buffer(p, len);

	asio::error_code ec;
	if (m_proxy_addr.address().is_v4() && m_ipv4_sock.is_open())
		m_ipv4_sock.send_to(iovec, m_proxy_addr, 0, ec);
	else
		m_ipv6_sock.send_to(iovec, m_proxy_addr, 0, ec);
}

// unwrap the UDP packet from the SOCKS5 header
void udp_socket::unwrap(char const* buf, int size)
{
	using namespace libtorrent::detail;

	// the minimum socks5 header size
	if (size <= 10) return;

	char const* p = buf;
	p += 2; // reserved
	int frag = read_uint8(p);
	// fragmentation is not supported
	if (frag != 0) return;

	udp::endpoint sender;

	int atyp = read_uint8(p);
	if (atyp == 1)
	{
		// IPv4
		sender.address(address_v4(read_uint32(p)));
		sender.port(read_uint16(p));
	}
	else if (atyp == 4)
	{
		// IPv6
		TORRENT_ASSERT(false && "not supported yet");

	}
	else
	{
		// domain name not supported
		return;
	}

	m_callback(sender, p, size - (p - buf));
}

void udp_socket::close()
{
	m_ipv4_sock.close();
	m_ipv6_sock.close();
	m_socks5_sock.close();
	m_callback.clear();
	if (m_connection_ticket >= 0)
	{
		m_cc.done(m_connection_ticket);
		m_connection_ticket = -1;
	}
}

void udp_socket::bind(int port)
{
	asio::error_code ec;

	if (m_ipv4_sock.is_open()) m_ipv4_sock.close();
	if (m_ipv6_sock.is_open()) m_ipv6_sock.close();

	m_ipv4_sock.open(udp::v4(), ec);
	if (!ec)
	{
		m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec);
		m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
			, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
	}
	m_ipv6_sock.open(udp::v6(), ec);
	if (!ec)
	{
		m_ipv6_sock.set_option(v6only(true), ec);
		m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec);
		m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
			, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
	}
	m_bind_port = port;
}

void udp_socket::set_proxy_settings(proxy_settings const& ps)
{
	m_socks5_sock.close();
	m_tunnel_packets = false;

	m_proxy_settings = ps;

	if (ps.type == proxy_settings::socks5
		|| ps.type == proxy_settings::socks5_pw)
	{
		// connect to socks5 server and open up the UDP tunnel
		tcp::resolver::query q(ps.hostname
			, boost::lexical_cast<std::string>(ps.port));
		m_resolver.async_resolve(q, boost::bind(
			&udp_socket::on_name_lookup, this, _1, _2));
	}
}

void udp_socket::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i)
{
	if (e) return;
	m_proxy_addr.address(i->endpoint().address());
	m_proxy_addr.port(i->endpoint().port());
	m_cc.enqueue(boost::bind(&udp_socket::on_connect, this, _1)
		, boost::bind(&udp_socket::on_timeout, this), seconds(10));
}

void udp_socket::on_timeout()
{
	m_socks5_sock.close();
	m_connection_ticket = -1;
}

void udp_socket::on_connect(int ticket)
{
	m_connection_ticket = ticket;
	asio::error_code ec;
	m_socks5_sock.open(m_proxy_addr.address().is_v4()?tcp::v4():tcp::v6(), ec);
	m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port())
		, boost::bind(&udp_socket::on_connected, this, _1));
}

void udp_socket::on_connected(asio::error_code const& e)
{
	m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;
	if (e) return;

	using namespace libtorrent::detail;

	// send SOCKS5 authentication methods
	char* p = &m_tmp_buf[0];
	write_uint8(5, p); // SOCKS VERSION 5
	if (m_proxy_settings.username.empty()
		|| m_proxy_settings.type == proxy_settings::socks5)
	{
		write_uint8(1, p); // 1 authentication method (no auth)
		write_uint8(0, p); // no authentication
	}
	else
	{
		write_uint8(2, p); // 2 authentication methods
		write_uint8(0, p); // no authentication
		write_uint8(2, p); // username/password
	}
	asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
		, boost::bind(&udp_socket::handshake1, this, _1));
}

void udp_socket::handshake1(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2)
		, boost::bind(&udp_socket::handshake2, this, _1));
}

void udp_socket::handshake2(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p);
	int method = read_uint8(p);

	if (version < 5) return;

	if (method == 0)
	{
		socks_forward_udp();
	}
	else if (method == 2)
	{
		if (m_proxy_settings.username.empty())
		{
			m_socks5_sock.close();
			return;
		}

		// start sub-negotiation
		char* p = &m_tmp_buf[0];
		write_uint8(1, p);
		write_uint8(m_proxy_settings.username.size(), p);
		write_string(m_proxy_settings.username, p);
		write_uint8(m_proxy_settings.password.size(), p);
		write_string(m_proxy_settings.password, p);
		asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
			, boost::bind(&udp_socket::handshake3, this, _1));
	}
	else
	{
		m_socks5_sock.close();
		return;
	}
}

void udp_socket::handshake3(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2)
		, boost::bind(&udp_socket::handshake4, this, _1));
}

void udp_socket::handshake4(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p);
	int status = read_uint8(p);

	if (version != 1) return;
	if (status != 0) return;

	socks_forward_udp();
}

void udp_socket::socks_forward_udp()
{
	using namespace libtorrent::detail;

	// send SOCKS5 UDP command
	char* p = &m_tmp_buf[0];
	write_uint8(5, p); // SOCKS VERSION 5
	write_uint8(3, p); // UDP ASSOCIATE command
	write_uint8(0, p); // reserved
	write_uint8(0, p); // ATYP IPv4
	write_uint32(0, p); // IP any
	write_uint16(m_bind_port, p);

	asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
		, boost::bind(&udp_socket::connect1, this, _1));
}

void udp_socket::connect1(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10)
		, boost::bind(&udp_socket::connect2, this, _1));
}

void udp_socket::connect2(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p); // VERSION
	int status = read_uint8(p); // STATUS
	read_uint8(p); // RESERVED
	int atyp = read_uint8(p); // address type

	if (version != 5) return;
	if (status != 0) return;

	if (atyp == 1)
	{
		m_proxy_addr.address(address_v4(read_uint32(p)));
		m_proxy_addr.port(read_uint16(p));
	}
	else
	{
		// in this case we need to read more data from the socket
		TORRENT_ASSERT(false && "not implemented yet!");
	}

	m_tunnel_packets = true;
}

<commit_msg>made udp_socket not use exception<commit_after>#include "libtorrent/udp_socket.hpp"
#include "libtorrent/connection_queue.hpp"
#include <stdlib.h>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/array.hpp>
#include <asio/read.hpp>

using namespace libtorrent;

udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c
	, connection_queue& cc)
	: m_callback(c)
	, m_ipv4_sock(ios)
	, m_ipv6_sock(ios)
	, m_bind_port(0)
	, m_socks5_sock(ios)
	, m_connection_ticket(-1)
	, m_cc(cc)
	, m_resolver(ios)
	, m_tunnel_packets(false)
{
}

void udp_socket::send(udp::endpoint const& ep, char const* p, int len)
{
	if (m_tunnel_packets)
	{
		// send udp packets through SOCKS5 server
		wrap(ep, p, len);
		return;
	}

	asio::error_code ec;
	if (ep.address().is_v4() && m_ipv4_sock.is_open())
		m_ipv4_sock.send_to(asio::buffer(p, len), ep, 0, ec);
	else
		m_ipv6_sock.send_to(asio::buffer(p, len), ep, 0, ec);
}

void udp_socket::on_read(udp::socket* s, asio::error_code const& e, std::size_t bytes_transferred)
{
	if (e) return;
	if (!m_callback) return;

	if (s == &m_ipv4_sock)
	{
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif

		if (m_tunnel_packets && m_v4_ep == m_proxy_addr)
			unwrap(m_v4_buf, bytes_transferred);
		else
			m_callback(m_v4_ep, m_v4_buf, bytes_transferred);

#ifndef BOOST_NO_EXCEPTIONS
		} catch(std::exception&) {}
#endif
		s->async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
			, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
	}
	else
	{
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif

		if (m_tunnel_packets && m_v6_ep == m_proxy_addr)
			unwrap(m_v6_buf, bytes_transferred);
		else
			m_callback(m_v6_ep, m_v6_buf, bytes_transferred);

#ifndef BOOST_NO_EXCEPTIONS
		} catch(std::exception&) {}
#endif
		s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
			, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
	}
}

void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len)
{
	using namespace libtorrent::detail;

	char header[20];
	char* h = header;

	write_uint16(0, h); // reserved
	write_uint8(0, h); // fragment
	write_uint8(ep.address().is_v4()?1:4, h); // atyp
	write_address(ep.address(), h);
	write_uint16(ep.port(), h);

	boost::array<asio::const_buffer, 2> iovec;
	iovec[0] = asio::const_buffer(header, h - header);
	iovec[1] = asio::const_buffer(p, len);

	asio::error_code ec;
	if (m_proxy_addr.address().is_v4() && m_ipv4_sock.is_open())
		m_ipv4_sock.send_to(iovec, m_proxy_addr, 0, ec);
	else
		m_ipv6_sock.send_to(iovec, m_proxy_addr, 0, ec);
}

// unwrap the UDP packet from the SOCKS5 header
void udp_socket::unwrap(char const* buf, int size)
{
	using namespace libtorrent::detail;

	// the minimum socks5 header size
	if (size <= 10) return;

	char const* p = buf;
	p += 2; // reserved
	int frag = read_uint8(p);
	// fragmentation is not supported
	if (frag != 0) return;

	udp::endpoint sender;

	int atyp = read_uint8(p);
	if (atyp == 1)
	{
		// IPv4
		sender.address(address_v4(read_uint32(p)));
		sender.port(read_uint16(p));
	}
	else if (atyp == 4)
	{
		// IPv6
		TORRENT_ASSERT(false && "not supported yet");

	}
	else
	{
		// domain name not supported
		return;
	}

	m_callback(sender, p, size - (p - buf));
}

void udp_socket::close()
{
	asio::error_code ec;
	m_ipv4_sock.close(ec);
	m_ipv6_sock.close(ec);
	m_socks5_sock.close(ec);
	m_callback.clear();
	if (m_connection_ticket >= 0)
	{
		m_cc.done(m_connection_ticket);
		m_connection_ticket = -1;
	}
}

void udp_socket::bind(int port)
{
	asio::error_code ec;

	if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
	if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);

	m_ipv4_sock.open(udp::v4(), ec);
	if (!ec)
	{
		m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec);
		m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
			, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
	}
	m_ipv6_sock.open(udp::v6(), ec);
	if (!ec)
	{
		m_ipv6_sock.set_option(v6only(true), ec);
		m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec);
		m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
			, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
	}
	m_bind_port = port;
}

void udp_socket::set_proxy_settings(proxy_settings const& ps)
{
	asio::error_code ec;
	m_socks5_sock.close(ec);
	m_tunnel_packets = false;

	m_proxy_settings = ps;

	if (ps.type == proxy_settings::socks5
		|| ps.type == proxy_settings::socks5_pw)
	{
		// connect to socks5 server and open up the UDP tunnel
		tcp::resolver::query q(ps.hostname
			, boost::lexical_cast<std::string>(ps.port));
		m_resolver.async_resolve(q, boost::bind(
			&udp_socket::on_name_lookup, this, _1, _2));
	}
}

void udp_socket::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i)
{
	if (e) return;
	m_proxy_addr.address(i->endpoint().address());
	m_proxy_addr.port(i->endpoint().port());
	m_cc.enqueue(boost::bind(&udp_socket::on_connect, this, _1)
		, boost::bind(&udp_socket::on_timeout, this), seconds(10));
}

void udp_socket::on_timeout()
{
	asio::error_code ec;
	m_socks5_sock.close(ec);
	m_connection_ticket = -1;
}

void udp_socket::on_connect(int ticket)
{
	m_connection_ticket = ticket;
	asio::error_code ec;
	m_socks5_sock.open(m_proxy_addr.address().is_v4()?tcp::v4():tcp::v6(), ec);
	m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port())
		, boost::bind(&udp_socket::on_connected, this, _1));
}

void udp_socket::on_connected(asio::error_code const& e)
{
	m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;
	if (e) return;

	using namespace libtorrent::detail;

	// send SOCKS5 authentication methods
	char* p = &m_tmp_buf[0];
	write_uint8(5, p); // SOCKS VERSION 5
	if (m_proxy_settings.username.empty()
		|| m_proxy_settings.type == proxy_settings::socks5)
	{
		write_uint8(1, p); // 1 authentication method (no auth)
		write_uint8(0, p); // no authentication
	}
	else
	{
		write_uint8(2, p); // 2 authentication methods
		write_uint8(0, p); // no authentication
		write_uint8(2, p); // username/password
	}
	asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
		, boost::bind(&udp_socket::handshake1, this, _1));
}

void udp_socket::handshake1(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2)
		, boost::bind(&udp_socket::handshake2, this, _1));
}

void udp_socket::handshake2(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p);
	int method = read_uint8(p);

	if (version < 5) return;

	if (method == 0)
	{
		socks_forward_udp();
	}
	else if (method == 2)
	{
		if (m_proxy_settings.username.empty())
		{
			asio::error_code ec;
			m_socks5_sock.close(ec);
			return;
		}

		// start sub-negotiation
		char* p = &m_tmp_buf[0];
		write_uint8(1, p);
		write_uint8(m_proxy_settings.username.size(), p);
		write_string(m_proxy_settings.username, p);
		write_uint8(m_proxy_settings.password.size(), p);
		write_string(m_proxy_settings.password, p);
		asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
			, boost::bind(&udp_socket::handshake3, this, _1));
	}
	else
	{
		asio::error_code ec;
		m_socks5_sock.close(ec);
		return;
	}
}

void udp_socket::handshake3(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2)
		, boost::bind(&udp_socket::handshake4, this, _1));
}

void udp_socket::handshake4(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p);
	int status = read_uint8(p);

	if (version != 1) return;
	if (status != 0) return;

	socks_forward_udp();
}

void udp_socket::socks_forward_udp()
{
	using namespace libtorrent::detail;

	// send SOCKS5 UDP command
	char* p = &m_tmp_buf[0];
	write_uint8(5, p); // SOCKS VERSION 5
	write_uint8(3, p); // UDP ASSOCIATE command
	write_uint8(0, p); // reserved
	write_uint8(0, p); // ATYP IPv4
	write_uint32(0, p); // IP any
	write_uint16(m_bind_port, p);

	asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf)
		, boost::bind(&udp_socket::connect1, this, _1));
}

void udp_socket::connect1(asio::error_code const& e)
{
	if (e) return;

	asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10)
		, boost::bind(&udp_socket::connect2, this, _1));
}

void udp_socket::connect2(asio::error_code const& e)
{
	if (e) return;

	using namespace libtorrent::detail;

	char* p = &m_tmp_buf[0];
	int version = read_uint8(p); // VERSION
	int status = read_uint8(p); // STATUS
	read_uint8(p); // RESERVED
	int atyp = read_uint8(p); // address type

	if (version != 5) return;
	if (status != 0) return;

	if (atyp == 1)
	{
		m_proxy_addr.address(address_v4(read_uint32(p)));
		m_proxy_addr.port(read_uint16(p));
	}
	else
	{
		// in this case we need to read more data from the socket
		TORRENT_ASSERT(false && "not implemented yet!");
	}

	m_tunnel_packets = true;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: XMLFootnoteSeparatorExport.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 15:32:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _XMLOFF_XMLFOOTNOTESEPARATOREXPORT_HXX
#include "XMLFootnoteSeparatorExport.hxx"
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_XMLEXP_HXX
#include <xmloff/xmlexp.hxx>
#endif

#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif

#ifndef _XMLOFF_XMLUCONV_HXX
#include <xmloff/xmluconv.hxx>
#endif

#ifndef _XMLOFF_XMLTOKEN_HXX
#include <xmloff/xmltoken.hxx>
#endif

#ifndef _XMLOFF_PROPERTYSETMAPPER_HXX
#include <xmloff/xmlprmap.hxx>
#endif

#ifndef _XMLOFF_PAGEMASTERSTYLEMAP_HXX
#include <xmloff/PageMasterStyleMap.hxx>
#endif

#ifndef _COM_SUN_STAR_TEXT_HORIZONTALADJUST_HPP_
#include <com/sun/star/text/HorizontalAdjust.hpp>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

using namespace ::com::sun::star;
using namespace ::xmloff::token;
using ::rtl::OUStringBuffer;
using ::std::vector;

XMLFootnoteSeparatorExport::XMLFootnoteSeparatorExport(SvXMLExport& rExp) :
    rExport(rExp)
{
}

XMLFootnoteSeparatorExport::~XMLFootnoteSeparatorExport()
{
}

static const SvXMLEnumMapEntry aXML_HorizontalAdjust_Enum[] =
{
    { XML_LEFT,     text::HorizontalAdjust_LEFT },
    { XML_CENTER,   text::HorizontalAdjust_CENTER },
    { XML_RIGHT,    text::HorizontalAdjust_RIGHT },
    { XML_TOKEN_INVALID, 0 }
};

void XMLFootnoteSeparatorExport::exportXML(
    const vector<XMLPropertyState> * pProperties,
    sal_uInt32
    #ifdef DBG_UTIL
    nIdx
    #endif
    ,
    const UniReference<XMLPropertySetMapper> & rMapper)
{
    DBG_ASSERT(NULL != pProperties, "Need property states");

    // intialize values
    sal_Int16 eLineAdjust = text::HorizontalAdjust_LEFT;
    sal_Int32 nLineColor = 0;
    sal_Int32 nLineDistance = 0;
    sal_Int8 nLineRelWidth = 0;
    sal_Int32 nLineTextDistance = 0;
    sal_Int16 nLineWeight = 0;

    // find indices into property map and get values
    sal_uInt32 nCount = pProperties->size();
    for(sal_uInt32 i = 0; i < nCount; i++)
    {
        const XMLPropertyState& rState = (*pProperties)[i];

        if( rState.mnIndex == -1 )
            continue;

        switch (rMapper->GetEntryContextId(rState.mnIndex))
        {
        case CTF_PM_FTN_LINE_ADJUST:
            rState.maValue >>= eLineAdjust;
            break;
        case CTF_PM_FTN_LINE_COLOR:
            rState.maValue >>= nLineColor;
            break;
        case CTF_PM_FTN_DISTANCE:
            rState.maValue >>= nLineDistance;
            break;
        case CTF_PM_FTN_LINE_WIDTH:
            rState.maValue >>= nLineRelWidth;
            break;
        case CTF_PM_FTN_LINE_DISTANCE:
            rState.maValue >>= nLineTextDistance;
            break;
        case CTF_PM_FTN_LINE_WEIGTH:
            DBG_ASSERT( i == nIdx,
                        "received wrong property state index" );
            rState.maValue >>= nLineWeight;
            break;
        }
    }

    OUStringBuffer sBuf;

    // weight/width
    if (nLineWeight > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf, nLineWeight);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_WIDTH,
                             sBuf.makeStringAndClear());
    }

    // line text distance
    if (nLineTextDistance > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf,nLineTextDistance);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_BEFORE_SEP,
                             sBuf.makeStringAndClear());
    }

    // line distance
    if (nLineDistance > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf, nLineDistance);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_AFTER_SEP,
                             sBuf.makeStringAndClear());
    }

    // adjustment
    if (rExport.GetMM100UnitConverter().convertEnum(
        sBuf, eLineAdjust, aXML_HorizontalAdjust_Enum))
    {
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_ADJUSTMENT,
                             sBuf.makeStringAndClear());
    }

    // relative line width
    SvXMLUnitConverter::convertPercent(sBuf, nLineRelWidth);
    rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_REL_WIDTH,
                         sBuf.makeStringAndClear());

    // color
    rExport.GetMM100UnitConverter().convertColor(sBuf, nLineColor);
    rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_COLOR,
                         sBuf.makeStringAndClear());

    SvXMLElementExport aElem(rExport, XML_NAMESPACE_STYLE,
                             XML_FOOTNOTE_SEP, sal_True, sal_True);
}
<commit_msg>INTEGRATION: CWS changefileheader (1.11.162); FILE MERGED 2008/04/01 16:09:54 thb 1.11.162.3: #i85898# Stripping all external header guards 2008/04/01 13:05:00 thb 1.11.162.2: #i85898# Stripping all external header guards 2008/03/31 16:28:21 rt 1.11.162.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: XMLFootnoteSeparatorExport.cxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"
#include "XMLFootnoteSeparatorExport.hxx"
#include <tools/debug.hxx>
#include <xmloff/xmlexp.hxx>
#include "xmlnmspe.hxx"
#include <xmloff/xmluconv.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlprmap.hxx>

#ifndef _XMLOFF_PAGEMASTERSTYLEMAP_HXX
#include <xmloff/PageMasterStyleMap.hxx>
#endif
#include <com/sun/star/text/HorizontalAdjust.hpp>
#include <rtl/ustrbuf.hxx>

using namespace ::com::sun::star;
using namespace ::xmloff::token;
using ::rtl::OUStringBuffer;
using ::std::vector;

XMLFootnoteSeparatorExport::XMLFootnoteSeparatorExport(SvXMLExport& rExp) :
    rExport(rExp)
{
}

XMLFootnoteSeparatorExport::~XMLFootnoteSeparatorExport()
{
}

static const SvXMLEnumMapEntry aXML_HorizontalAdjust_Enum[] =
{
    { XML_LEFT,     text::HorizontalAdjust_LEFT },
    { XML_CENTER,   text::HorizontalAdjust_CENTER },
    { XML_RIGHT,    text::HorizontalAdjust_RIGHT },
    { XML_TOKEN_INVALID, 0 }
};

void XMLFootnoteSeparatorExport::exportXML(
    const vector<XMLPropertyState> * pProperties,
    sal_uInt32
    #ifdef DBG_UTIL
    nIdx
    #endif
    ,
    const UniReference<XMLPropertySetMapper> & rMapper)
{
    DBG_ASSERT(NULL != pProperties, "Need property states");

    // intialize values
    sal_Int16 eLineAdjust = text::HorizontalAdjust_LEFT;
    sal_Int32 nLineColor = 0;
    sal_Int32 nLineDistance = 0;
    sal_Int8 nLineRelWidth = 0;
    sal_Int32 nLineTextDistance = 0;
    sal_Int16 nLineWeight = 0;

    // find indices into property map and get values
    sal_uInt32 nCount = pProperties->size();
    for(sal_uInt32 i = 0; i < nCount; i++)
    {
        const XMLPropertyState& rState = (*pProperties)[i];

        if( rState.mnIndex == -1 )
            continue;

        switch (rMapper->GetEntryContextId(rState.mnIndex))
        {
        case CTF_PM_FTN_LINE_ADJUST:
            rState.maValue >>= eLineAdjust;
            break;
        case CTF_PM_FTN_LINE_COLOR:
            rState.maValue >>= nLineColor;
            break;
        case CTF_PM_FTN_DISTANCE:
            rState.maValue >>= nLineDistance;
            break;
        case CTF_PM_FTN_LINE_WIDTH:
            rState.maValue >>= nLineRelWidth;
            break;
        case CTF_PM_FTN_LINE_DISTANCE:
            rState.maValue >>= nLineTextDistance;
            break;
        case CTF_PM_FTN_LINE_WEIGTH:
            DBG_ASSERT( i == nIdx,
                        "received wrong property state index" );
            rState.maValue >>= nLineWeight;
            break;
        }
    }

    OUStringBuffer sBuf;

    // weight/width
    if (nLineWeight > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf, nLineWeight);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_WIDTH,
                             sBuf.makeStringAndClear());
    }

    // line text distance
    if (nLineTextDistance > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf,nLineTextDistance);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_BEFORE_SEP,
                             sBuf.makeStringAndClear());
    }

    // line distance
    if (nLineDistance > 0)
    {
        rExport.GetMM100UnitConverter().convertMeasure(sBuf, nLineDistance);
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_AFTER_SEP,
                             sBuf.makeStringAndClear());
    }

    // adjustment
    if (rExport.GetMM100UnitConverter().convertEnum(
        sBuf, eLineAdjust, aXML_HorizontalAdjust_Enum))
    {
        rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_ADJUSTMENT,
                             sBuf.makeStringAndClear());
    }

    // relative line width
    SvXMLUnitConverter::convertPercent(sBuf, nLineRelWidth);
    rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_REL_WIDTH,
                         sBuf.makeStringAndClear());

    // color
    rExport.GetMM100UnitConverter().convertColor(sBuf, nLineColor);
    rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_COLOR,
                         sBuf.makeStringAndClear());

    SvXMLElementExport aElem(rExport, XML_NAMESPACE_STYLE,
                             XML_FOOTNOTE_SEP, sal_True, sal_True);
}
<|endoftext|>


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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
 * TODO:
 *
 * handle timeouts
 * notice if the socket was closed on us unexpectedly!
 *
 */

#include "debugkit.h"
#include <QtGui>

#include <assert.h>
#include <fstream>
using namespace std;

// Constructor which creates the main window.

DebugKit::DebugKit() {
	setWindowTitle(tr("openc2e's Debug Kit"));

	tabwidget = new QTabWidget(this);
	setCentralWidget(tabwidget);

	infopage = new QWidget();
	infolayout = new QGridLayout(infopage);
	connectedstatus = new QLabel(infopage);
	connectedstatus->setText(tr("Not connected"));
	infolayout->addWidget(connectedstatus, 0, 0, 1, 3);
	hostname_edit = new QLineEdit(infopage);
	hostname_edit->setText("localhost");
	infolayout->addWidget(hostname_edit, 1, 0);
	port_edit = new QSpinBox(infopage);
	port_edit->setMinimum(1); port_edit->setMaximum(65535);
	port_edit->setValue(20001); // TODO: read from dotfile
	infolayout->addWidget(port_edit, 1, 1);
	connect_button = new QPushButton(tr("Connect"), infopage);
	connect_button->connect(connect_button, SIGNAL(clicked()), this, SLOT(connectButton()));
	infolayout->addWidget(connect_button, 1, 2);
	QLabel *gamedatalabel = new QLabel(tr("Game data directories:"), this);
	infolayout->addWidget(gamedatalabel, 2, 0, 1, 3);
	gamedatadirs = new QListWidget(infopage);
	infolayout->addWidget(gamedatadirs, 3, 0, 1, 3);
	tabwidget->addTab(infopage, tr("Info"));

	injectorpage = new QWidget();
	injectorlayout = new QGridLayout(injectorpage);
	agentlist = new QListWidget(injectorpage);
	agentlist->setSortingEnabled(true);
	agentlist->connect(agentlist, SIGNAL(currentRowChanged(int)), this, SLOT(selectedAgentChanged(int)));
	injectorlayout->addWidget(agentlist, 0, 0);
	inject_button = new QPushButton(tr("Inject"), injectorpage);
	inject_button->setDisabled(true);
	inject_button->connect(inject_button, SIGNAL(clicked()), this, SLOT(injectButton()));
	injectorlayout->addWidget(inject_button, 1, 0);
	tabwidget->addTab(injectorpage, tr("Agent Injector"));

	debugpage = new QWidget();
	tabwidget->addTab(debugpage, tr("Debug"));

	resize(600, 400);

	socket = new QTcpSocket();
	socket->connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError()));

	setConnectedStatus(false);

	tryConnect();
}

DebugKit::~DebugKit() {
	delete socket;
}

void DebugKit::connectButton() {
	if (connect_button->text() == tr("Disconnect")) {
		setConnectedStatus(false);
		connectedstatus->setText(tr("Not connected"));
	} else {
		tryConnect();
	}
}

void DebugKit::setConnectedStatus(bool s) {
	tabwidget->setTabEnabled(1, s);
	tabwidget->setTabEnabled(2, s);
	hostname_edit->setDisabled(s);
	port_edit->setDisabled(s);
	gamedatadirs->setDisabled(!s);
	if (s) {
		connect_button->setText(tr("Disconnect"));
	} else {
		gamedatadirs->clear();
		connect_button->setText(tr("Connect"));
	}
}

void DebugKit::setBusyStatus(bool s) {
	connect_button->setDisabled(s);
	if (agentlist->currentRow() != -1)
		inject_button->setDisabled(s);
}

void DebugKit::tryConnect() {
	assert(socket->state() == QAbstractSocket::UnconnectedState);
	setBusyStatus(true);
	socket->connect(socket, SIGNAL(connected()), this, SLOT(connectAttempt()));
	socket->connectToHost(hostname_edit->text(), port_edit->value());
}

void DebugKit::socketError() {
	socket->disconnect(socket, SIGNAL(connected()), 0, 0);

	//if (socket->error() == QAbstractSocket::RemoteHostClosedError)
	//	return;

	setBusyStatus(false);
	setConnectedStatus(false);

	QString err = tr("Not connected") + " (" + socket->errorString() + ")";
	if (socket->error() == QAbstractSocket::ConnectionRefusedError)
		err = err + " - " + tr("Is openc2e running?");

	connectedstatus->setText(err);
}

void DebugKit::connectAttempt() {
	socket->disconnect(socket, SIGNAL(connected()), this, SLOT(connectAttempt()));
	setBusyStatus(false);

	// obtain the data we need: outs "hi\n", outs gnam, outs "\n", outs oc2e ddir
	socket->write("outs \"hi\\n\"\nouts gnam\nouts \"\\n\"\nouts oc2e ddir\nrscr\n");
	socket->waitForReadyRead(200); // wait for 200ms at most
	QString result = socket->readLine().data();
	if (result == "hi\n") {
		setConnectedStatus(true);
		QString gnam = QString(socket->readLine().data()).trimmed();
		connectedstatus->setText(tr("Connected to game") + " \"" + gnam + "\"");

		QString l = socket->readLine().data();
		while (l.size() > 0) {
			gamedatadirs->addItem(l.trimmed());
			l = socket->readLine().data();
		}

		readAgents();
	} else {
		setConnectedStatus(false);
		connectedstatus->setText(tr("Not connected") + " (" + tr("bad handshake \"") + result + "\"" + tr("; are you sure openc2e is running?") + ")");
	}
	socket->close();
}

void DebugKit::selectedAgentChanged(int i) {
	if (i != -1)
		inject_button->setDisabled(false);
}

#include <iostream>
#include <string>
#include "../../endianlove.h"
#include "../../streamutils.h"

std::string readpascalstring(std::istream &s) {
	uint16 size;
	uint8 a; s.read((char *)&a, 1);
	if (a == 255)
		size = read16(s);
	else
		size = a;

	char x[size];
	s.read((char *)&x, size);
	return std::string(x, size);
}

struct c1cobfile {
	uint16 no_objects;
	uint32 expire_month;
	uint32 expire_day;
	uint32 expire_year;
	std::vector<std::string> scripts;
	std::vector<std::string> imports;
	uint16 no_objects_used;
	std::string name;

	c1cobfile(std::ifstream &s) {
		s >> std::noskipws;

		uint16 version = read16(s);

		// TODO: mph
		if (version != 1) {
			//QMessageBox::warning(this, tr("Failed to open"), tr("Version %1 is not supported").arg((int)version));
			return;
		}

		no_objects = read16(s);
		expire_month = read32(s);
		expire_day = read32(s);
		expire_year = read32(s);
		uint16 noscripts = read16(s);
		uint16 noimports = read16(s);
		no_objects_used = read16(s);
		uint16 reserved_zero = read16(s);
		assert(reserved_zero == 0);

		for (unsigned int i = 0; i < noscripts; i++)
			scripts.push_back(readpascalstring(s));
		for (unsigned int i = 0; i < noimports; i++)
			imports.push_back(readpascalstring(s));

		uint32 imagewidth = read32(s);
		uint32 imageheight = read32(s);
		uint16 secondimagewidth = read16(s);
		assert(imagewidth == secondimagewidth);
		char imagedata[imagewidth * imageheight];
		s.read((char *)&imagedata, imagewidth * imageheight);
		name = readpascalstring(s);
	}
};

void DebugKit::readAgents() {
	inject_button->setDisabled(true);
	agentlist->clear();

	for (unsigned int i = 0; i < gamedatadirs->count(); i++) {
		QString dirname = gamedatadirs->item(i)->text();
		QDir dir(dirname);
		if (!dir.exists()) {
			QMessageBox msgBox(QMessageBox::Warning, tr("Directory missing"), dirname, 0, this);
			continue;
		}

		QStringList filters;
		filters << "*.cob";
		dir.setNameFilters(filters);

		QStringList cobfiles = dir.entryList();
		for (unsigned int j = 0; j < cobfiles.size(); j++) {
			QString file = dirname + '/' + cobfiles[j];
			std::ifstream cobstream(file.toAscii(), std::ios::binary);
			if (!cobstream.fail()) {
				c1cobfile cobfile(cobstream);
				QListWidgetItem *newItem = new QListWidgetItem(cobfile.name.c_str(), agentlist);
				newItem->setToolTip(file);
			}
		}
	}
}

void DebugKit::injectButton() {
	QString filename = agentlist->currentItem()->toolTip();
	std::ifstream cobstream(filename.toAscii(), std::ios::binary);
	if (cobstream.fail()) {
		QMessageBox::warning(this, tr("Failed to open"), filename);
		return;
	}

	c1cobfile cobfile(cobstream);

	std::string idata;
	// this works around a stupid qt issue where it drops the socket if there's no lines returned
	// TODO: surely this is just fuzzie being dumb
	idata += "outs \"\\n\"\n";
	for (unsigned int i = 0; i < cobfile.scripts.size(); i++) {
		idata += cobfile.scripts[i] + "\n";
	}
	for (unsigned int i = 0; i < cobfile.imports.size(); i++) {
		idata += "iscr," + cobfile.imports[i] + "\n";
	}
	idata += "rscr\n";

	injectdata = idata.c_str();

	setBusyStatus(true);
	socket->connect(socket, SIGNAL(connected()), this, SLOT(injectAttempt()));
	socket->connectToHost(hostname_edit->text(), port_edit->value());
}

void DebugKit::injectAttempt() {
	socket->disconnect(socket, SIGNAL(connected()), this, SLOT(injectAttempt()));
	setBusyStatus(false);

	socket->write(injectdata.toAscii());
	socket->waitForReadyRead(200); // wait for 200ms at most
	QString result = QString(socket->readAll().data()).trimmed();
	std::cout << (char *)result.toAscii().data() << std::endl;
	socket->close();

	if (result.size())
		QMessageBox::warning(this, tr("Injection returned data (error?)"), result);
}

<commit_msg>Replace variable-size arrays with boost vectors in debugkit to fix compilation on windows (sigh)<commit_after>/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/*
 * TODO:
 *
 * handle timeouts
 * notice if the socket was closed on us unexpectedly!
 *
 */

#include "debugkit.h"
#include <QtGui>

#include <assert.h>
#include <fstream>
#include <boost/scoped_array.hpp>

using namespace std;

// Constructor which creates the main window.

DebugKit::DebugKit() {
	setWindowTitle(tr("openc2e's Debug Kit"));

	tabwidget = new QTabWidget(this);
	setCentralWidget(tabwidget);

	infopage = new QWidget();
	infolayout = new QGridLayout(infopage);
	connectedstatus = new QLabel(infopage);
	connectedstatus->setText(tr("Not connected"));
	infolayout->addWidget(connectedstatus, 0, 0, 1, 3);
	hostname_edit = new QLineEdit(infopage);
	hostname_edit->setText("localhost");
	infolayout->addWidget(hostname_edit, 1, 0);
	port_edit = new QSpinBox(infopage);
	port_edit->setMinimum(1); port_edit->setMaximum(65535);
	port_edit->setValue(20001); // TODO: read from dotfile
	infolayout->addWidget(port_edit, 1, 1);
	connect_button = new QPushButton(tr("Connect"), infopage);
	connect_button->connect(connect_button, SIGNAL(clicked()), this, SLOT(connectButton()));
	infolayout->addWidget(connect_button, 1, 2);
	QLabel *gamedatalabel = new QLabel(tr("Game data directories:"), this);
	infolayout->addWidget(gamedatalabel, 2, 0, 1, 3);
	gamedatadirs = new QListWidget(infopage);
	infolayout->addWidget(gamedatadirs, 3, 0, 1, 3);
	tabwidget->addTab(infopage, tr("Info"));

	injectorpage = new QWidget();
	injectorlayout = new QGridLayout(injectorpage);
	agentlist = new QListWidget(injectorpage);
	agentlist->setSortingEnabled(true);
	agentlist->connect(agentlist, SIGNAL(currentRowChanged(int)), this, SLOT(selectedAgentChanged(int)));
	injectorlayout->addWidget(agentlist, 0, 0);
	inject_button = new QPushButton(tr("Inject"), injectorpage);
	inject_button->setDisabled(true);
	inject_button->connect(inject_button, SIGNAL(clicked()), this, SLOT(injectButton()));
	injectorlayout->addWidget(inject_button, 1, 0);
	tabwidget->addTab(injectorpage, tr("Agent Injector"));

	debugpage = new QWidget();
	tabwidget->addTab(debugpage, tr("Debug"));

	resize(600, 400);

	socket = new QTcpSocket();
	socket->connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError()));

	setConnectedStatus(false);

	tryConnect();
}

DebugKit::~DebugKit() {
	delete socket;
}

void DebugKit::connectButton() {
	if (connect_button->text() == tr("Disconnect")) {
		setConnectedStatus(false);
		connectedstatus->setText(tr("Not connected"));
	} else {
		tryConnect();
	}
}

void DebugKit::setConnectedStatus(bool s) {
	tabwidget->setTabEnabled(1, s);
	tabwidget->setTabEnabled(2, s);
	hostname_edit->setDisabled(s);
	port_edit->setDisabled(s);
	gamedatadirs->setDisabled(!s);
	if (s) {
		connect_button->setText(tr("Disconnect"));
	} else {
		gamedatadirs->clear();
		connect_button->setText(tr("Connect"));
	}
}

void DebugKit::setBusyStatus(bool s) {
	connect_button->setDisabled(s);
	if (agentlist->currentRow() != -1)
		inject_button->setDisabled(s);
}

void DebugKit::tryConnect() {
	assert(socket->state() == QAbstractSocket::UnconnectedState);
	setBusyStatus(true);
	socket->connect(socket, SIGNAL(connected()), this, SLOT(connectAttempt()));
	socket->connectToHost(hostname_edit->text(), port_edit->value());
}

void DebugKit::socketError() {
	socket->disconnect(socket, SIGNAL(connected()), 0, 0);

	//if (socket->error() == QAbstractSocket::RemoteHostClosedError)
	//	return;

	setBusyStatus(false);
	setConnectedStatus(false);

	QString err = tr("Not connected") + " (" + socket->errorString() + ")";
	if (socket->error() == QAbstractSocket::ConnectionRefusedError)
		err = err + " - " + tr("Is openc2e running?");

	connectedstatus->setText(err);
}

void DebugKit::connectAttempt() {
	socket->disconnect(socket, SIGNAL(connected()), this, SLOT(connectAttempt()));
	setBusyStatus(false);

	// obtain the data we need: outs "hi\n", outs gnam, outs "\n", outs oc2e ddir
	socket->write("outs \"hi\\n\"\nouts gnam\nouts \"\\n\"\nouts oc2e ddir\nrscr\n");
	socket->waitForReadyRead(200); // wait for 200ms at most
	QString result = socket->readLine().data();
	if (result == "hi\n") {
		setConnectedStatus(true);
		QString gnam = QString(socket->readLine().data()).trimmed();
		connectedstatus->setText(tr("Connected to game") + " \"" + gnam + "\"");

		QString l = socket->readLine().data();
		while (l.size() > 0) {
			gamedatadirs->addItem(l.trimmed());
			l = socket->readLine().data();
		}

		readAgents();
	} else {
		setConnectedStatus(false);
		connectedstatus->setText(tr("Not connected") + " (" + tr("bad handshake \"") + result + "\"" + tr("; are you sure openc2e is running?") + ")");
	}
	socket->close();
}

void DebugKit::selectedAgentChanged(int i) {
	if (i != -1)
		inject_button->setDisabled(false);
}

#include <iostream>
#include <string>
#include "../../endianlove.h"
#include "../../streamutils.h"

std::string readpascalstring(std::istream &s) {
	uint16 size;
	uint8 a; s.read((char *)&a, 1);
	if (a == 255)
		size = read16(s);
	else
		size = a;

	boost::scoped_array<char> x(new char[size]);
	//char x[size];
	s.read(x.get(), size);
	return std::string(x.get(), size);
}

struct c1cobfile {
	uint16 no_objects;
	uint32 expire_month;
	uint32 expire_day;
	uint32 expire_year;
	std::vector<std::string> scripts;
	std::vector<std::string> imports;
	uint16 no_objects_used;
	std::string name;

	c1cobfile(std::ifstream &s) {
		s >> std::noskipws;

		uint16 version = read16(s);

		// TODO: mph
		if (version != 1) {
			//QMessageBox::warning(this, tr("Failed to open"), tr("Version %1 is not supported").arg((int)version));
			return;
		}

		no_objects = read16(s);
		expire_month = read32(s);
		expire_day = read32(s);
		expire_year = read32(s);
		uint16 noscripts = read16(s);
		uint16 noimports = read16(s);
		no_objects_used = read16(s);
		uint16 reserved_zero = read16(s);
		assert(reserved_zero == 0);

		for (unsigned int i = 0; i < noscripts; i++)
			scripts.push_back(readpascalstring(s));
		for (unsigned int i = 0; i < noimports; i++)
			imports.push_back(readpascalstring(s));

		uint32 imagewidth = read32(s);
		uint32 imageheight = read32(s);
		uint16 secondimagewidth = read16(s);
		assert(imagewidth == secondimagewidth);
		boost::scoped_array<char> imagedata(new char[imagewidth * imageheight]);
		s.read(imagedata.get(), imagewidth * imageheight);
		name = readpascalstring(s);
	}
};

void DebugKit::readAgents() {
	inject_button->setDisabled(true);
	agentlist->clear();

	for (unsigned int i = 0; i < gamedatadirs->count(); i++) {
		QString dirname = gamedatadirs->item(i)->text();
		QDir dir(dirname);
		if (!dir.exists()) {
			QMessageBox msgBox(QMessageBox::Warning, tr("Directory missing"), dirname, 0, this);
			continue;
		}

		QStringList filters;
		filters << "*.cob";
		dir.setNameFilters(filters);

		QStringList cobfiles = dir.entryList();
		for (unsigned int j = 0; j < cobfiles.size(); j++) {
			QString file = dirname + '/' + cobfiles[j];
			std::ifstream cobstream(file.toAscii(), std::ios::binary);
			if (!cobstream.fail()) {
				c1cobfile cobfile(cobstream);
				QListWidgetItem *newItem = new QListWidgetItem(cobfile.name.c_str(), agentlist);
				newItem->setToolTip(file);
			}
		}
	}
}

void DebugKit::injectButton() {
	QString filename = agentlist->currentItem()->toolTip();
	std::ifstream cobstream(filename.toAscii(), std::ios::binary);
	if (cobstream.fail()) {
		QMessageBox::warning(this, tr("Failed to open"), filename);
		return;
	}

	c1cobfile cobfile(cobstream);

	std::string idata;
	// this works around a stupid qt issue where it drops the socket if there's no lines returned
	// TODO: surely this is just fuzzie being dumb
	idata += "outs \"\\n\"\n";
	for (unsigned int i = 0; i < cobfile.scripts.size(); i++) {
		idata += cobfile.scripts[i] + "\n";
	}
	for (unsigned int i = 0; i < cobfile.imports.size(); i++) {
		idata += "iscr," + cobfile.imports[i] + "\n";
	}
	idata += "rscr\n";

	injectdata = idata.c_str();

	setBusyStatus(true);
	socket->connect(socket, SIGNAL(connected()), this, SLOT(injectAttempt()));
	socket->connectToHost(hostname_edit->text(), port_edit->value());
}

void DebugKit::injectAttempt() {
	socket->disconnect(socket, SIGNAL(connected()), this, SLOT(injectAttempt()));
	setBusyStatus(false);

	socket->write(injectdata.toAscii());
	socket->waitForReadyRead(200); // wait for 200ms at most
	QString result = QString(socket->readAll().data()).trimmed();
	std::cout << (char *)result.toAscii().data() << std::endl;
	socket->close();

	if (result.size())
		QMessageBox::warning(this, tr("Injection returned data (error?)"), result);
}

<|endoftext|>


<commit_before>#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "runner.hh"
#include <iostream>

using namespace v8;
using namespace std;

SpawnRunner::SpawnRunner(JsString& file, JsArray& args, JsObject& options)
        : file_(file),
          args_(args),
          options_(options),

          timeout_(0),
          status_(0),
          child_pid_(-1),
          has_timedout_(false) {
    JsValue timeout_opt = options->Get(Symbol("timeout"));
    if(timeout_opt->IsNumber()) {
        timeout_ = static_cast<int64_t>(timeout_opt->IntegerValue());
    }
}

JsObject SpawnRunner::Run() {
    pid_t pid = fork();
    if(pid == 0) {
        RunChild();
        _exit(127);
    } else {
        int stat = RunParent(pid);
        return BuildResultObject(stat);
    }
    return BuildResultObject(0);
}

int SpawnRunner::RunChild() {
    if(PipeStdio()) { return 1; }
    if(SetEnvironment()) { return 1; }
    if(ChangeDirectory()) { return 1; }
    String::Utf8Value file(file_);
    char** args = BuildArgs();
    execvp(*file, args);
    fprintf(stderr, "errno: %d\n", errno);
    perror(*file);
    return 1;
}

int SpawnRunner::RunParent(pid_t pid) {
    child_pid_ = pid;
    int stat;
    if(0 < timeout_) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        suseconds_t timeout = timeout_ * 1000;
        suseconds_t start = tv.tv_usec;

        while(waitpid(pid, &stat, WNOHANG) == 0) {
            usleep(TIMEOUT_INTERVAL);
            gettimeofday(&tv, NULL);
            if(timeout < tv.tv_usec - start) {
                kill(pid, SIGTERM);
                has_timedout_ = true;
            }
        }
    } else {
        waitpid(pid, &stat, 0);
    }
    return stat;
}

JsObject SpawnRunner::BuildResultObject(int stat) {
    Local<Object> result = Object::New();

    if(WIFEXITED(stat)) {
        status_ = WEXITSTATUS(stat);
        result->Set(Symbol("signal"), Null());
    } else if(WIFSIGNALED(stat)) {
        int sig = WTERMSIG(stat);
        JsString signame = String::New(node::signo_string(sig));
        result->Set(Symbol("signal"), signame);
        status_ = 128 + sig;
    }

    result->Set(Symbol("status"), Number::New(status_));
    result->Set(Symbol("pid"), Number::New(child_pid_));
    result->Set(Symbol("file"), file_);
    result->Set(Symbol("args"), args_);
    if(has_timedout_) {
        result->Set(Symbol("_hasTimedOut"), Boolean::New(has_timedout_));
    }
    return result;
}

char** SpawnRunner::BuildArgs() {
    int len = args_->Length();
    char** args = new char*[len + 1];

    for(int i = 0; i < len; i++) {
        String::Utf8Value value(args_->Get(i));
        char* str = new char[value.length() + 1];
        strcpy(str, *value);
        args[i] = str;
    }

    // add sentinel
    args[len] = NULL;
    return args;
}

int SpawnRunner::PipeStdio() {
    JsArray stdio = options_->Get(Symbol("stdio")).As<Array>();

    const char* files[3] = {"/dev/stdin", "/dev/stdout", "/dev/stderr"};
    const char* names[3] = {"stdin pipe", "stdout pipe", "stderr pipe"};
    int modes[3] = {O_RDONLY, O_WRONLY, O_WRONLY};

    for(int i = 0; i < 3; i++) {
        JsValue pipe = stdio->Get(Number::New(i));
        int fd;

        if(pipe->IsNumber()) {
            fd = pipe->IntegerValue();
        } else {
            fd = open(files[i], modes[i]);
            if(fd == -1) {
                fprintf(stderr, "errno: %d\n", errno);
                perror(files[i]);
                return 1;
            }
       }
        if(dup2(fd, i) == -1) {
            fprintf(stderr, "errno: %d\n", errno);
            perror(names[i]);
            return 1;
        }
    }
    return 0;
}

int SpawnRunner::SetEnvironment() {
    JsArray envPairs = options_->Get(Symbol("envPairs")).As<Array>();
    int len = envPairs->Length();
    for(int i = 0; i < len; i++) {
        String::Utf8Value value(envPairs->Get(i));
        putenv(*value);
    }

    return 0;
}

int SpawnRunner::ChangeDirectory() {
    JsValue cwd = options_->Get(Symbol("cwd"));
    if(cwd->IsString()) {
        String::Utf8Value cwd_value(cwd);
        int err = chdir(*cwd_value);
        if(err) {
            fprintf(stderr, "errno: %d\n", errno);
            perror(*cwd_value);
            return err;
        }
    }
    return 0;
}
<commit_msg>Fix spawn timeout<commit_after>#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "runner.hh"
#include <iostream>

using namespace v8;
using namespace std;

const double usec = 1.0 / 1000 / 1000;

double tv_to_seconds(struct timeval* tv) {
    return tv->tv_sec + tv->tv_usec * usec;
}

SpawnRunner::SpawnRunner(JsString& file, JsArray& args, JsObject& options)
        : file_(file),
          args_(args),
          options_(options),

          timeout_(0),
          status_(0),
          child_pid_(-1),
          has_timedout_(false) {
    JsValue timeout_opt = options->Get(Symbol("timeout"));
    if(timeout_opt->IsNumber()) {
        timeout_ = static_cast<int64_t>(timeout_opt->IntegerValue());
    }
}

JsObject SpawnRunner::Run() {
    pid_t pid = fork();
    if(pid == 0) {
        RunChild();
        _exit(127);
    } else {
        int stat = RunParent(pid);
        return BuildResultObject(stat);
    }
    return BuildResultObject(0);
}

int SpawnRunner::RunChild() {
    if(PipeStdio()) { return 1; }
    if(SetEnvironment()) { return 1; }
    if(ChangeDirectory()) { return 1; }
    String::Utf8Value file(file_);
    char** args = BuildArgs();
    execvp(*file, args);
    fprintf(stderr, "errno: %d\n", errno);
    perror(*file);
    return 1;
}

int SpawnRunner::RunParent(pid_t pid) {
    child_pid_ = pid;
    int stat;
    if(0 < timeout_) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        double timeout = timeout_ / 1000.0;
        double start = tv_to_seconds(&tv);

        while(waitpid(pid, &stat, WNOHANG) == 0) {
            usleep(TIMEOUT_INTERVAL);
            gettimeofday(&tv, NULL);
            if(timeout < tv_to_seconds(&tv) - start) {
                kill(pid, SIGTERM);
                has_timedout_ = true;
            }
        }
    } else {
        waitpid(pid, &stat, 0);
    }
    return stat;
}

JsObject SpawnRunner::BuildResultObject(int stat) {
    Local<Object> result = Object::New();

    if(WIFEXITED(stat)) {
        status_ = WEXITSTATUS(stat);
        result->Set(Symbol("signal"), Null());
    } else if(WIFSIGNALED(stat)) {
        int sig = WTERMSIG(stat);
        JsString signame = String::New(node::signo_string(sig));
        result->Set(Symbol("signal"), signame);
        status_ = 128 + sig;
    }

    result->Set(Symbol("status"), Number::New(status_));
    result->Set(Symbol("pid"), Number::New(child_pid_));
    result->Set(Symbol("file"), file_);
    result->Set(Symbol("args"), args_);
    if(has_timedout_) {
        result->Set(Symbol("_hasTimedOut"), Boolean::New(has_timedout_));
    }
    return result;
}

char** SpawnRunner::BuildArgs() {
    int len = args_->Length();
    char** args = new char*[len + 1];

    for(int i = 0; i < len; i++) {
        String::Utf8Value value(args_->Get(i));
        char* str = new char[value.length() + 1];
        strcpy(str, *value);
        args[i] = str;
    }

    // add sentinel
    args[len] = NULL;
    return args;
}

int SpawnRunner::PipeStdio() {
    JsArray stdio = options_->Get(Symbol("stdio")).As<Array>();

    const char* files[3] = {"/dev/stdin", "/dev/stdout", "/dev/stderr"};
    const char* names[3] = {"stdin pipe", "stdout pipe", "stderr pipe"};
    int modes[3] = {O_RDONLY, O_WRONLY, O_WRONLY};

    for(int i = 0; i < 3; i++) {
        JsValue pipe = stdio->Get(Number::New(i));
        int fd;

        if(pipe->IsNumber()) {
            fd = pipe->IntegerValue();
        } else {
            fd = open(files[i], modes[i]);
            if(fd == -1) {
                fprintf(stderr, "errno: %d\n", errno);
                perror(files[i]);
                return 1;
            }
       }
        if(dup2(fd, i) == -1) {
            fprintf(stderr, "errno: %d\n", errno);
            perror(names[i]);
            return 1;
        }
    }
    return 0;
}

int SpawnRunner::SetEnvironment() {
    JsArray envPairs = options_->Get(Symbol("envPairs")).As<Array>();
    int len = envPairs->Length();
    for(int i = 0; i < len; i++) {
        String::Utf8Value value(envPairs->Get(i));
        putenv(*value);
    }

    return 0;
}

int SpawnRunner::ChangeDirectory() {
    JsValue cwd = options_->Get(Symbol("cwd"));
    if(cwd->IsString()) {
        String::Utf8Value cwd_value(cwd);
        int err = chdir(*cwd_value);
        if(err) {
            fprintf(stderr, "errno: %d\n", errno);
            perror(*cwd_value);
            return err;
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 4 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 4 or less.");
		return 0;
	} else if ( nrrd->spaceDim > 3 ){
		theMsg->printf("ERROR: for now, nrrd input can only handle data with space dimension 3 or less.");
		return 0;
	}

    const int dims[4] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1,
		(nrrd->dim > 3) ? nrrd->axis[3].size : 1
	};

	McPrimType pType = NULL;
	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  pType = MC_UINT8; break;
		case nrrdTypeChar:   pType = MC_INT8;  break;
		case nrrdTypeUShort: pType = MC_UINT16;break;
		case nrrdTypeShort:  pType = MC_INT16; break;
		case nrrdTypeInt:    pType = MC_INT32; break;
		case nrrdTypeFloat:  pType = MC_FLOAT; break;
		case nrrdTypeDouble: pType = MC_DOUBLE;break;
		default: break;
	}

	if(pType == NULL)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	HxUniformScalarField3* field = new HxUniformScalarField3(dims,pType,nrrd->data);

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	int firstSpaceAxis = -1;
	int numSpaceAxesSoFar = 0;
	int nonSpatialDimension = -1;
	for ( size_t ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrd->axis[ax].kind )
		{
			case nrrdKindUnknown:
			case nrrdKindDomain:
			case nrrdKindSpace:
			case nrrdKindTime: firstSpaceAxis=firstSpaceAxis<0?ax:firstSpaceAxis;
							   numSpaceAxesSoFar++; break;
			default: nonSpatialDimension = ax; continue;
		}

		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+ax, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[ax] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[ax] = 1.0;
				break;
		}
	}
	if ( firstSpaceAxis < 0 || firstSpaceAxis >1 )
	{
		theMsg->printf("ERROR: Unable to identify first spatial axis in nrrd. Got %d\n", firstSpaceAxis);
		return 0;
	}

	// Figure out size of non-spatial dimension (ie vector, colour etc)
	int nDataVar = 1;
	if ( nonSpatialDimension == 0) nDataVar = dims[nonSpatialDimension];
	else if ( nonSpatialDimension > 0) {
		// At the moment we can't handle having the vector dimension come later because
		// that would require shuffling the nrrd data block to prepare it for Amira
		theMsg->printf("ERROR: Only nrrds with vector values in the 0th dimension (not %d) are currently supported\n", nonSpatialDimension);
		return 0;
	}

	// Now initialise lattice
	// HxLattice3* lattice = new HxLattice3(&dims[firstSpaceAxis], nDataVar, primType, otherLattice->coords()->duplicate());

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = field->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0+firstSpaceAxis] == 1 ? 1 : (dims[0+firstSpaceAxis] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1+firstSpaceAxis] == 1 ? 1 : (dims[1+firstSpaceAxis] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2+firstSpaceAxis] == 1 ? 1 : (dims[2+firstSpaceAxis] - 1) );

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<commit_msg>Correctly read in 4D data<commit_after>/////////////////////////////////////////////////////////////////
/*
 *  Amira Reader for the nrrd (Nearly Raw Raster Data) format:
 *  http://teem.sourceforge.net/nrrd/format.html
 *  Currently only supports 3d single channel data
 *  Copyright 2009 Gregory Jefferis. All rights reserved.
 *  License GPL >=3
 *  Certain portions of this code were copied/amended from the CMTK
 *  library: http://www.nitrc.org/projects/cmtk/
 */
/////////////////////////////////////////////////////////////////
#include <NrrdIO/NrrdIOAPI.h>

#include <hxfield/HxUniformScalarField3.h>
#include <Amira/HxMessage.h>
#include <teem/nrrd.h>

NRRDIO_API
int NrrdReader(const char* filename)
{

	Nrrd *nrrd = nrrdNew();
	if ( nrrdLoad( nrrd, filename, NULL ) )
		throw biffGetDone(NRRD);

    if ( nrrd->dim > 4 )
	{
		theMsg->printf("ERROR: for now, nrrd input can only handle data with dimension 4 or less.");
		return 0;
	} else if ( nrrd->spaceDim > 3 ){
		theMsg->printf("ERROR: for now, nrrd input can only handle data with space dimension 3 or less.");
		return 0;
	}

    const int dims[4] =
	{
		(nrrd->dim > 0) ? nrrd->axis[0].size : 1,
		(nrrd->dim > 1) ? nrrd->axis[1].size : 1,
		(nrrd->dim > 2) ? nrrd->axis[2].size : 1,
		(nrrd->dim > 3) ? nrrd->axis[3].size : 1
	};

	McPrimType pType = NULL;
	switch ( nrrd->type )
	{
		case nrrdTypeUChar:  pType = MC_UINT8; break;
		case nrrdTypeChar:   pType = MC_INT8;  break;
		case nrrdTypeUShort: pType = MC_UINT16;break;
		case nrrdTypeShort:  pType = MC_INT16; break;
		case nrrdTypeInt:    pType = MC_INT32; break;
		case nrrdTypeFloat:  pType = MC_FLOAT; break;
		case nrrdTypeDouble: pType = MC_DOUBLE;break;
		default: break;
	}

	if(pType == NULL)
	{
		theMsg->printf("ERROR: unknown nrrd input type.");
		return 0;
	}

	// First fetch axis spacing
	double spacing[3] = { 1.0, 1.0, 1.0 };
	int firstSpaceAxis = -1;
	int numSpaceAxesSoFar = 0;
	int nonSpatialDimension = -1;
	for ( unsigned int ax = 0; ax < nrrd->dim; ++ax )
	{
		switch ( nrrd->axis[ax].kind )
		{
			case nrrdKindUnknown:
			case nrrdKindDomain:
			case nrrdKindSpace:
			case nrrdKindTime: firstSpaceAxis=firstSpaceAxis<0?ax:firstSpaceAxis; break;
			default: nonSpatialDimension = ax; continue;
		}
		switch ( nrrdSpacingCalculate( nrrd, ax, spacing+numSpaceAxesSoFar, nrrd->axis[ax].spaceDirection ) )
		{
			case nrrdSpacingStatusScalarNoSpace:
				break;
			case nrrdSpacingStatusDirection:
				break;
			case nrrdSpacingStatusScalarWithSpace:
				theMsg->printf("WARNING: nrrdSpacingCalculate returned nrrdSpacingStatusScalarWithSpace\n");
				spacing[numSpaceAxesSoFar] = nrrd->axis[ax].spacing;
				break;
			case nrrdSpacingStatusNone:
			default:
				theMsg->printf("WARNING: no pixel spacings in Nrrd for axis %d ; setting to 1.0\n",ax);
				spacing[numSpaceAxesSoFar] = 1.0;
				break;
		}
		numSpaceAxesSoFar++;
	}
	if ( firstSpaceAxis < 0 || firstSpaceAxis >1 )
	{
		theMsg->printf("ERROR: Unable to identify first spatial axis in nrrd. Got %d\n", firstSpaceAxis);
		return 0;
	}

	// Figure out size of non-spatial dimension (ie vector, colour etc)
	int nDataVar = 1;
	if ( nonSpatialDimension == 0) nDataVar = dims[nonSpatialDimension];
	else if ( nonSpatialDimension > 0) {
		// At the moment we can't handle having the vector dimension come later because
		// that would require shuffling the nrrd data block to prepare it for Amira
		theMsg->printf("ERROR: Only nrrds with vector values in the 0th dimension (not %d) are currently supported\n", nonSpatialDimension);
		return 0;
	}

	// Initialise coordinates (these will be uniform) starting at first space axis
	HxUniformCoord3* coord = new HxUniformCoord3(&dims[firstSpaceAxis]);

	// Now let's set the physical dimensions
	// This is done by defining the bounding box, the range of the voxel centres
	// given in the order: xmin,xmax,ymin ...
	float *bbox = coord->bbox();
	bbox[0] = isnan(nrrd->spaceOrigin[0])?0.0f:(float) nrrd->spaceOrigin[0];
	bbox[2] = isnan(nrrd->spaceOrigin[1])?0.0f:(float) nrrd->spaceOrigin[1];
	bbox[4] = isnan(nrrd->spaceOrigin[2])?0.0f:(float) nrrd->spaceOrigin[2];

	// When a dimension is 1, Amira still seems to have a defined spacing
	bbox[1] = bbox[0] + (float) spacing[0] * ( dims[0+firstSpaceAxis] == 1 ? 1 : (dims[0+firstSpaceAxis] - 1) );
	bbox[3] = bbox[2] + (float) spacing[1] * ( dims[1+firstSpaceAxis] == 1 ? 1 : (dims[1+firstSpaceAxis] - 1) );
	bbox[5] = bbox[4] + (float) spacing[2] * ( dims[2+firstSpaceAxis] == 1 ? 1 : (dims[2+firstSpaceAxis] - 1) );

	// Finally initialise lattice
	HxLattice3* lattice = new HxLattice3(nDataVar, pType, coord, nrrd->data);
	HxField3* field = HxLattice3::create(lattice);

	// Shouldn't need to check for data loading
	HxData::registerData(field, filename);

    return 1;
}

<|endoftext|>