<commit_before>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_resize_method_impl
{
    constexpr static std::size_t dummy=0;
    template<typename T> static std::true_type  check(decltype(std::declval<T>().resize(dummy))*);
    template<typename T> static std::false_type check(...);
};

struct is_comparable_impl
{
    template<typename T> static std::true_type  check(decltype(std::declval<T>() < std::declval<T>())*);
    template<typename T> static std::false_type check(...);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype(...)
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

// ---------------------------------------------------------------------------
// C++14 enable_if_t
template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

}// detail
}//toml
#endif // TOML_TRAITS
<commit_msg>refactor: add utility meta-func for internal use<commit_after>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include <type_traits>
#include <utility>
#include <chrono>
#include <tuple>
#include <string>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_resize_method_impl
{
    constexpr static std::size_t dummy=0;
    template<typename T> static std::true_type  check(decltype(std::declval<T>().resize(dummy))*);
    template<typename T> static std::false_type check(...);
};

struct is_comparable_impl
{
    template<typename T> static std::true_type  check(decltype(std::declval<T>() < std::declval<T>())*);
    template<typename T> static std::false_type check(...);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype(...)
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

// ---------------------------------------------------------------------------
// C++14 enable_if_t
template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

// ---------------------------------------------------------------------------
// C++20 remove_cvref_t

template<typename T>
struct remove_cvref
{
    using type = typename std::remove_cv<
        typename std::remove_reference<T>::type>::type;
};

template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

}// detail
}//toml
#endif // TOML_TRAITS
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;
using namespace std;

struct Params
{
    Params();
    static Params read(int argc, char** argv);

    string left;
    string right;

    string method_str() const
    {
        switch (method)
        {
        case BM: return "BM";
        case BP: return "BP";
        case CSBP: return "CSBP";
        }
        return "";
    }
    enum {BM, BP, CSBP} method;
    int ndisp; // Max disparity + 1
};

struct App
{
    App(const Params& p);
    void run();
    void handleKey(char key);
    void printParams() const;

    void workBegin() { work_begin = getTickCount(); }
    void workEnd()
    {
        int64 d = getTickCount() - work_begin;
        double f = getTickFrequency();
        work_fps = f / d;
    }

    string text() const
    {
        stringstream ss;
        ss << "(" << p.method_str() << ") FPS: " << setiosflags(ios::left) << setprecision(4) << work_fps;
        return ss.str();
    }
private:
    Params p;
    bool running;

    Mat left_src, right_src;
    Mat left, right;
    gpu::GpuMat d_left, d_right;

    gpu::StereoBM_GPU bm;
    gpu::StereoBeliefPropagation bp;
    gpu::StereoConstantSpaceBP csbp;

    int64 work_begin;
    double work_fps;
};

int main(int argc, char** argv)
{
    try
    {
        if (argc < 2)
        {
            cout << "Usage: stereo_match_gpu\n"
                << "\t-l <left_view> -r <right_view> # must be rectified\n"
                << "\t-m <stereo_match_method> # bm | bp | csbp\n";
            return 1;
        }
        App app(Params::read(argc, argv));
        app.run();
    }
    catch (const exception& e)
    {
        cout << "error: " << e.what() << endl;
    }
    return 0;
}

Params::Params()
{
    method = BM;
    ndisp = 64;
}

Params Params::read(int argc, char** argv)
{
    Params p;

    for (int i = 1; i < argc - 1; i += 2)
    {
        string key = argv[i];
        string val = argv[i + 1];
        if (key == "-l") p.left = val;
        else if (key == "-r") p.right = val;
        else if (key == "-m")
        {
            if (val == "BM") p.method = BM;
            else if (val == "BP") p.method = BP;
            else if (val == "CSBP") p.method = CSBP;
            else throw runtime_error("unknown stereo match method: " + val);
        }
        else if (key == "-ndisp") p.ndisp = atoi(val.c_str());
        else throw runtime_error("unknown key: " + key);
    }

    return p;
}

App::App(const Params& p)
    : p(p), running(false)
{
    cout << "stereo_match_gpu sample\n";
    cout << "\nControls:\n"
        << "\tesc - exit\n"
        << "\tp - print current parameters\n"
        << "\tg - convert source images into gray\n"
        << "\tm - change stereo match method\n"
        << "\ts - change Sobel prefiltering flag (for BM only)\n"
        << "\t1/q - increase/decrease maximum disparity\n"
        << "\t2/w - increase/decrease window size (for BM only)\n"
        << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n"
        << "\t4/r - increase/decrease level count (for BP and CSBP only)\n";
}

void App::run()
{
    // Load images
    left_src = imread(p.left);
    right_src = imread(p.right);
    if (left_src.empty()) throw runtime_error("can't open file \"" + p.left + "\"");
    if (right_src.empty()) throw runtime_error("can't open file \"" + p.right + "\"");
    cvtColor(left_src, left, CV_BGR2GRAY);
    cvtColor(right_src, right, CV_BGR2GRAY);
    d_left = left;
    d_right = right;

    imshow("left", left);
    imshow("right", right);

	// Set common parameters
    bm.ndisp = p.ndisp;
    bp.ndisp = p.ndisp;
    csbp.ndisp = p.ndisp;

    // Prepare disparity map of specified type
    Mat disp(left.size(), CV_8U);
    gpu::GpuMat d_disp(left.size(), CV_8U);

    cout << endl;
    printParams();

    running = true;
    while (running)
    {
        workBegin();
        switch (p.method)
        {
        case Params::BM:
            if (d_left.channels() > 1 || d_right.channels() > 1)
            {
                cout << "BM doesn't support color images\n";
                cvtColor(left_src, left, CV_BGR2GRAY);
                cvtColor(right_src, right, CV_BGR2GRAY);
                cout << "image_channels: " << left.channels() << endl;
                d_left = left;
                d_right = right;
                imshow("left", left);
                imshow("right", right);
            }
            bm(d_left, d_right, d_disp);
            break;
        case Params::BP: bp(d_left, d_right, d_disp); break;
        case Params::CSBP: csbp(d_left, d_right, d_disp); break;
        }
        workEnd();

        // Show results
        disp = d_disp;
        putText(disp, text(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255));
        imshow("disparity", disp);

        handleKey((char)waitKey(3));
    }
}

void App::printParams() const
{
    cout << "--- Parameters ---\n";
    cout << "image_size: (" << left.cols << ", " << left.rows << ")\n";
    cout << "image_channels: " << left.channels() << endl;
    cout << "method: " << p.method_str() << endl
        << "ndisp: " << p.ndisp << endl;
    switch (p.method)
    {
    case Params::BM:
        cout << "win_size: " << bm.winSize << endl;
        cout << "prefilter_sobel: " << bm.preset << endl;
        break;
    case Params::BP:
        cout << "iter_count: " << bp.iters << endl;
        cout << "level_count: " << bp.levels << endl;
        break;
    case Params::CSBP:
        cout << "iter_count: " << csbp.iters << endl;
        cout << "level_count: " << csbp.levels << endl;
        break;
    }
    cout << endl;
}

void App::handleKey(char key)
{
    switch (key)
    {
    case 27:
        running = false;
        break;
    case 'p': case 'P':
        printParams();
        break;
    case 'g': case 'G':
        if (left.channels() == 1 && p.method != Params::BM)
        {
            left = left_src;
            right = right_src;
        }
        else
        {
            cvtColor(left_src, left, CV_BGR2GRAY);
            cvtColor(right_src, right, CV_BGR2GRAY);
        }
        d_left = left;
        d_right = right;
        cout << "image_channels: " << left.channels() << endl;
        imshow("left", left);
        imshow("right", right);
        break;
    case 'm': case 'M':
        switch (p.method)
        {
        case Params::BM:
            p.method = Params::BP;
            break;
        case Params::BP:
            p.method = Params::CSBP;
            break;
        case Params::CSBP:
            p.method = Params::BM;
            break;
        }
        cout << "method: " << p.method_str() << endl;
        break;
    case 's': case 'S':
        if (p.method == Params::BM)
        {
            switch (bm.preset)
            {
            case gpu::StereoBM_GPU::BASIC_PRESET:
                bm.preset = gpu::StereoBM_GPU::PREFILTER_XSOBEL;
                break;
            case gpu::StereoBM_GPU::PREFILTER_XSOBEL:
                bm.preset = gpu::StereoBM_GPU::BASIC_PRESET;
                break;
            }
            cout << "prefilter_sobel: " << bm.preset << endl;
        }
        break;
    case '1':
        p.ndisp = p.ndisp == 1 ? 8 : p.ndisp + 8;
        cout << "ndisp: " << p.ndisp << endl;
        bm.ndisp = p.ndisp;
        bp.ndisp = p.ndisp;
        csbp.ndisp = p.ndisp;
        break;
    case 'q': case 'Q':
        p.ndisp = max(p.ndisp - 8, 1);
        cout << "ndisp: " << p.ndisp << endl;
        bm.ndisp = p.ndisp;
        bp.ndisp = p.ndisp;
        csbp.ndisp = p.ndisp;
        break;
    case '2':
        if (p.method == Params::BM)
        {
            bm.winSize = min(bm.winSize + 1, 51);
            cout << "win_size: " << bm.winSize << endl;
        }
        break;
    case 'w': case 'W':
        if (p.method == Params::BM)
        {
            bm.winSize = max(bm.winSize - 1, 2);
            cout << "win_size: " << bm.winSize << endl;
        }
        break;
    case '3':
        if (p.method == Params::BP)
        {
            bp.iters += 1;
            cout << "iter_count: " << bp.iters << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.iters += 1;
            cout << "iter_count: " << csbp.iters << endl;
        }
        break;
    case 'e': case 'E':
        if (p.method == Params::BP)
        {
            bp.iters = max(bp.iters - 1, 1);
            cout << "iter_count: " << bp.iters << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.iters = max(csbp.iters - 1, 1);
            cout << "iter_count: " << csbp.iters << endl;
        }
        break;
    case '4':
        if (p.method == Params::BP)
        {
            bp.levels += 1;
            cout << "level_count: " << bp.levels << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.levels += 1;
            cout << "level_count: " << csbp.levels << endl;
        }
        break;
    case 'r': case 'R':
        if (p.method == Params::BP)
        {
            bp.levels = max(bp.levels - 1, 1);
            cout << "level_count: " << bp.levels << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.levels = max(csbp.levels - 1, 1);
            cout << "level_count: " << csbp.levels << endl;
        }
        break;
    }
}

<commit_msg>minor changes in the gpu stereo sample<commit_after>#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace cv;
using namespace std;

struct Params
{
    Params();
    static Params read(int argc, char** argv);

    string left;
    string right;

    string method_str() const
    {
        switch (method)
        {
        case BM: return "BM";
        case BP: return "BP";
        case CSBP: return "CSBP";
        }
        return "";
    }
    enum {BM, BP, CSBP} method;
    int ndisp; // Max disparity + 1
};

struct App
{
    App(const Params& p);
    void run();
    void handleKey(char key);
    void printParams() const;

    void workBegin() { work_begin = getTickCount(); }
    void workEnd()
    {
        int64 d = getTickCount() - work_begin;
        double f = getTickFrequency();
        work_fps = f / d;
    }

    string text() const
    {
        stringstream ss;
        ss << "(" << p.method_str() << ") FPS: " << setiosflags(ios::left)
            << setprecision(4) << work_fps;
        return ss.str();
    }
private:
    Params p;
    bool running;

    Mat left_src, right_src;
    Mat left, right;
    gpu::GpuMat d_left, d_right;

    gpu::StereoBM_GPU bm;
    gpu::StereoBeliefPropagation bp;
    gpu::StereoConstantSpaceBP csbp;

    int64 work_begin;
    double work_fps;
};

int main(int argc, char** argv)
{
    try
    {
        if (argc < 2)
        {
            cout << "Usage: stereo_match_gpu\n"
                << "\t-l <left_view> -r <right_view> # must be rectified\n"
                << "\t-m <stereo_match_method> # BM | BP | CSBP\n";
            return 1;
        }
        App app(Params::read(argc, argv));
        app.run();
    }
    catch (const exception& e)
    {
        cout << "error: " << e.what() << endl;
    }
    return 0;
}

Params::Params()
{
    method = BM;
    ndisp = 64;
}

Params Params::read(int argc, char** argv)
{
    Params p;

    for (int i = 1; i < argc - 1; i += 2)
    {
        string key = argv[i];
        string val = argv[i + 1];
        if (key == "-l") p.left = val;
        else if (key == "-r") p.right = val;
        else if (key == "-m")
        {
            if (val == "BM") p.method = BM;
            else if (val == "BP") p.method = BP;
            else if (val == "CSBP") p.method = CSBP;
            else throw runtime_error("unknown stereo match method: " + val);
        }
        else if (key == "-ndisp") p.ndisp = atoi(val.c_str());
        else throw runtime_error("unknown key: " + key);
    }

    return p;
}

App::App(const Params& p)
    : p(p), running(false)
{
    cout << "stereo_match_gpu sample\n";
    cout << "\nControls:\n"
        << "\tesc - exit\n"
        << "\tp - print current parameters\n"
        << "\tg - convert source images into gray\n"
        << "\tm - change stereo match method\n"
        << "\ts - change Sobel prefiltering flag (for BM only)\n"
        << "\t1/q - increase/decrease maximum disparity\n"
        << "\t2/w - increase/decrease window size (for BM only)\n"
        << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n"
        << "\t4/r - increase/decrease level count (for BP and CSBP only)\n";
}

void App::run()
{
    // Load images
    left_src = imread(p.left);
    right_src = imread(p.right);
    if (left_src.empty()) throw runtime_error("can't open file \"" + p.left + "\"");
    if (right_src.empty()) throw runtime_error("can't open file \"" + p.right + "\"");
    cvtColor(left_src, left, CV_BGR2GRAY);
    cvtColor(right_src, right, CV_BGR2GRAY);
    d_left = left;
    d_right = right;

    imshow("left", left);
    imshow("right", right);

	// Set common parameters
    bm.ndisp = p.ndisp;
    bp.ndisp = p.ndisp;
    csbp.ndisp = p.ndisp;

    // Prepare disparity map of specified type
    Mat disp(left.size(), CV_8U);
    gpu::GpuMat d_disp(left.size(), CV_8U);

    cout << endl;
    printParams();

    running = true;
    while (running)
    {
        workBegin();
        switch (p.method)
        {
        case Params::BM:
            if (d_left.channels() > 1 || d_right.channels() > 1)
            {
                cout << "BM doesn't support color images\n";
                cvtColor(left_src, left, CV_BGR2GRAY);
                cvtColor(right_src, right, CV_BGR2GRAY);
                cout << "image_channels: " << left.channels() << endl;
                d_left = left;
                d_right = right;
                imshow("left", left);
                imshow("right", right);
            }
            bm(d_left, d_right, d_disp);
            break;
        case Params::BP: bp(d_left, d_right, d_disp); break;
        case Params::CSBP: csbp(d_left, d_right, d_disp); break;
        }
        workEnd();

        // Show results
        disp = d_disp;
        putText(disp, text(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255));
        imshow("disparity", disp);

        handleKey((char)waitKey(3));
    }
}

void App::printParams() const
{
    cout << "--- Parameters ---\n";
    cout << "image_size: (" << left.cols << ", " << left.rows << ")\n";
    cout << "image_channels: " << left.channels() << endl;
    cout << "method: " << p.method_str() << endl
        << "ndisp: " << p.ndisp << endl;
    switch (p.method)
    {
    case Params::BM:
        cout << "win_size: " << bm.winSize << endl;
        cout << "prefilter_sobel: " << bm.preset << endl;
        break;
    case Params::BP:
        cout << "iter_count: " << bp.iters << endl;
        cout << "level_count: " << bp.levels << endl;
        break;
    case Params::CSBP:
        cout << "iter_count: " << csbp.iters << endl;
        cout << "level_count: " << csbp.levels << endl;
        break;
    }
    cout << endl;
}

void App::handleKey(char key)
{
    switch (key)
    {
    case 27:
        running = false;
        break;
    case 'p': case 'P':
        printParams();
        break;
    case 'g': case 'G':
        if (left.channels() == 1 && p.method != Params::BM)
        {
            left = left_src;
            right = right_src;
        }
        else
        {
            cvtColor(left_src, left, CV_BGR2GRAY);
            cvtColor(right_src, right, CV_BGR2GRAY);
        }
        d_left = left;
        d_right = right;
        cout << "image_channels: " << left.channels() << endl;
        imshow("left", left);
        imshow("right", right);
        break;
    case 'm': case 'M':
        switch (p.method)
        {
        case Params::BM:
            p.method = Params::BP;
            break;
        case Params::BP:
            p.method = Params::CSBP;
            break;
        case Params::CSBP:
            p.method = Params::BM;
            break;
        }
        cout << "method: " << p.method_str() << endl;
        break;
    case 's': case 'S':
        if (p.method == Params::BM)
        {
            switch (bm.preset)
            {
            case gpu::StereoBM_GPU::BASIC_PRESET:
                bm.preset = gpu::StereoBM_GPU::PREFILTER_XSOBEL;
                break;
            case gpu::StereoBM_GPU::PREFILTER_XSOBEL:
                bm.preset = gpu::StereoBM_GPU::BASIC_PRESET;
                break;
            }
            cout << "prefilter_sobel: " << bm.preset << endl;
        }
        break;
    case '1':
        p.ndisp = p.ndisp == 1 ? 8 : p.ndisp + 8;
        cout << "ndisp: " << p.ndisp << endl;
        bm.ndisp = p.ndisp;
        bp.ndisp = p.ndisp;
        csbp.ndisp = p.ndisp;
        break;
    case 'q': case 'Q':
        p.ndisp = max(p.ndisp - 8, 1);
        cout << "ndisp: " << p.ndisp << endl;
        bm.ndisp = p.ndisp;
        bp.ndisp = p.ndisp;
        csbp.ndisp = p.ndisp;
        break;
    case '2':
        if (p.method == Params::BM)
        {
            bm.winSize = min(bm.winSize + 1, 51);
            cout << "win_size: " << bm.winSize << endl;
        }
        break;
    case 'w': case 'W':
        if (p.method == Params::BM)
        {
            bm.winSize = max(bm.winSize - 1, 2);
            cout << "win_size: " << bm.winSize << endl;
        }
        break;
    case '3':
        if (p.method == Params::BP)
        {
            bp.iters += 1;
            cout << "iter_count: " << bp.iters << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.iters += 1;
            cout << "iter_count: " << csbp.iters << endl;
        }
        break;
    case 'e': case 'E':
        if (p.method == Params::BP)
        {
            bp.iters = max(bp.iters - 1, 1);
            cout << "iter_count: " << bp.iters << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.iters = max(csbp.iters - 1, 1);
            cout << "iter_count: " << csbp.iters << endl;
        }
        break;
    case '4':
        if (p.method == Params::BP)
        {
            bp.levels += 1;
            cout << "level_count: " << bp.levels << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.levels += 1;
            cout << "level_count: " << csbp.levels << endl;
        }
        break;
    case 'r': case 'R':
        if (p.method == Params::BP)
        {
            bp.levels = max(bp.levels - 1, 1);
            cout << "level_count: " << bp.levels << endl;
        }
        else if (p.method == Params::CSBP)
        {
            csbp.levels = max(csbp.levels - 1, 1);
            cout << "level_count: " << csbp.levels << endl;
        }
        break;
    }
}

<|endoftext|>


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

#ifndef SC_PREVLOC_HXX
#define SC_PREVLOC_HXX

#ifndef SC_ADDRESS_HXX
#include "address.hxx"
#endif

#ifndef _LIST_HXX
#include <tools/list.hxx>
#endif

#ifndef _SV_MAPMOD_HXX
#include <vcl/mapmod.hxx>
#endif

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

#define SC_PREVIEW_MAXRANGES    4
#define SC_PREVIEW_RANGE_EDGE   0
#define SC_PREVIEW_RANGE_REPCOL 1
#define SC_PREVIEW_RANGE_REPROW 2
#define SC_PREVIEW_RANGE_TAB    3

class OutputDevice;
class String;
class Point;
class Rectangle;
class ScAddress;
class ScRange;
class ScDocument;

struct ScPreviewColRowInfo
{
    BOOL    bIsHeader;
    SCCOLROW    nDocIndex;
    long    nPixelStart;
    long    nPixelEnd;

    void Set( BOOL bHeader, SCCOLROW nIndex, long nStart, long nEnd )
    {
        bIsHeader   = bHeader;
        nDocIndex   = nIndex;
        nPixelStart = nStart;
        nPixelEnd   = nEnd;
    }
};

class ScPreviewTableInfo
{
    SCTAB                   nTab;
    SCCOL                   nCols;
    SCROW                   nRows;
    ScPreviewColRowInfo*    pColInfo;
    ScPreviewColRowInfo*    pRowInfo;

public:
            ScPreviewTableInfo();
            ~ScPreviewTableInfo();

    SCTAB                       GetTab() const      { return nTab; }
    SCCOL                       GetCols() const     { return nCols; }
    SCROW                       GetRows() const     { return nRows; }
    const ScPreviewColRowInfo*  GetColInfo() const  { return pColInfo; }
    const ScPreviewColRowInfo*  GetRowInfo() const  { return pRowInfo; }

    void    SetTab( SCTAB nNewTab );
    void    SetColInfo( SCCOL nCount, ScPreviewColRowInfo* pNewInfo );
    void    SetRowInfo( SCROW nCount, ScPreviewColRowInfo* pNewInfo );
    void    LimitToArea( const Rectangle& rPixelArea );
};

class ScPreviewLocationData
{
    OutputDevice* pWindow;
    ScDocument* pDoc;
    MapMode     aCellMapMode;
    MapMode     aDrawMapMode[SC_PREVIEW_MAXRANGES];
    Rectangle   aDrawRectangle[SC_PREVIEW_MAXRANGES];
        sal_uInt8       aDrawRangeId[SC_PREVIEW_MAXRANGES];
    USHORT      nDrawRanges;
    SCTAB       nPrintTab;
    List        aEntries;

    ScAddress   GetCellFromRange( const Size& rOffsetPixel, const ScRange& rRange ) const;
    Rectangle   GetOffsetPixel( const ScAddress& rCellPos, const ScRange& rRange ) const;

public:
            ScPreviewLocationData( ScDocument* pDocument, OutputDevice* pWin );
            ~ScPreviewLocationData();

    void    SetCellMapMode( const MapMode& rMapMode );
    void    SetPrintTab( SCTAB nNew );
    void    Clear();
    void    AddCellRange( const Rectangle& rRect, const ScRange& rRange, BOOL bRepCol, BOOL bRepRow,
                            const MapMode& rDrawMap );
    void    AddColHeaders( const Rectangle& rRect, SCCOL nStartCol, SCCOL nEndCol, BOOL bRepCol );
    void    AddRowHeaders( const Rectangle& rRect, SCROW nStartRow, SCROW nEndRow, BOOL bRepRow );
    void    AddHeaderFooter( const Rectangle& rRect, BOOL bHeader, BOOL bLeft );
    void    AddNoteMark( const Rectangle& rRect, const ScAddress& rPos );
    void    AddNoteText( const Rectangle& rRect, const ScAddress& rPos );

    SCTAB   GetPrintTab() const     { return nPrintTab; }

    //  Get info on visible columns/rows in the visible area
    void    GetTableInfo( const Rectangle& rVisiblePixel, ScPreviewTableInfo& rInfo ) const;

    USHORT  GetDrawRanges() const   { return nDrawRanges; }
    void    GetDrawRange( USHORT nPos, Rectangle& rPixelRect, MapMode& rMapMode, sal_uInt8& rRangeId ) const;

    BOOL    GetHeaderPosition( Rectangle& rHeaderRect ) const;
    BOOL    GetFooterPosition( Rectangle& rFooterRect ) const;
    BOOL    IsHeaderLeft() const;
    BOOL    IsFooterLeft() const;

    long    GetNoteCountInRange( const Rectangle& rVisiblePixel, BOOL bNoteMarks ) const;
    BOOL    GetNoteInRange( const Rectangle& rVisiblePixel, long nIndex, BOOL bNoteMarks,
                            ScAddress& rCellPos, Rectangle& rNoteRect ) const;
    Rectangle GetNoteInRangeOutputRect(const Rectangle& rVisiblePixel, BOOL bNoteMarks,
                            const ScAddress& aCellPos) const;

    //  Check if any cells (including column/row headers) are in the visible area
    BOOL    HasCellsInRange( const Rectangle& rVisiblePixel ) const;

    BOOL    GetCell( const Point& rPos, ScAddress& rCellPos, Rectangle& rCellRect ) const;
    BOOL    GetCellPosition( const ScAddress& rCellPos, Rectangle& rCellRect ) const;

    // returns the rectangle where the EditEngine draws the text of a Header Cell
    // if bColHeader is true it returns the rectangle of the header of the column in rCellPos
    // otherwise of the header of the row in rCellPos
    Rectangle GetHeaderCellOutputRect(const Rectangle& rVisRect, const ScAddress& rCellPos, sal_Bool bColHeader) const;
    Rectangle GetCellOutputRect(const ScAddress& rCellPos) const;

    // Query the range and rectangle of the main (non-repeat) cell range.
    // Returns FALSE if not contained.
    BOOL    GetMainCellRange( ScRange& rRange, Rectangle& rPixRect ) const;
};

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.11.700); FILE MERGED 2008/04/01 15:30:59 thb 1.11.700.3: #i85898# Stripping all external header guards 2008/04/01 12:36:48 thb 1.11.700.2: #i85898# Stripping all external header guards 2008/03/31 17:15:46 rt 1.11.700.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: prevloc.hxx,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.
 *
 ************************************************************************/

#ifndef SC_PREVLOC_HXX
#define SC_PREVLOC_HXX

#include "address.hxx"
#include <tools/list.hxx>
#include <vcl/mapmod.hxx>
#include <sal/types.h>

#define SC_PREVIEW_MAXRANGES    4
#define SC_PREVIEW_RANGE_EDGE   0
#define SC_PREVIEW_RANGE_REPCOL 1
#define SC_PREVIEW_RANGE_REPROW 2
#define SC_PREVIEW_RANGE_TAB    3

class OutputDevice;
class String;
class Point;
class Rectangle;
class ScAddress;
class ScRange;
class ScDocument;

struct ScPreviewColRowInfo
{
    BOOL    bIsHeader;
    SCCOLROW    nDocIndex;
    long    nPixelStart;
    long    nPixelEnd;

    void Set( BOOL bHeader, SCCOLROW nIndex, long nStart, long nEnd )
    {
        bIsHeader   = bHeader;
        nDocIndex   = nIndex;
        nPixelStart = nStart;
        nPixelEnd   = nEnd;
    }
};

class ScPreviewTableInfo
{
    SCTAB                   nTab;
    SCCOL                   nCols;
    SCROW                   nRows;
    ScPreviewColRowInfo*    pColInfo;
    ScPreviewColRowInfo*    pRowInfo;

public:
            ScPreviewTableInfo();
            ~ScPreviewTableInfo();

    SCTAB                       GetTab() const      { return nTab; }
    SCCOL                       GetCols() const     { return nCols; }
    SCROW                       GetRows() const     { return nRows; }
    const ScPreviewColRowInfo*  GetColInfo() const  { return pColInfo; }
    const ScPreviewColRowInfo*  GetRowInfo() const  { return pRowInfo; }

    void    SetTab( SCTAB nNewTab );
    void    SetColInfo( SCCOL nCount, ScPreviewColRowInfo* pNewInfo );
    void    SetRowInfo( SCROW nCount, ScPreviewColRowInfo* pNewInfo );
    void    LimitToArea( const Rectangle& rPixelArea );
};

class ScPreviewLocationData
{
    OutputDevice* pWindow;
    ScDocument* pDoc;
    MapMode     aCellMapMode;
    MapMode     aDrawMapMode[SC_PREVIEW_MAXRANGES];
    Rectangle   aDrawRectangle[SC_PREVIEW_MAXRANGES];
        sal_uInt8       aDrawRangeId[SC_PREVIEW_MAXRANGES];
    USHORT      nDrawRanges;
    SCTAB       nPrintTab;
    List        aEntries;

    ScAddress   GetCellFromRange( const Size& rOffsetPixel, const ScRange& rRange ) const;
    Rectangle   GetOffsetPixel( const ScAddress& rCellPos, const ScRange& rRange ) const;

public:
            ScPreviewLocationData( ScDocument* pDocument, OutputDevice* pWin );
            ~ScPreviewLocationData();

    void    SetCellMapMode( const MapMode& rMapMode );
    void    SetPrintTab( SCTAB nNew );
    void    Clear();
    void    AddCellRange( const Rectangle& rRect, const ScRange& rRange, BOOL bRepCol, BOOL bRepRow,
                            const MapMode& rDrawMap );
    void    AddColHeaders( const Rectangle& rRect, SCCOL nStartCol, SCCOL nEndCol, BOOL bRepCol );
    void    AddRowHeaders( const Rectangle& rRect, SCROW nStartRow, SCROW nEndRow, BOOL bRepRow );
    void    AddHeaderFooter( const Rectangle& rRect, BOOL bHeader, BOOL bLeft );
    void    AddNoteMark( const Rectangle& rRect, const ScAddress& rPos );
    void    AddNoteText( const Rectangle& rRect, const ScAddress& rPos );

    SCTAB   GetPrintTab() const     { return nPrintTab; }

    //  Get info on visible columns/rows in the visible area
    void    GetTableInfo( const Rectangle& rVisiblePixel, ScPreviewTableInfo& rInfo ) const;

    USHORT  GetDrawRanges() const   { return nDrawRanges; }
    void    GetDrawRange( USHORT nPos, Rectangle& rPixelRect, MapMode& rMapMode, sal_uInt8& rRangeId ) const;

    BOOL    GetHeaderPosition( Rectangle& rHeaderRect ) const;
    BOOL    GetFooterPosition( Rectangle& rFooterRect ) const;
    BOOL    IsHeaderLeft() const;
    BOOL    IsFooterLeft() const;

    long    GetNoteCountInRange( const Rectangle& rVisiblePixel, BOOL bNoteMarks ) const;
    BOOL    GetNoteInRange( const Rectangle& rVisiblePixel, long nIndex, BOOL bNoteMarks,
                            ScAddress& rCellPos, Rectangle& rNoteRect ) const;
    Rectangle GetNoteInRangeOutputRect(const Rectangle& rVisiblePixel, BOOL bNoteMarks,
                            const ScAddress& aCellPos) const;

    //  Check if any cells (including column/row headers) are in the visible area
    BOOL    HasCellsInRange( const Rectangle& rVisiblePixel ) const;

    BOOL    GetCell( const Point& rPos, ScAddress& rCellPos, Rectangle& rCellRect ) const;
    BOOL    GetCellPosition( const ScAddress& rCellPos, Rectangle& rCellRect ) const;

    // returns the rectangle where the EditEngine draws the text of a Header Cell
    // if bColHeader is true it returns the rectangle of the header of the column in rCellPos
    // otherwise of the header of the row in rCellPos
    Rectangle GetHeaderCellOutputRect(const Rectangle& rVisRect, const ScAddress& rCellPos, sal_Bool bColHeader) const;
    Rectangle GetCellOutputRect(const ScAddress& rCellPos) const;

    // Query the range and rectangle of the main (non-repeat) cell range.
    // Returns FALSE if not contained.
    BOOL    GetMainCellRange( ScRange& rRange, Rectangle& rPixRect ) const;
};

#endif
<|endoftext|>


<commit_before>#include "Wren++.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp, memcpy
#include <cassert>
#include <iostream>

namespace
{

struct BoundState
{
    std::unordered_map< std::size_t, WrenForeignMethodFn > methods{};
    std::unordered_map< std::size_t, WrenForeignClassMethods > classes{};
};

WrenForeignMethodFn foreignMethodProvider(WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature)
{
    auto* boundState = (BoundState*)wrenGetUserData(vm);
    auto it = boundState->methods.find(wrenpp::detail::hashMethodSignature(module, className, isStatic, signature));
    if (it == boundState->methods.end())
    {
        return NULL;
    }

    return it->second;
}

WrenForeignClassMethods foreignClassProvider(WrenVM* vm, const char* m, const char* c)
{
    auto* boundState = (BoundState*)wrenGetUserData(vm);
    auto it = boundState->classes.find(wrenpp::detail::hashClassSignature(m, c));
    if (it == boundState->classes.end())
    {
        return WrenForeignClassMethods{ nullptr, nullptr };
    }

    return it->second;
}

inline const char* errorTypeToString(WrenErrorType type)
{
    switch (type)
    {
        case WREN_ERROR_COMPILE: return "WREN_ERROR_COMPILE";
        case WREN_ERROR_RUNTIME: return "WREN_ERROR_RUNTIME";
        case WREN_ERROR_STACK_TRACE: return "WREN_ERROR_STACK_TRACE";
        default: assert(false); return "";
    }
}

char* loadModuleFnWrapper(WrenVM* vm, const char* mod)
{
    return wrenpp::VM::loadModuleFn(mod);
}

void writeFnWrapper(WrenVM* vm, const char* text)
{
    wrenpp::VM::writeFn(text);
}

void errorFnWrapper(WrenVM*, WrenErrorType type, const char* module, int line, const char* message)
{
    wrenpp::VM::errorFn(type, module, line, message);
}

void* reallocateFnWrapper(void* memory, std::size_t newSize)
{
    return wrenpp::VM::reallocateFn(memory, newSize);
}

}

namespace wrenpp
{

namespace detail
{
void registerFunction(WrenVM* vm, const std::string& mod, const std::string& cName, bool isStatic, std::string sig, WrenForeignMethodFn function)
{
    BoundState* boundState = (BoundState*)wrenGetUserData(vm);
    std::size_t hash = detail::hashMethodSignature(mod.c_str(), cName.c_str(), isStatic, sig.c_str());
    boundState->methods.insert(std::make_pair(hash, function));
}

void registerClass(WrenVM* vm, const std::string& mod, std::string cName, WrenForeignClassMethods methods)
{
    BoundState* boundState = (BoundState*)wrenGetUserData(vm);
    std::size_t hash = detail::hashClassSignature(mod.c_str(), cName.c_str());
    boundState->classes.insert(std::make_pair(hash, methods));
}

}

Value null = Value();

Value::Value(bool val)
    : type_{ WREN_TYPE_BOOL }, string_{ nullptr }
{
    set(val);
}

Value::Value(float val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(double val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(int val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(unsigned int val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(const char* str)
    : type_{ WREN_TYPE_STRING }, string_{ nullptr }
{
    string_ = (char*)VM::reallocateFn(nullptr, std::strlen(str) + 1);
    std::strcpy(string_, str);
}

Value::~Value()
{
    if (string_)
    {
        VM::reallocateFn(string_, 0u);
    }
}

Method::Method(VM* vm, WrenHandle* variable, WrenHandle* method)
    : vm_(vm),
    method_(method),
    variable_(variable)
{}

Method::Method(Method&& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_)
{
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.variable_ = nullptr;
}

Method::~Method()
{
    if (vm_)
    {
        assert(method_ && variable_);
        wrenReleaseHandle(vm_->ptr(), method_);
        wrenReleaseHandle(vm_->ptr(), variable_);
    }
}

Method& Method::operator=(Method&& rhs)
{
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    variable_ = rhs.variable_;
    rhs.vm_ = nullptr;
    rhs.method_ = nullptr;
    rhs.variable_ = nullptr;

    return *this;
}

ClassContext ModuleContext::beginClass(std::string c)
{
    return ClassContext(c, *this);
}

void ModuleContext::endModule() {}

ModuleContext& ClassContext::endClass()
{
    return module_;
}

ClassContext::ClassContext(std::string c, ModuleContext& mod)
    : module_(mod),
    class_(c)
{}

ClassContext& ClassContext::bindCFunction(bool isStatic, std::string signature, WrenForeignMethodFn function)
{
    detail::registerFunction(module_.vm_, module_.name_, class_, isStatic, signature, function);
    return *this;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn VM::loadModuleFn = [](const char* mod) -> char*
{
    std::string path(mod);
    path += ".wren";
    std::string source;
    try
    {
        source = wrenpp::detail::fileToString(path);
    }
    catch (const std::exception&)
    {
        return NULL;
    }
    char* buffer = (char*)malloc(source.size());
    assert(buffer != nullptr);
    memcpy(buffer, source.c_str(), source.size());
    return buffer;
};

WriteFn VM::writeFn = [](const char* text) -> void
{
    std::cout << text;
};

ErrorFn VM::errorFn = [](WrenErrorType type, const char* module_name, int line, const char* message) -> void
{
    const char* typeStr = errorTypeToString(type);
    if (module_name)
    {
        std::cout << typeStr << " in " << module_name << ":" << line << "> " << message << std::endl;
    }
    else
    {
        std::cout << typeStr << "> " << message << std::endl;
    }
};

ReallocateFn VM::reallocateFn = std::realloc;

std::size_t VM::initialHeapSize = 0xA00000u;

std::size_t VM::minHeapSize = 0x100000u;

int VM::heapGrowthPercent = 50;

std::size_t VM::chunkSize = 0x500000u;

VM::VM()
    : vm_{ nullptr }
{
    WrenConfiguration configuration{};
    wrenInitConfiguration(&configuration);
    configuration.reallocateFn = reallocateFnWrapper;
    configuration.initialHeapSize = initialHeapSize;
    configuration.minHeapSize = minHeapSize;
    configuration.heapGrowthPercent = heapGrowthPercent;
    configuration.bindForeignMethodFn = foreignMethodProvider;
    configuration.loadModuleFn = loadModuleFnWrapper;
    configuration.bindForeignClassFn = foreignClassProvider;
    configuration.writeFn = writeFnWrapper;
    configuration.errorFn = errorFnWrapper;
    configuration.userData = new BoundState();

    vm_ = wrenNewVM(&configuration);
}

VM::VM(VM&& other)
    : vm_{ other.vm_ }
{
    other.vm_ = nullptr;
}

VM& VM::operator=(VM&& rhs)
{
    vm_ = rhs.vm_;
    rhs.vm_ = nullptr;
    return *this;
}

VM::~VM()
{
    if (vm_ != nullptr)
    {
        delete (BoundState*)wrenGetUserData(vm_);
        wrenFreeVM(vm_);
    }
}

Result VM::executeModule(const std::string& mod)
{
    const std::string source(loadModuleFn(mod.c_str()));
    auto res = wrenInterpret(vm_, source.c_str());

    if (res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR)
    {
        return Result::CompileError;
    }

    if (res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR)
    {
        return Result::RuntimeError;
    }

    return Result::Success;
}

Result VM::executeString(const std::string& code)
{
    auto res = wrenInterpret(vm_, code.c_str());

    if (res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR)
    {
        return Result::CompileError;
    }

    if (res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR)
    {
        return Result::RuntimeError;
    }

    return Result::Success;
}

void VM::collectGarbage()
{
    wrenCollectGarbage(vm_);
}

Method VM::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
)
{
    wrenEnsureSlots(vm_, 1);
    wrenGetVariable(vm_, mod.c_str(), var.c_str(), 0);
    WrenHandle* variable = wrenGetSlotHandle(vm_, 0);
    WrenHandle* handle = wrenMakeCallHandle(vm_, sig.c_str());
    return Method(this, variable, handle);
}

ModuleContext VM::beginModule(std::string name)
{
    return ModuleContext(vm_, name);
}

}
<commit_msg>Resolve #12 (#13)<commit_after>#include "Wren++.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp, memcpy
#include <cassert>
#include <iostream>

namespace
{

struct BoundState
{
    std::unordered_map< std::size_t, WrenForeignMethodFn > methods{};
    std::unordered_map< std::size_t, WrenForeignClassMethods > classes{};
};

WrenForeignMethodFn foreignMethodProvider(WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature)
{
    auto* boundState = (BoundState*)wrenGetUserData(vm);
    auto it = boundState->methods.find(wrenpp::detail::hashMethodSignature(module, className, isStatic, signature));
    if (it == boundState->methods.end())
    {
        return NULL;
    }

    return it->second;
}

WrenForeignClassMethods foreignClassProvider(WrenVM* vm, const char* m, const char* c)
{
    auto* boundState = (BoundState*)wrenGetUserData(vm);
    auto it = boundState->classes.find(wrenpp::detail::hashClassSignature(m, c));
    if (it == boundState->classes.end())
    {
        return WrenForeignClassMethods{ nullptr, nullptr };
    }

    return it->second;
}

inline const char* errorTypeToString(WrenErrorType type)
{
    switch (type)
    {
        case WREN_ERROR_COMPILE: return "WREN_ERROR_COMPILE";
        case WREN_ERROR_RUNTIME: return "WREN_ERROR_RUNTIME";
        case WREN_ERROR_STACK_TRACE: return "WREN_ERROR_STACK_TRACE";
        default: assert(false); return "";
    }
}

char* loadModuleFnWrapper(WrenVM* vm, const char* mod)
{
    return wrenpp::VM::loadModuleFn(mod);
}

void writeFnWrapper(WrenVM* vm, const char* text)
{
    wrenpp::VM::writeFn(text);
}

void errorFnWrapper(WrenVM*, WrenErrorType type, const char* module, int line, const char* message)
{
    wrenpp::VM::errorFn(type, module, line, message);
}

void* reallocateFnWrapper(void* memory, std::size_t newSize)
{
    return wrenpp::VM::reallocateFn(memory, newSize);
}

}

namespace wrenpp
{

namespace detail
{
void registerFunction(WrenVM* vm, const std::string& mod, const std::string& cName, bool isStatic, std::string sig, WrenForeignMethodFn function)
{
    BoundState* boundState = (BoundState*)wrenGetUserData(vm);
    std::size_t hash = detail::hashMethodSignature(mod.c_str(), cName.c_str(), isStatic, sig.c_str());
    boundState->methods.insert(std::make_pair(hash, function));
}

void registerClass(WrenVM* vm, const std::string& mod, std::string cName, WrenForeignClassMethods methods)
{
    BoundState* boundState = (BoundState*)wrenGetUserData(vm);
    std::size_t hash = detail::hashClassSignature(mod.c_str(), cName.c_str());
    boundState->classes.insert(std::make_pair(hash, methods));
}

}

Value null = Value();

Value::Value(bool val)
    : type_{ WREN_TYPE_BOOL }, string_{ nullptr }
{
    set(val);
}

Value::Value(float val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(double val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(int val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(unsigned int val)
    : type_{ WREN_TYPE_NUM }, string_{ nullptr }
{
    set(val);
}

Value::Value(const char* str)
    : type_{ WREN_TYPE_STRING }, string_{ nullptr }
{
    string_ = (char*)VM::reallocateFn(nullptr, std::strlen(str) + 1);
    std::strcpy(string_, str);
}

Value::~Value()
{
    if (string_)
    {
        VM::reallocateFn(string_, 0u);
    }
}

Method::Method(VM* vm, WrenHandle* variable, WrenHandle* method)
    : vm_(vm),
    method_(method),
    variable_(variable)
{}

Method::Method(Method&& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_)
{
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.variable_ = nullptr;
}

Method::~Method()
{
    if (vm_)
    {
        assert(method_ && variable_);
        wrenReleaseHandle(vm_->ptr(), method_);
        wrenReleaseHandle(vm_->ptr(), variable_);
    }
}

Method& Method::operator=(Method&& rhs)
{
    if (&rhs != this)
    {
        vm_ = rhs.vm_;
        method_ = rhs.method_;
        variable_ = rhs.variable_;
        rhs.vm_ = nullptr;
        rhs.method_ = nullptr;
        rhs.variable_ = nullptr;
    }

    return *this;
}

ClassContext ModuleContext::beginClass(std::string c)
{
    return ClassContext(c, *this);
}

void ModuleContext::endModule() {}

ModuleContext& ClassContext::endClass()
{
    return module_;
}

ClassContext::ClassContext(std::string c, ModuleContext& mod)
    : module_(mod),
    class_(c)
{}

ClassContext& ClassContext::bindCFunction(bool isStatic, std::string signature, WrenForeignMethodFn function)
{
    detail::registerFunction(module_.vm_, module_.name_, class_, isStatic, signature, function);
    return *this;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn VM::loadModuleFn = [](const char* mod) -> char*
{
    std::string path(mod);
    path += ".wren";
    std::string source;
    try
    {
        source = wrenpp::detail::fileToString(path);
    }
    catch (const std::exception&)
    {
        return NULL;
    }
    char* buffer = (char*)malloc(source.size());
    assert(buffer != nullptr);
    memcpy(buffer, source.c_str(), source.size());
    return buffer;
};

WriteFn VM::writeFn = [](const char* text) -> void
{
    std::cout << text;
};

ErrorFn VM::errorFn = [](WrenErrorType type, const char* module_name, int line, const char* message) -> void
{
    const char* typeStr = errorTypeToString(type);
    if (module_name)
    {
        std::cout << typeStr << " in " << module_name << ":" << line << "> " << message << std::endl;
    }
    else
    {
        std::cout << typeStr << "> " << message << std::endl;
    }
};

ReallocateFn VM::reallocateFn = std::realloc;

std::size_t VM::initialHeapSize = 0xA00000u;

std::size_t VM::minHeapSize = 0x100000u;

int VM::heapGrowthPercent = 50;

std::size_t VM::chunkSize = 0x500000u;

VM::VM()
    : vm_{ nullptr }
{
    WrenConfiguration configuration{};
    wrenInitConfiguration(&configuration);
    configuration.reallocateFn = reallocateFnWrapper;
    configuration.initialHeapSize = initialHeapSize;
    configuration.minHeapSize = minHeapSize;
    configuration.heapGrowthPercent = heapGrowthPercent;
    configuration.bindForeignMethodFn = foreignMethodProvider;
    configuration.loadModuleFn = loadModuleFnWrapper;
    configuration.bindForeignClassFn = foreignClassProvider;
    configuration.writeFn = writeFnWrapper;
    configuration.errorFn = errorFnWrapper;
    configuration.userData = new BoundState();

    vm_ = wrenNewVM(&configuration);
}

VM::VM(VM&& other)
    : vm_{ other.vm_ }
{
    other.vm_ = nullptr;
}

VM& VM::operator=(VM&& rhs)
{
    if (&rhs != this)
    {
        vm_ = rhs.vm_;
        rhs.vm_ = nullptr;
    }
    return *this;
}

VM::~VM()
{
    if (vm_ != nullptr)
    {
        delete (BoundState*)wrenGetUserData(vm_);
        wrenFreeVM(vm_);
    }
}

Result VM::executeModule(const std::string& mod)
{
    const std::string source(loadModuleFn(mod.c_str()));
    auto res = wrenInterpret(vm_, source.c_str());

    if (res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR)
    {
        return Result::CompileError;
    }

    if (res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR)
    {
        return Result::RuntimeError;
    }

    return Result::Success;
}

Result VM::executeString(const std::string& code)
{
    auto res = wrenInterpret(vm_, code.c_str());

    if (res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR)
    {
        return Result::CompileError;
    }

    if (res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR)
    {
        return Result::RuntimeError;
    }

    return Result::Success;
}

void VM::collectGarbage()
{
    wrenCollectGarbage(vm_);
}

Method VM::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
)
{
    wrenEnsureSlots(vm_, 1);
    wrenGetVariable(vm_, mod.c_str(), var.c_str(), 0);
    WrenHandle* variable = wrenGetSlotHandle(vm_, 0);
    WrenHandle* handle = wrenMakeCallHandle(vm_, sig.c_str());
    return Method(this, variable, handle);
}

ModuleContext VM::beginModule(std::string name)
{
    return ModuleContext(vm_, name);
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "bitmunk/purchase/PieceDownloader.h"

#include "bitmunk/purchase/PurchaseModule.h"
#include "monarch/event/ObserverDelegate.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/rt/RunnableDelegate.h"
#include "monarch/util/Timer.h"

using namespace std;
using namespace bitmunk::common;
using namespace bitmunk::protocol;
using namespace bitmunk::purchase;
using namespace bitmunk::node;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::util;

#define EVENT_DOWNLOAD_STATE "bitmunk.purchase.DownloadState"

PieceDownloader::PieceDownloader(Node* node, FiberId parentId) :
   NodeFiber(node, parentId),
   DownloadStateFiber(node, "PieceDownloader", &mFiberExitData),
   mUniqueId(0),
   mPieceSize(0),
   mSection(NULL),
   mFileId(NULL),
   mFilePiece(NULL),
   mConnection(NULL),
   mRequest(NULL),
   mResponse(NULL),
   mPieceDownloadRate(NULL),
   mDownloadRate(NULL),
   mInterrupted(false)
{
}

PieceDownloader::~PieceDownloader()
{
   if(mFileId != NULL)
   {
      free(mFileId);
   }
}

void PieceDownloader::initialize(
   uint32_t id,
   uint32_t pieceSize,
   ContractSection& cs, FileId fileId, FilePiece& fp,
   RateAverager* pa, RateAverager* ra)
{
   mUniqueId = id;
   mPieceSize = pieceSize;
   mSection = cs.clone();
   mFileId = strdup(fileId);
   mFilePiece = fp.clone();
   mPieceDownloadRate = pa;
   mDownloadRate = ra;
}

void PieceDownloader::download()
{
   /* Algorithm:

   1. If download failed, send event, notify parent, exit.
   2. If download would block, register with IOWatcher.
   3. If download finished, send event, notify parent, exit.

   */

   bool error = false;

   // connect if not already connected
   if(mConnection == NULL)
   {
      if(connect())
      {
         // FIXME: set connection to asynchronous IO when writing optimization
         // to use IOMonitor (and maybe even move this out of an operation)

         // add bandwidth throttler to connection
         mConnection->setBandwidthThrottler(mDownloadThrottler, true);
      }
      else
      {
         error = true;
      }
   }

   if(!error)
   {
      logDownloadStateMessage("downloading piece from seller...");

      // send an event that the download has started
      sendEvent(false, EVENT_DOWNLOAD_STATE ".pieceStarted");

      // FIXME: when switching to IOMonitor, possibly just do this in
      // the fiber, and do one tiny read at a time

      // keep receiving and writing data while success
      bool success = true;
      char b[2048];
      int numBytes;
      uint64_t start = System::getCurrentMilliseconds();
      while(success && (numBytes = mInputStream->read(b, 2048)) > 0)
      {
         mTotalDownloadRate->addItems(numBytes, start);
         mDownloadRate->addItems(numBytes, start);
         mPieceDownloadRate->addItems(numBytes, start);
         success = success && mOutputStream->write(b, numBytes);
         start = System::getCurrentMilliseconds();
      }

      if(success && numBytes == 0)
      {
         // check content security
         mInMessage.checkContentSecurity(
            mResponse->getHeader(), &(*mTrailer), &(*mSignature));
         if(mInMessage.getSecurityStatus() == BtpMessage::Breach)
         {
            // set exception
            ExceptionRef e = new Exception(
               "Message security breach.",
               "bitmunk.protocol.Security");
            e->getDetails()["resource"] = mUrl.toString().c_str();
            Exception::set(e);
            success = false;
         }
      }

      if(numBytes < 0 || !success)
      {
         ExceptionRef e = Exception::get();
         if(true)//!e->getDetails()->hasMember("wouldBlock"))
         {
            // download failed:
            error = true;

            // disconnect
            mConnection->close();

            // clean up
            delete mConnection;
            delete mRequest;
            delete mResponse;
            mOutputStream->close();
            mOutputStream.setNull();
         }
         else
         {
            // download would block, register with IOWatcher (which
            // will wakeup piece downloader to run step 2 again)
            // FIXME: use &PieceDownloader::fdUpdated;
         }
      }
      else
      {
         // disconnect
         mConnection->close();

         // clean up
         delete mConnection;
         delete mRequest;
         delete mResponse;
         mOutputStream->close();
         mOutputStream.setNull();

         // download finished
         logDownloadStateMessage("piece download finished");

         MO_CAT_INFO(BM_PURCHASE_CAT,
            "UserId %" PRIu64 ", DownloadState %" PRIu64 ": "
            "piece download finished, rate: %g bytes/s",
            BM_USER_ID(mDownloadState["userId"]),
            mDownloadState["id"]->getUInt64(),
            mPieceDownloadRate->getTotalItemsPerSecond());

         // get file piece trailers:
         string value;

         // actual size of file piece
         mTrailer->getField("Bitmunk-Piece-Size", value);
         mFilePiece["size"] = value.c_str();
         // convert
         mFilePiece["size"]->setType(UInt32);
         // FIXME: check errno

         // bfp signature on piece
         mTrailer->getField("Bitmunk-Bfp-Signature", value);
         mFilePiece["bfpSignature"] = value.c_str();

         // seller signature on piece + seller profile ID
         mTrailer->getField("Bitmunk-Seller-Signature", value);
         mFilePiece["sellerSignature"] = value.c_str();
         mTrailer->getField("Bitmunk-Seller-Profile-Id", value);
         BM_ID_SET(mFilePiece["sellerProfileId"], value.c_str());

         // open key information (to be sent to SVA to unlock piece key)
         mTrailer->getField("Bitmunk-Open-Key-Algorithm", value);
         mFilePiece["openKey"]["algorithm"] = value.c_str();
         mTrailer->getField("Bitmunk-Open-Key-Data", value);
         mFilePiece["openKey"]["data"] = value.c_str();
         mTrailer->getField("Bitmunk-Open-Key-Length", value);
         mFilePiece["openKey"]["length"] = value.c_str();
         // convert
         mFilePiece["openKey"]["length"]->setType(UInt32);
         // FIXME: check errno

         // encrypted piece key information
         // (to be unlocked with open key by SVA)
         mTrailer->getField("Bitmunk-Piece-Key-Algorithm", value);
         mFilePiece["pieceKey"]["algorithm"] = value.c_str();
         mTrailer->getField("Bitmunk-Piece-Key-Data", value);
         mFilePiece["pieceKey"]["data"] = value.c_str();
         mTrailer->getField("Bitmunk-Piece-Key-Length", value);
         mFilePiece["pieceKey"]["length"] = value.c_str();
         // convert
         mFilePiece["pieceKey"]["length"]->setType(UInt32);
         // FIXME: check errno

         // set piece to encrypted and ciphered
         mFilePiece["encrypted"] = true;
         mFilePiece["ciphered"] = true;
      }
   }

   // create message regarding operation completion
   DynamicObject msg;
   msg["pieceReceived"] = !error;
   if(error)
   {
      msg["exception"] = Exception::getAsDynamicObject();
   }

   // send message to self
   messageSelf(msg);
}

void PieceDownloader::fdUpdated(int fd, int events)
{
   // FIXME: this code must be changed to send a message to self like the
   // download operation does -- this ensures that interrupting this fiber
   // happens cleanly

   /*
   // FIXME: determine if error based on events
   bool error = false;

   if(error)
   {
      // create exception for given IO error event
      // FIXME: get specific event error
      ExceptionRef e = new Exception(
         "FIXME: I am an exception that occurred while waiting for IO "
         "in the purchase module's PieceDownloader class");
      sendEvent(true, NULL);
   }
   */
}

void PieceDownloader::processMessages()
{
   logDownloadStateMessage("starting...");

   // send message to parent that piece has been started
   DynamicObject msg;
   msg["pieceDownloaderId"] = mUniqueId;
   msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
   BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
   msg["pieceStarted"] = true;
   msg["piece"] = mFilePiece.clone();
   msg["section"] = mSection.clone();
   BM_ID_SET(msg["fileId"], mFileId);
   messageParent(msg);

   // run a new download operation
   RunnableRef r = new RunnableDelegate<PieceDownloader>(
      this, &PieceDownloader::download);
   Operation op = r;
   getNode()->runOperation(op);

   // wait for messages
   const char* keys[] =
      {"interrupt", "pieceReceived", "pieceFailed", NULL};
   bool pieceReceived = false;
   bool done = false;
   while(!done)
   {
      DynamicObject list = waitForMessages(keys);
      DynamicObjectIterator i = list.getIterator();
      while(i->hasNext())
      {
         DynamicObject& msg = i->next();

         // if interrupted, interrupt operation
         if(msg->hasMember("interrupt"))
         {
            // ensure unique piece downloader ID matches
            if(mUniqueId == msg["pieceDownloaderId"]->getUInt32())
            {
               // piece downloader interrupted
               mInterrupted = true;

               // send interruption event if pause is false
               if(!msg["pause"]->getBoolean())
               {
                  ExceptionRef e = new Exception(
                     "PieceDownloader interrupted.",
                     "bitmunk.purchase.PieceDownloader.interrupted");
                  Exception::set(e);
                  sendEvent(true, NULL);
               }

               // interrupt download operation
               op->interrupt();
            }
         }
         // message regards receiving piece
         else if(msg["pieceReceived"]->getBoolean())
         {
            sendEvent(false, EVENT_DOWNLOAD_STATE ".pieceFinished");
            pieceReceived = done = true;
         }
         // piece failed message
         else
         {
            // only send an error event if there was no interruption
            if(!mInterrupted)
            {
               // convert the exception from a dynamic object, send error event
               ExceptionRef e = Exception::convertToException(msg["exception"]);
               Exception::set(e);
               sendEvent(true, NULL);
            }

            done = true;
         }
      }
   }

   if(pieceReceived)
   {
      logDownloadStateMessage("finished with success");

      // send message to parent that piece has been received
      DynamicObject msg;
      msg["pieceDownloaderId"] = mUniqueId;
      msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
      BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
      msg["pieceReceived"] = true;
      msg["piece"] = mFilePiece;
      msg["section"] = mSection;
      BM_ID_SET(msg["fileId"], mFileId);
      msg["pieceRate"] = mPieceDownloadRate->getTotalItemsPerSecond();
      messageParent(msg);
   }
   else
   {
      logDownloadStateMessage("finished with error");

      // send message to parent that piece has failed
      DynamicObject msg;
      msg["pieceDownloaderId"] = mUniqueId;
      msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
      BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
      msg["pieceFailed"] = true;
      msg["piece"] = mFilePiece;
      msg["section"] = mSection;
      BM_ID_SET(msg["fileId"], mFileId);
      msg["pieceRate"] = mPieceDownloadRate->getTotalItemsPerSecond();
      messageParent(msg);
   }
}

bool PieceDownloader::connect()
{
   bool rval = false;

   // get buyer's profile
   ProfileRef profile;
   UserId userId = BM_USER_ID(mDownloadState["userId"]);
   if((rval = getNode()->getLoginData(userId, NULL, &profile)))
   {
      // find media ID for file ID
      MediaId mediaId = 0;
      FileInfoIterator fii = mSection["ware"]["fileInfos"].getIterator();
      while(mediaId == 0 && fii->hasNext())
      {
         FileInfo& fi = fii->next();
         if(BM_FILE_ID_EQUALS(BM_FILE_ID(fi["id"]), mFileId))
         {
            mediaId = BM_MEDIA_ID(fi["mediaId"]);
         }
      }

      // create piece request
      DynamicObject pieceRequest;
      pieceRequest["csHash"] = mSection["hash"]->getString();
      BM_ID_SET(pieceRequest["fileId"], mFileId);
      BM_ID_SET(pieceRequest["mediaId"], mediaId);
      pieceRequest["index"] = mFilePiece["index"]->getUInt32();
      // use full standard piece size, seller may truncate if last piece
      pieceRequest["size"] = mPieceSize;
      pieceRequest["peerbuyKey"] = mSection["peerbuyKey"]->getString();
      BM_ID_SET(
         pieceRequest["sellerProfileId"],
         BM_PROFILE_ID(mSection["seller"]["profileId"]));
      BM_ID_SET(pieceRequest["bfpId"], BM_BFP_ID(mFilePiece["bfpId"]));

      // setup btp messages
      mOutMessage.setDynamicObject(pieceRequest);
      mOutMessage.setType(BtpMessage::Post);
      mOutMessage.setUserId(userId);
      mOutMessage.setAgentProfile(profile);
      mInMessage.setPublicKeySource(getNode()->getPublicKeyCache());

      // create url to get file piece
      mUrl.format("%s/api/3.0/sales/contract/filepiece?nodeuser=%" PRIu64,
         mSection["seller"]["url"]->getString(),
         BM_USER_ID(mSection["seller"]["userId"]));

      MO_CAT_INFO(BM_PURCHASE_CAT,
         "UserId %" PRIu64 ", DownloadState %" PRIu64 ": "
         "connecting to seller (%" PRIu64 ":%u) @ %s",
         BM_USER_ID(mDownloadState["userId"]),
         mDownloadState["id"]->getUInt64(),
         BM_USER_ID(mSection["seller"]["userId"]),
         BM_SERVER_ID(mSection["seller"]["serverId"]),
         mUrl.toString().c_str());

      // connect to seller
      // bfp->startReading() may take more than 30 seconds to execute
      // on seller side, so clients should set their read timeouts to
      // something high like 2-5 minutes
      // FIXME: this may need to be done in the IOMonitor/IOWatcher, not
      // on the connection
      BtpClient* btpc = getNode()->getMessenger()->getBtpClient();
      mConnection = btpc->createConnection(
         BM_USER_ID(mSection["seller"]["userId"]), &mUrl, 120);
      if((rval = (mConnection != NULL)))
      {
         logDownloadStateMessage("connected to seller...");

         // create request and response
         mRequest = mConnection->createRequest();
         mResponse = mRequest->createResponse();

         // send message
         if((rval = btpc->sendMessage(
            &mUrl, &mOutMessage, mRequest, &mInMessage, mResponse)))
         {
            logDownloadStateMessage("preparing to download piece...");

            // get receive content stream
            mInMessage.getContentReceiveStream(
               mResponse, mInputStream, mTrailer, mSignature);

            // set up output stream
            File file(mFilePiece["path"]->getString());
            if(!(rval = file->mkdirs()))
            {
               ExceptionRef e = new Exception(
                  "Failed to create output directory for downloading file "
                  "pieces.",
                  "bitmunk.purchase.PieceDownloader.OutputFileWriteError");
               e->getDetails()["path"] = file->getPath();
               Exception::push(e);
            }
            else
            {
               mOutputStream = new FileOutputStream(file);
            }
         }
      }

      if(!rval)
      {
         // clean up
         if(mConnection != NULL)
         {
            mConnection->close();
            delete mConnection;
            delete mRequest;
            delete mResponse;
         }
      }
   }

   return rval;
}
// FIXME: clean these parameters up, its ugly
void PieceDownloader::sendEvent(bool error, const char* type)
{
   Event e;

   if(error)
   {
      // set failure event
      e["type"] = EVENT_DOWNLOAD_STATE ".exception";
      e["details"]["exception"] = Exception::getAsDynamicObject();
   }
   else
   {
      // send success event
      e["type"] = type;
   }

   // send event
   BM_ID_SET(e["details"]["fileId"], mFileId);
   e["details"]["piece"] = mFilePiece;
   e["details"]["downloaded"] = mPieceDownloadRate->getTotalItemCount();
   sendDownloadStateEvent(e);
}
<commit_msg>Updated FIXME.<commit_after>/*
 * Copyright (c) 2008-2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "bitmunk/purchase/PieceDownloader.h"

#include "bitmunk/purchase/PurchaseModule.h"
#include "monarch/event/ObserverDelegate.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/rt/RunnableDelegate.h"
#include "monarch/util/Timer.h"

using namespace std;
using namespace bitmunk::common;
using namespace bitmunk::protocol;
using namespace bitmunk::purchase;
using namespace bitmunk::node;
using namespace monarch::event;
using namespace monarch::fiber;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::util;

#define EVENT_DOWNLOAD_STATE "bitmunk.purchase.DownloadState"

PieceDownloader::PieceDownloader(Node* node, FiberId parentId) :
   NodeFiber(node, parentId),
   DownloadStateFiber(node, "PieceDownloader", &mFiberExitData),
   mUniqueId(0),
   mPieceSize(0),
   mSection(NULL),
   mFileId(NULL),
   mFilePiece(NULL),
   mConnection(NULL),
   mRequest(NULL),
   mResponse(NULL),
   mPieceDownloadRate(NULL),
   mDownloadRate(NULL),
   mInterrupted(false)
{
}

PieceDownloader::~PieceDownloader()
{
   if(mFileId != NULL)
   {
      free(mFileId);
   }
}

void PieceDownloader::initialize(
   uint32_t id,
   uint32_t pieceSize,
   ContractSection& cs, FileId fileId, FilePiece& fp,
   RateAverager* pa, RateAverager* ra)
{
   mUniqueId = id;
   mPieceSize = pieceSize;
   mSection = cs.clone();
   mFileId = strdup(fileId);
   mFilePiece = fp.clone();
   mPieceDownloadRate = pa;
   mDownloadRate = ra;
}

void PieceDownloader::download()
{
   /* Algorithm:

   1. If download failed, send event, notify parent, exit.
   2. If download would block, register with IOWatcher.
   3. If download finished, send event, notify parent, exit.

   */

   bool error = false;

   // connect if not already connected
   if(mConnection == NULL)
   {
      if(connect())
      {
         // FIXME: set connection to asynchronous IO when writing optimization
         // to use IOMonitor (and maybe even move this out of an operation)

         // add bandwidth throttler to connection
         mConnection->setBandwidthThrottler(mDownloadThrottler, true);
      }
      else
      {
         error = true;
      }
   }

   if(!error)
   {
      logDownloadStateMessage("downloading piece from seller...");

      // send an event that the download has started
      sendEvent(false, EVENT_DOWNLOAD_STATE ".pieceStarted");

      // FIXME: when switching to IOMonitor this will be done in the fiber
      // with IO scheduling handled at the appropriate layer

      // keep receiving and writing data while success
      bool success = true;
      char b[2048];
      int numBytes;
      uint64_t start = System::getCurrentMilliseconds();
      while(success && (numBytes = mInputStream->read(b, 2048)) > 0)
      {
         mTotalDownloadRate->addItems(numBytes, start);
         mDownloadRate->addItems(numBytes, start);
         mPieceDownloadRate->addItems(numBytes, start);
         success = success && mOutputStream->write(b, numBytes);
         start = System::getCurrentMilliseconds();
      }

      if(success && numBytes == 0)
      {
         // check content security
         mInMessage.checkContentSecurity(
            mResponse->getHeader(), &(*mTrailer), &(*mSignature));
         if(mInMessage.getSecurityStatus() == BtpMessage::Breach)
         {
            // set exception
            ExceptionRef e = new Exception(
               "Message security breach.",
               "bitmunk.protocol.Security");
            e->getDetails()["resource"] = mUrl.toString().c_str();
            Exception::set(e);
            success = false;
         }
      }

      if(numBytes < 0 || !success)
      {
         ExceptionRef e = Exception::get();
         if(true)//!e->getDetails()->hasMember("wouldBlock"))
         {
            // download failed:
            error = true;

            // disconnect
            mConnection->close();

            // clean up
            delete mConnection;
            delete mRequest;
            delete mResponse;
            mOutputStream->close();
            mOutputStream.setNull();
         }
         else
         {
            // download would block, register with IOWatcher (which
            // will wakeup piece downloader to run step 2 again)
            // FIXME: use &PieceDownloader::fdUpdated;
         }
      }
      else
      {
         // disconnect
         mConnection->close();

         // clean up
         delete mConnection;
         delete mRequest;
         delete mResponse;
         mOutputStream->close();
         mOutputStream.setNull();

         // download finished
         logDownloadStateMessage("piece download finished");

         MO_CAT_INFO(BM_PURCHASE_CAT,
            "UserId %" PRIu64 ", DownloadState %" PRIu64 ": "
            "piece download finished, rate: %g bytes/s",
            BM_USER_ID(mDownloadState["userId"]),
            mDownloadState["id"]->getUInt64(),
            mPieceDownloadRate->getTotalItemsPerSecond());

         // get file piece trailers:
         string value;

         // actual size of file piece
         mTrailer->getField("Bitmunk-Piece-Size", value);
         mFilePiece["size"] = value.c_str();
         // convert
         mFilePiece["size"]->setType(UInt32);
         // FIXME: check errno

         // bfp signature on piece
         mTrailer->getField("Bitmunk-Bfp-Signature", value);
         mFilePiece["bfpSignature"] = value.c_str();

         // seller signature on piece + seller profile ID
         mTrailer->getField("Bitmunk-Seller-Signature", value);
         mFilePiece["sellerSignature"] = value.c_str();
         mTrailer->getField("Bitmunk-Seller-Profile-Id", value);
         BM_ID_SET(mFilePiece["sellerProfileId"], value.c_str());

         // open key information (to be sent to SVA to unlock piece key)
         mTrailer->getField("Bitmunk-Open-Key-Algorithm", value);
         mFilePiece["openKey"]["algorithm"] = value.c_str();
         mTrailer->getField("Bitmunk-Open-Key-Data", value);
         mFilePiece["openKey"]["data"] = value.c_str();
         mTrailer->getField("Bitmunk-Open-Key-Length", value);
         mFilePiece["openKey"]["length"] = value.c_str();
         // convert
         mFilePiece["openKey"]["length"]->setType(UInt32);
         // FIXME: check errno

         // encrypted piece key information
         // (to be unlocked with open key by SVA)
         mTrailer->getField("Bitmunk-Piece-Key-Algorithm", value);
         mFilePiece["pieceKey"]["algorithm"] = value.c_str();
         mTrailer->getField("Bitmunk-Piece-Key-Data", value);
         mFilePiece["pieceKey"]["data"] = value.c_str();
         mTrailer->getField("Bitmunk-Piece-Key-Length", value);
         mFilePiece["pieceKey"]["length"] = value.c_str();
         // convert
         mFilePiece["pieceKey"]["length"]->setType(UInt32);
         // FIXME: check errno

         // set piece to encrypted and ciphered
         mFilePiece["encrypted"] = true;
         mFilePiece["ciphered"] = true;
      }
   }

   // create message regarding operation completion
   DynamicObject msg;
   msg["pieceReceived"] = !error;
   if(error)
   {
      msg["exception"] = Exception::getAsDynamicObject();
   }

   // send message to self
   messageSelf(msg);
}

void PieceDownloader::fdUpdated(int fd, int events)
{
   // FIXME: this code must be changed to send a message to self like the
   // download operation does -- this ensures that interrupting this fiber
   // happens cleanly

   /*
   // FIXME: determine if error based on events
   bool error = false;

   if(error)
   {
      // create exception for given IO error event
      // FIXME: get specific event error
      ExceptionRef e = new Exception(
         "FIXME: I am an exception that occurred while waiting for IO "
         "in the purchase module's PieceDownloader class");
      sendEvent(true, NULL);
   }
   */
}

void PieceDownloader::processMessages()
{
   logDownloadStateMessage("starting...");

   // send message to parent that piece has been started
   DynamicObject msg;
   msg["pieceDownloaderId"] = mUniqueId;
   msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
   BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
   msg["pieceStarted"] = true;
   msg["piece"] = mFilePiece.clone();
   msg["section"] = mSection.clone();
   BM_ID_SET(msg["fileId"], mFileId);
   messageParent(msg);

   // run a new download operation
   RunnableRef r = new RunnableDelegate<PieceDownloader>(
      this, &PieceDownloader::download);
   Operation op = r;
   getNode()->runOperation(op);

   // wait for messages
   const char* keys[] =
      {"interrupt", "pieceReceived", "pieceFailed", NULL};
   bool pieceReceived = false;
   bool done = false;
   while(!done)
   {
      DynamicObject list = waitForMessages(keys);
      DynamicObjectIterator i = list.getIterator();
      while(i->hasNext())
      {
         DynamicObject& msg = i->next();

         // if interrupted, interrupt operation
         if(msg->hasMember("interrupt"))
         {
            // ensure unique piece downloader ID matches
            if(mUniqueId == msg["pieceDownloaderId"]->getUInt32())
            {
               // piece downloader interrupted
               mInterrupted = true;

               // send interruption event if pause is false
               if(!msg["pause"]->getBoolean())
               {
                  ExceptionRef e = new Exception(
                     "PieceDownloader interrupted.",
                     "bitmunk.purchase.PieceDownloader.interrupted");
                  Exception::set(e);
                  sendEvent(true, NULL);
               }

               // interrupt download operation
               op->interrupt();
            }
         }
         // message regards receiving piece
         else if(msg["pieceReceived"]->getBoolean())
         {
            sendEvent(false, EVENT_DOWNLOAD_STATE ".pieceFinished");
            pieceReceived = done = true;
         }
         // piece failed message
         else
         {
            // only send an error event if there was no interruption
            if(!mInterrupted)
            {
               // convert the exception from a dynamic object, send error event
               ExceptionRef e = Exception::convertToException(msg["exception"]);
               Exception::set(e);
               sendEvent(true, NULL);
            }

            done = true;
         }
      }
   }

   if(pieceReceived)
   {
      logDownloadStateMessage("finished with success");

      // send message to parent that piece has been received
      DynamicObject msg;
      msg["pieceDownloaderId"] = mUniqueId;
      msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
      BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
      msg["pieceReceived"] = true;
      msg["piece"] = mFilePiece;
      msg["section"] = mSection;
      BM_ID_SET(msg["fileId"], mFileId);
      msg["pieceRate"] = mPieceDownloadRate->getTotalItemsPerSecond();
      messageParent(msg);
   }
   else
   {
      logDownloadStateMessage("finished with error");

      // send message to parent that piece has failed
      DynamicObject msg;
      msg["pieceDownloaderId"] = mUniqueId;
      msg["downloadStateId"] = mDownloadState["id"]->getUInt64();
      BM_ID_SET(msg["userId"], BM_USER_ID(mDownloadState["userId"]));
      msg["pieceFailed"] = true;
      msg["piece"] = mFilePiece;
      msg["section"] = mSection;
      BM_ID_SET(msg["fileId"], mFileId);
      msg["pieceRate"] = mPieceDownloadRate->getTotalItemsPerSecond();
      messageParent(msg);
   }
}

bool PieceDownloader::connect()
{
   bool rval = false;

   // get buyer's profile
   ProfileRef profile;
   UserId userId = BM_USER_ID(mDownloadState["userId"]);
   if((rval = getNode()->getLoginData(userId, NULL, &profile)))
   {
      // find media ID for file ID
      MediaId mediaId = 0;
      FileInfoIterator fii = mSection["ware"]["fileInfos"].getIterator();
      while(mediaId == 0 && fii->hasNext())
      {
         FileInfo& fi = fii->next();
         if(BM_FILE_ID_EQUALS(BM_FILE_ID(fi["id"]), mFileId))
         {
            mediaId = BM_MEDIA_ID(fi["mediaId"]);
         }
      }

      // create piece request
      DynamicObject pieceRequest;
      pieceRequest["csHash"] = mSection["hash"]->getString();
      BM_ID_SET(pieceRequest["fileId"], mFileId);
      BM_ID_SET(pieceRequest["mediaId"], mediaId);
      pieceRequest["index"] = mFilePiece["index"]->getUInt32();
      // use full standard piece size, seller may truncate if last piece
      pieceRequest["size"] = mPieceSize;
      pieceRequest["peerbuyKey"] = mSection["peerbuyKey"]->getString();
      BM_ID_SET(
         pieceRequest["sellerProfileId"],
         BM_PROFILE_ID(mSection["seller"]["profileId"]));
      BM_ID_SET(pieceRequest["bfpId"], BM_BFP_ID(mFilePiece["bfpId"]));

      // setup btp messages
      mOutMessage.setDynamicObject(pieceRequest);
      mOutMessage.setType(BtpMessage::Post);
      mOutMessage.setUserId(userId);
      mOutMessage.setAgentProfile(profile);
      mInMessage.setPublicKeySource(getNode()->getPublicKeyCache());

      // create url to get file piece
      mUrl.format("%s/api/3.0/sales/contract/filepiece?nodeuser=%" PRIu64,
         mSection["seller"]["url"]->getString(),
         BM_USER_ID(mSection["seller"]["userId"]));

      MO_CAT_INFO(BM_PURCHASE_CAT,
         "UserId %" PRIu64 ", DownloadState %" PRIu64 ": "
         "connecting to seller (%" PRIu64 ":%u) @ %s",
         BM_USER_ID(mDownloadState["userId"]),
         mDownloadState["id"]->getUInt64(),
         BM_USER_ID(mSection["seller"]["userId"]),
         BM_SERVER_ID(mSection["seller"]["serverId"]),
         mUrl.toString().c_str());

      // connect to seller
      // bfp->startReading() may take more than 30 seconds to execute
      // on seller side, so clients should set their read timeouts to
      // something high like 2-5 minutes
      // FIXME: this may need to be done in the IOMonitor/IOWatcher, not
      // on the connection
      BtpClient* btpc = getNode()->getMessenger()->getBtpClient();
      mConnection = btpc->createConnection(
         BM_USER_ID(mSection["seller"]["userId"]), &mUrl, 120);
      if((rval = (mConnection != NULL)))
      {
         logDownloadStateMessage("connected to seller...");

         // create request and response
         mRequest = mConnection->createRequest();
         mResponse = mRequest->createResponse();

         // send message
         if((rval = btpc->sendMessage(
            &mUrl, &mOutMessage, mRequest, &mInMessage, mResponse)))
         {
            logDownloadStateMessage("preparing to download piece...");

            // get receive content stream
            mInMessage.getContentReceiveStream(
               mResponse, mInputStream, mTrailer, mSignature);

            // set up output stream
            File file(mFilePiece["path"]->getString());
            if(!(rval = file->mkdirs()))
            {
               ExceptionRef e = new Exception(
                  "Failed to create output directory for downloading file "
                  "pieces.",
                  "bitmunk.purchase.PieceDownloader.OutputFileWriteError");
               e->getDetails()["path"] = file->getPath();
               Exception::push(e);
            }
            else
            {
               mOutputStream = new FileOutputStream(file);
            }
         }
      }

      if(!rval)
      {
         // clean up
         if(mConnection != NULL)
         {
            mConnection->close();
            delete mConnection;
            delete mRequest;
            delete mResponse;
         }
      }
   }

   return rval;
}
// FIXME: clean these parameters up, its ugly
void PieceDownloader::sendEvent(bool error, const char* type)
{
   Event e;

   if(error)
   {
      // set failure event
      e["type"] = EVENT_DOWNLOAD_STATE ".exception";
      e["details"]["exception"] = Exception::getAsDynamicObject();
   }
   else
   {
      // send success event
      e["type"] = type;
   }

   // send event
   BM_ID_SET(e["details"]["fileId"], mFileId);
   e["details"]["piece"] = mFilePiece;
   e["details"]["downloaded"] = mPieceDownloadRate->getTotalItemCount();
   sendDownloadStateEvent(e);
}
<|endoftext|>