<commit_before>//----------------------------------------------------------------------------
/// \file   enumu.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief This file defines enum with assignable unique values
//----------------------------------------------------------------------------
// Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>
// Created: 2015-04-11
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/variadic_seq_to_seq.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/tuple/push_back.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <utxx/detail/enum_helper.hpp>
#include <utxx/string.hpp>
#include <cassert>
#include <map>

#ifdef UTXX_ENUM_SUPPORT_SERIALIZATION
# ifndef UTXX__ENUM_FRIEND_SERIALIZATION__
#   include <boost/serialization/access.hpp>

#   define UTXX__ENUM_FRIEND_SERIALIZATION__ \
    friend class boost::serialization::access
# endif
#else
# ifndef UTXX__ENUM_FRIEND_SERIALIZATION__
#   define UTXX__ENUM_FRIEND_SERIALIZATION__
# endif
#endif

//------------------------------------------------------------------------------
/// The difference between enumu.hpp and enumv.hpp is that UTXX_ENUMU
/// allows the enum to have specific enumerated unique constants, whereas
/// UTXX_ENUMV permits the use of non-unique constants. The enum name lookup by
/// value is faster for UTXX_ENUMU, since it uses a play array with lookup by
/// index, whereas UTXX_ENUMV uses a map, so ```enum X { A=1, B=2 }``` is
/// equivalent to ```UTXX_ENUMU(X, int, (A, 1)(B, 2))```, and name lookups are
/// implemented using:
///       ```
///          switch(val) {
///             case 1: return "A";
///             case 2: return "B";
///             ...
///          }
///       ```
/// `UTXX_ENUMU(EnumName, Opts, Enums)`
/// * EnumName - the name of ENUM
/// * Opts - can be one of three formats:
///     * Type                      - Enum of Type. Adds DEF_NAME=0.
///     * (Type,DefValue)           - Enum of Type. Adds DEF_NAME=DefValue.
///     * (Type,UndefName,DefValue) - Enum of Type. Adds UndefName=DefValue.
///     * (Type,UndefName,DefValue,FirstVal) - Ditto. Start enum with FirstVal.
/// * Enums is either a variadic list or sequence of arguments:
///     * Enum1, Enum2, ...
///     * (Enum1)(Enum2)...
///     where each `EnumN` can be given a Value associated with each EnumName,
///     and may optionally specify a symbolic value label:
///         * EnumName
///         * (EnumName,Value)              - EnumName's code()  = Value
///         * (EnumName,Value,"EnumValue")  - EnumName's value() = "EnumValue"
//------------------------------------------------------------------------------
/// NOTE: DefValue as well as values given to EnumName's must be distinct!
//------------------------------------------------------------------------------
/// Enum declaration:
/// ```
/// #include <utxx/enumu.hpp>
///
/// UTXX_ENUMU(MyEnumT,
///    (                    // This parameter is a tuple of up to four elements:
///     char,               //   This is enum storage type
///     NIL,                //   Name of the undefined type
///     ' ',                //   NIL's value
///     'a'                 //   Value assigned to the first item (Orange)
///    ),
///    (Orange)             // Orange's value will be set to 'a'
///    (Apple, 'x', "Fuji") // Item with a value and with name string "Fuji"
///    (Pear,  'y')         // Item with value 'y' (name defaults to "Pear")
/// // (Fig,   'y')         // NOTE: this would result in compile-time error!
///    (Grape)              // Grape's value will be equal to 'y'+1
/// );
///
/// Sample usage:
/// MyEnumT val = MyEnumT::from_string("Pear");
/// std::cout << "Value: " << to_string(val) << std::endl;
/// std::cout << "Value: " << val            << std::endl;
//------------------------------------------------------------------------------
#define UTXX_ENUMU(ENUM, TYPE, ...)                                            \
        UTXX_ENUMU__(                                                          \
            ENUM,                                                              \
            UTXX_ENUM_GET_TYPE(TYPE),                                          \
            UTXX_ENUM_GET_UNDEF_NAME(TYPE),                                    \
            UTXX_ENUM_GET_UNDEF_VAL(TYPE),                                     \
            UTXX_ENUM_GET_FIRST_VAL(TYPE),                                     \
            BOOST_PP_TUPLE_ENUM(                                               \
                BOOST_PP_IF(                                                   \
                    BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1),    \
                        BOOST_PP_IF(BOOST_PP_IS_BEGIN_PARENS(__VA_ARGS__),     \
                            (__VA_ARGS__),                                     \
                            ((__VA_ARGS__))),                                  \
                        (BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))))              \
        )

#define UTXX_ENUMU__(ENUM, TYPE, DEF_NAME, DEF_VAL, ...)                       \
    struct ENUM {                                                              \
        using value_type = TYPE;                                               \
                                                                               \
        enum type : TYPE {                                                     \
            DEF_NAME = (DEF_VAL),                                              \
            BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(                          \
                UTXX_ENUM_INTERNAL_GET_NAMEVAL__, _,                           \
                BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__)))                    \
        };                                                                     \
                                                                               \
        using meta_type  = std::tuple<type, std::string, std::string>;         \
                                                                               \
        explicit  ENUM(long v) noexcept : m_val(type(v))   {}                  \
        constexpr ENUM()       noexcept : m_val(DEF_NAME)  {}                  \
        constexpr ENUM(type v) noexcept : m_val(v)         {}                  \
                                                                               \
        ENUM(ENUM&&)                 = default;                                \
        ENUM(ENUM const&)            = default;                                \
                                                                               \
        ENUM& operator=(ENUM const&) = default;                                \
        ENUM& operator=(ENUM&&)      = default;                                \
                                                                               \
        static constexpr const char*   class_name() { return #ENUM;        }   \
        constexpr operator  type()     const { return m_val; }                 \
        constexpr bool      empty()    const { return m_val == DEF_NAME;   }   \
        void                clear()          { m_val =  DEF_NAME;          }   \
                                                                               \
        static    constexpr bool is_enum()   { return true;                }   \
        static    constexpr bool is_flags()  { return false;               }   \
                                                                               \
        const std::string& name()    const { return std::get<1>(meta(m_val));} \
        const std::string& value()   const { return std::get<2>(meta(m_val));} \
        TYPE               code()    const { return TYPE(m_val);           }   \
                                                                               \
        const std::string& to_string() const { return value();             }   \
        static const std::string&                                              \
                           to_string(type a) { return ENUM(a).to_string(); }   \
        const char*        c_str()     const { return to_string().c_str(); }   \
        static const char* c_str(type a)     { return to_string(a).c_str();}   \
                                                                               \
        /* Returns true if the given value is a valid value for this enum */   \
        static constexpr bool valid(TYPE v)  {                                 \
            if (v == DEF_NAME) return true;                                    \
            bool found = false;                                                \
            auto f = [&found, v](type t, auto&) {                              \
                if (t == v) { found = true; return false; }                    \
                return true;                                                   \
            };                                                                 \
            for_each(f);                                                       \
            return found;                                                      \
        }                                                                      \
                                                                               \
        static ENUM                                                            \
        from_string(const char* a, bool a_nocase=false, bool as_name=false)  { \
            auto f = a_nocase ? &strcasecmp : &strcmp;                         \
            for (auto& t : metas())                                            \
                if (!f((as_name ? std::get<1>(t) : std::get<2>(t)).c_str(),a)) \
                    return ENUM(std::get<0>(t));                               \
            return ENUM(DEF_NAME);                                             \
        }                                                                      \
                                                                               \
        static ENUM from_string(const std::string& a, bool a_nocase=false,     \
                                bool as_name=false)                            \
            { return from_string(a.c_str(), a_nocase, as_name); }              \
                                                                               \
        static ENUM from_string_nc(const std::string& a, bool as_name=false) { \
            return from_string(a, true, as_name);                              \
        }                                                                      \
        static ENUM from_string_nc(const char* a, bool as_name=false) {        \
            return from_string(a, true, as_name);                              \
        }                                                                      \
                                                                               \
        static ENUM from_name(const char* a, bool a_nocase=false) {            \
            return from_string(a, a_nocase, true);                             \
        }                                                                      \
        static ENUM from_value(const char* a, bool a_nocase=false) {           \
            return from_string(a, a_nocase, false);                            \
        }                                                                      \
                                                                               \
        template <typename StreamT>                                            \
        inline friend StreamT& operator<< (StreamT& out, ENUM const& a) {      \
            out << a.value();                                                  \
            return out;                                                        \
        }                                                                      \
                                                                               \
        template <typename StreamT>                                            \
        inline friend StreamT& operator<< (StreamT& out, ENUM::type a)  {      \
            return out << ENUM(a);                                             \
        }                                                                      \
                                                                               \
        static constexpr size_t size()  { return s_size-1; }                   \
                                                                               \
        template <typename Visitor>                                            \
        static void for_each(const Visitor& a_fun) {                           \
            int i=0;                                                           \
            for (auto& m : metas())                                            \
                if (i++ && !a_fun(m))                                          \
                    break;                                                     \
        }                                                                      \
                                                                               \
    private:                                                                   \
        static const meta_type& null_meta() {                                  \
            static const meta_type s_val =                                     \
                std::make_tuple(DEF_NAME, BOOST_PP_STRINGIZE(DEF_NAME),        \
                                          BOOST_PP_STRINGIZE(DEF_NAME));       \
            return s_val;                                                      \
        }                                                                      \
        static const size_t s_size =                                           \
            1+BOOST_PP_SEQ_SIZE(BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__));    \
        static const std::array<meta_type, s_size>& metas() {                  \
            static const std::array<meta_type, s_size> s_metas{{               \
                null_meta(),                                                   \
                BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(                      \
                    UTXX_INTERNAL_ENUMU_META_TUPLE__, _,                       \
                    BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__)))                \
            }};                                                                \
            return s_metas;                                                    \
        }                                                                      \
                                                                               \
        static const meta_type& meta(type n) {                                 \
            switch (n) {                                                       \
                case DEF_NAME: return metas()[0];                              \
                BOOST_PP_SEQ_FOR_EACH_I_R(1,                                   \
                    UTXX_INTERNAL_ENUMU_CASE__, _,                             \
                    BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__))                 \
                default:        return metas()[0];                             \
            }                                                                  \
        }                                                                      \
                                                                               \
        UTXX__ENUM_FRIEND_SERIALIZATION__;                                     \
                                                                               \
        type m_val;                                                            \
    }

#define UTXX_INTERNAL_ENUMU_META_TUPLE__(x, _, val)                            \
    std::make_tuple(                                                           \
        BOOST_PP_TUPLE_ELEM(0, val),                                           \
        BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, val)),                       \
        BOOST_PP_IIF(                                                          \
            BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(val), 2),                     \
            BOOST_PP_TUPLE_ELEM(2, BOOST_PP_TUPLE_PUSH_BACK(val,_)),           \
            BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, val))))

#define UTXX_INTERNAL_ENUMU_CASE__(x, _, i, item)                              \
            case BOOST_PP_TUPLE_ELEM(0, item): return metas()[BOOST_PP_INC(i)];
<commit_msg>Fix enumu compilation problem<commit_after>//----------------------------------------------------------------------------
/// \file   enumu.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief This file defines enum with assignable unique values
//----------------------------------------------------------------------------
// Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>
// Created: 2015-04-11
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/variadic/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/variadic_seq_to_seq.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/tuple/push_back.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <utxx/detail/enum_helper.hpp>
#include <utxx/string.hpp>
#include <cassert>
#include <map>

#ifdef UTXX_ENUM_SUPPORT_SERIALIZATION
# ifndef UTXX__ENUM_FRIEND_SERIALIZATION__
#   include <boost/serialization/access.hpp>

#   define UTXX__ENUM_FRIEND_SERIALIZATION__ \
    friend class boost::serialization::access
# endif
#else
# ifndef UTXX__ENUM_FRIEND_SERIALIZATION__
#   define UTXX__ENUM_FRIEND_SERIALIZATION__
# endif
#endif

//------------------------------------------------------------------------------
/// The difference between enumu.hpp and enumv.hpp is that UTXX_ENUMU
/// allows the enum to have specific enumerated unique constants, whereas
/// UTXX_ENUMV permits the use of non-unique constants. The enum name lookup by
/// value is faster for UTXX_ENUMU, since it uses a play array with lookup by
/// index, whereas UTXX_ENUMV uses a map, so ```enum X { A=1, B=2 }``` is
/// equivalent to ```UTXX_ENUMU(X, int, (A, 1)(B, 2))```, and name lookups are
/// implemented using:
///       ```
///          switch(val) {
///             case 1: return "A";
///             case 2: return "B";
///             ...
///          }
///       ```
/// `UTXX_ENUMU(EnumName, Opts, Enums)`
/// * EnumName - the name of ENUM
/// * Opts - can be one of three formats:
///     * Type                      - Enum of Type. Adds DEF_NAME=0.
///     * (Type,DefValue)           - Enum of Type. Adds DEF_NAME=DefValue.
///     * (Type,UndefName,DefValue) - Enum of Type. Adds UndefName=DefValue.
///     * (Type,UndefName,DefValue,FirstVal) - Ditto. Start enum with FirstVal.
/// * Enums is either a variadic list or sequence of arguments:
///     * Enum1, Enum2, ...
///     * (Enum1)(Enum2)...
///     where each `EnumN` can be given a Value associated with each EnumName,
///     and may optionally specify a symbolic value label:
///         * EnumName
///         * (EnumName,Value)              - EnumName's code()  = Value
///         * (EnumName,Value,"EnumValue")  - EnumName's value() = "EnumValue"
//------------------------------------------------------------------------------
/// NOTE: DefValue as well as values given to EnumName's must be distinct!
//------------------------------------------------------------------------------
/// Enum declaration:
/// ```
/// #include <utxx/enumu.hpp>
///
/// UTXX_ENUMU(MyEnumT,
///    (                    // This parameter is a tuple of up to four elements:
///     char,               //   This is enum storage type
///     NIL,                //   Name of the undefined type
///     ' ',                //   NIL's value
///     'a'                 //   Value assigned to the first item (Orange)
///    ),
///    (Orange)             // Orange's value will be set to 'a'
///    (Apple, 'x', "Fuji") // Item with a value and with name string "Fuji"
///    (Pear,  'y')         // Item with value 'y' (name defaults to "Pear")
/// // (Fig,   'y')         // NOTE: this would result in compile-time error!
///    (Grape)              // Grape's value will be equal to 'y'+1
/// );
///
/// Sample usage:
/// MyEnumT val = MyEnumT::from_string("Pear");
/// std::cout << "Value: " << to_string(val) << std::endl;
/// std::cout << "Value: " << val            << std::endl;
//------------------------------------------------------------------------------
#define UTXX_ENUMU(ENUM, TYPE, ...)                                            \
        UTXX_ENUMU__(                                                          \
            ENUM,                                                              \
            UTXX_ENUM_GET_TYPE(TYPE),                                          \
            UTXX_ENUM_GET_UNDEF_NAME(TYPE),                                    \
            UTXX_ENUM_GET_UNDEF_VAL(TYPE),                                     \
            UTXX_ENUM_GET_FIRST_VAL(TYPE),                                     \
            BOOST_PP_TUPLE_ENUM(                                               \
                BOOST_PP_IF(                                                   \
                    BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1),    \
                        BOOST_PP_IF(BOOST_PP_IS_BEGIN_PARENS(__VA_ARGS__),     \
                            (__VA_ARGS__),                                     \
                            ((__VA_ARGS__))),                                  \
                        (BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))))              \
        )

#define UTXX_ENUMU__(ENUM, TYPE, DEF_NAME, DEF_VAL, FIRST_VAL, ...)            \
    struct ENUM {                                                              \
        using value_type = TYPE;                                               \
                                                                               \
        enum type : TYPE {                                                     \
            DEF_NAME = (DEF_VAL),                                              \
            _START_  = FIRST_VAL-1,                                            \
            BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(                          \
                UTXX_ENUM_INTERNAL_GET_NAMEVAL__, _,                           \
                BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__)))                    \
        };                                                                     \
                                                                               \
        using meta_type  = std::tuple<type, std::string, std::string>;         \
                                                                               \
        explicit  ENUM(long v) noexcept : m_val(type(v))   {}                  \
        constexpr ENUM()       noexcept : m_val(DEF_NAME)  {}                  \
        constexpr ENUM(type v) noexcept : m_val(v)         {}                  \
                                                                               \
        ENUM(ENUM&&)                 = default;                                \
        ENUM(ENUM const&)            = default;                                \
                                                                               \
        ENUM& operator=(ENUM const&) = default;                                \
        ENUM& operator=(ENUM&&)      = default;                                \
                                                                               \
        static constexpr const char*   class_name() { return #ENUM;        }   \
        constexpr operator  type()     const { return m_val; }                 \
        constexpr bool      empty()    const { return m_val == DEF_NAME;   }   \
        void                clear()          { m_val =  DEF_NAME;          }   \
                                                                               \
        static    constexpr bool is_enum()   { return true;                }   \
        static    constexpr bool is_flags()  { return false;               }   \
                                                                               \
        const std::string& name()    const { return std::get<1>(meta(m_val));} \
        const std::string& value()   const { return std::get<2>(meta(m_val));} \
        TYPE               code()    const { return TYPE(m_val);           }   \
                                                                               \
        const std::string& to_string() const { return value();             }   \
        static const std::string&                                              \
                           to_string(type a) { return ENUM(a).to_string(); }   \
        const char*        c_str()     const { return to_string().c_str(); }   \
        static const char* c_str(type a)     { return to_string(a).c_str();}   \
                                                                               \
        /* Returns true if the given value is a valid value for this enum */   \
        static constexpr bool valid(TYPE v)  {                                 \
            if (v == DEF_NAME) return true;                                    \
            bool found = false;                                                \
            auto f = [&found, v](type t, auto&) {                              \
                if (t == v) { found = true; return false; }                    \
                return true;                                                   \
            };                                                                 \
            for_each(f);                                                       \
            return found;                                                      \
        }                                                                      \
                                                                               \
        static ENUM                                                            \
        from_string(const char* a, bool a_nocase=false, bool as_name=false)  { \
            auto f = a_nocase ? &strcasecmp : &strcmp;                         \
            for (auto& t : metas())                                            \
                if (!f((as_name ? std::get<1>(t) : std::get<2>(t)).c_str(),a)) \
                    return ENUM(std::get<0>(t));                               \
            return ENUM(DEF_NAME);                                             \
        }                                                                      \
                                                                               \
        static ENUM from_string(const std::string& a, bool a_nocase=false,     \
                                bool as_name=false)                            \
            { return from_string(a.c_str(), a_nocase, as_name); }              \
                                                                               \
        static ENUM from_string_nc(const std::string& a, bool as_name=false) { \
            return from_string(a, true, as_name);                              \
        }                                                                      \
        static ENUM from_string_nc(const char* a, bool as_name=false) {        \
            return from_string(a, true, as_name);                              \
        }                                                                      \
                                                                               \
        static ENUM from_name(const char* a, bool a_nocase=false) {            \
            return from_string(a, a_nocase, true);                             \
        }                                                                      \
        static ENUM from_value(const char* a, bool a_nocase=false) {           \
            return from_string(a, a_nocase, false);                            \
        }                                                                      \
                                                                               \
        template <typename StreamT>                                            \
        inline friend StreamT& operator<< (StreamT& out, ENUM const& a) {      \
            out << a.value();                                                  \
            return out;                                                        \
        }                                                                      \
                                                                               \
        template <typename StreamT>                                            \
        inline friend StreamT& operator<< (StreamT& out, ENUM::type a)  {      \
            return out << ENUM(a);                                             \
        }                                                                      \
                                                                               \
        static constexpr size_t size()  { return s_size-1; }                   \
                                                                               \
        template <typename Visitor>                                            \
        static void for_each(const Visitor& a_fun) {                           \
            int i=0;                                                           \
            for (auto& m : metas())                                            \
                if (i++ && !a_fun(std::get<0>(m), m))                          \
                    break;                                                     \
        }                                                                      \
                                                                               \
    private:                                                                   \
        static const meta_type& null_meta() {                                  \
            static const meta_type s_val =                                     \
                std::make_tuple(DEF_NAME, BOOST_PP_STRINGIZE(DEF_NAME),        \
                                          BOOST_PP_STRINGIZE(DEF_NAME));       \
            return s_val;                                                      \
        }                                                                      \
        static const size_t s_size =                                           \
            1+BOOST_PP_SEQ_SIZE(BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__));    \
        static const std::array<meta_type, s_size>& metas() {                  \
            static const std::array<meta_type, s_size> s_metas{{               \
                null_meta(),                                                   \
                BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(                      \
                    UTXX_INTERNAL_ENUMU_META_TUPLE__, _,                       \
                    BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__)))                \
            }};                                                                \
            return s_metas;                                                    \
        }                                                                      \
                                                                               \
        static const meta_type& meta(type n) {                                 \
            switch (n) {                                                       \
                case DEF_NAME: return metas()[0];                              \
                BOOST_PP_SEQ_FOR_EACH_I_R(1,                                   \
                    UTXX_INTERNAL_ENUMU_CASE__, _,                             \
                    BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__))                 \
                default:        return metas()[0];                             \
            }                                                                  \
        }                                                                      \
                                                                               \
        UTXX__ENUM_FRIEND_SERIALIZATION__;                                     \
                                                                               \
        type m_val;                                                            \
    }

#define UTXX_INTERNAL_ENUMU_META_TUPLE__(x, _, val)                            \
    std::make_tuple(                                                           \
        BOOST_PP_TUPLE_ELEM(0, val),                                           \
        BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, val)),                       \
        BOOST_PP_IIF(                                                          \
            BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(val), 2),                     \
            BOOST_PP_TUPLE_ELEM(2, BOOST_PP_TUPLE_PUSH_BACK(val,_)),           \
            BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, val))))

#define UTXX_INTERNAL_ENUMU_CASE__(x, _, i, item)                              \
            case BOOST_PP_TUPLE_ELEM(0, item): return metas()[BOOST_PP_INC(i)];
<|endoftext|>


<commit_before>#ifndef VISUALIZER_H
#define VISUALIZER_H
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <armadillo>
#include <string>
#include "colormaps.hpp"
#include "lowPassFilter.hpp"
#include "gaussianKernel.hpp"

namespace visa
{
/** Matrix visualizer using the SFML libray */
class Visualizer
{
public:
  Visualizer();
  ~Visualizer();

  /** Initialize the window handler */
  virtual void init( const char *windowName );

  /** Initialize the window handler */
  void init();

  /** Set values to visualize */
  void fillVertexArray( arma::mat &values );

  /** Set values to visualize */
  virtual void fillVertexArray( arma::vec &values ){};

  /** Checks if the window is still open */
  bool isOpen() const;

  /** Checks for events */
  bool pollEvent( sf::Event &event ) const;

  /** Close the window */
  void close(){ window->close(); };

  /** Dump image to screen */
  void display(){ window->display(); };

  /** Draw the vertex array */
  void draw();

  /** Fill the window with a black background color */
  void clear(){ window->clear(sf::Color::Black); };

  /** Set upper limit of the colorscale */
  void setColorMax( double max ){ colorMax = max; };

  /** Set the lower limit for the colorscale */
  void setColorMin( double min ){ colorMin = min; };

  /** Set both colorlimits (provided for convenience) */
  void setColorLim( double min, double max );

  /** Set color map */
  void setCmap( Colormaps::Colormap_t cm ){ cmaps.setMap(cm); };

  /** Sets the opacity */
  void setOpacity( double alpha );

  /** Down sample by simple averaging */
  static double average( const arma::mat &mat );

  /** Save current scene */
  sf::Image capture(){ return window->capture(); };

  /** Return the name of the plot */
  const std::string& getName() const { return name; };

  /** Set upper and lower y-limit. Only relevant for 1D plots */
  virtual void setLimits( double min, double max ){};
protected:
  sf::RenderWindow *window{NULL};
  sf::View *view{NULL};
  sf::VertexArray *vArray{NULL};
  sf::Texture *tx{NULL};
  visa::LowPassFilter filter;
  visa::GaussianKernel filterKernel;
  std::string name;
  sf::Image img;

  unsigned int width{640};
  unsigned int height{480};
  static const unsigned int defaultWidth{640};
  static const unsigned int defaultHeight{480};
  double colorMax{1.0};
  double colorMin{0.0};
  unsigned int vArrayNrow{0};
  unsigned int vArrayNcol{0};
  Colormaps cmaps;
  bool resizingEnabled{true};
  bool colorLimitsSetByUser{false};
  sf::Uint8 *pixels{NULL};
  sf::Uint8 alpha{0};

  /** Set color corresponding to value */
  void setColor( double value, sf::Color &color ) const;

  /** Run the matrix through the low pass filter */
  void filterMatrix( arma::mat &mat );

  /** Resize the window to match the matrix */
  void resizeWindow( unsigned int newWidth, unsigned int newHeight );

  /** Resize width */
  void resizeWidth( unsigned int newWidth );

  /** Resize height */
  void resizeHeight( unsigned int newHeight );

  /** Restores the default window height and width */
  void restoreDefaultWindowSize();

  /** Filter horizontally */
  void filterHorizontal( arma::mat &mat );

  /** Filter vertically */
  void filterVertical( arma::mat &mat );

  /** Set limits based on max and min value */
  void setMaxMinColors( arma::mat &mat );
};
}; // namespace
#endif
<commit_msg>Changes default value of alpha<commit_after>#ifndef VISUALIZER_H
#define VISUALIZER_H
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <armadillo>
#include <string>
#include "colormaps.hpp"
#include "lowPassFilter.hpp"
#include "gaussianKernel.hpp"

namespace visa
{
/** Matrix visualizer using the SFML libray */
class Visualizer
{
public:
  Visualizer();
  ~Visualizer();

  /** Initialize the window handler */
  virtual void init( const char *windowName );

  /** Initialize the window handler */
  void init();

  /** Set values to visualize */
  void fillVertexArray( arma::mat &values );

  /** Set values to visualize */
  virtual void fillVertexArray( arma::vec &values ){};

  /** Checks if the window is still open */
  bool isOpen() const;

  /** Checks for events */
  bool pollEvent( sf::Event &event ) const;

  /** Close the window */
  void close(){ window->close(); };

  /** Dump image to screen */
  void display(){ window->display(); };

  /** Draw the vertex array */
  void draw();

  /** Fill the window with a black background color */
  void clear(){ window->clear(sf::Color::Black); };

  /** Set upper limit of the colorscale */
  void setColorMax( double max ){ colorMax = max; };

  /** Set the lower limit for the colorscale */
  void setColorMin( double min ){ colorMin = min; };

  /** Set both colorlimits (provided for convenience) */
  void setColorLim( double min, double max );

  /** Set color map */
  void setCmap( Colormaps::Colormap_t cm ){ cmaps.setMap(cm); };

  /** Sets the opacity */
  void setOpacity( double alpha );

  /** Down sample by simple averaging */
  static double average( const arma::mat &mat );

  /** Save current scene */
  sf::Image capture(){ return window->capture(); };

  /** Return the name of the plot */
  const std::string& getName() const { return name; };

  /** Set upper and lower y-limit. Only relevant for 1D plots */
  virtual void setLimits( double min, double max ){};
protected:
  sf::RenderWindow *window{NULL};
  sf::View *view{NULL};
  sf::VertexArray *vArray{NULL};
  sf::Texture *tx{NULL};
  visa::LowPassFilter filter;
  visa::GaussianKernel filterKernel;
  std::string name;
  sf::Image img;

  unsigned int width{640};
  unsigned int height{480};
  static const unsigned int defaultWidth{640};
  static const unsigned int defaultHeight{480};
  double colorMax{1.0};
  double colorMin{0.0};
  unsigned int vArrayNrow{0};
  unsigned int vArrayNcol{0};
  Colormaps cmaps;
  bool resizingEnabled{true};
  bool colorLimitsSetByUser{false};
  sf::Uint8 *pixels{NULL};
  sf::Uint8 alpha{255};

  /** Set color corresponding to value */
  void setColor( double value, sf::Color &color ) const;

  /** Run the matrix through the low pass filter */
  void filterMatrix( arma::mat &mat );

  /** Resize the window to match the matrix */
  void resizeWindow( unsigned int newWidth, unsigned int newHeight );

  /** Resize width */
  void resizeWidth( unsigned int newWidth );

  /** Resize height */
  void resizeHeight( unsigned int newHeight );

  /** Restores the default window height and width */
  void restoreDefaultWindowSize();

  /** Filter horizontally */
  void filterHorizontal( arma::mat &mat );

  /** Filter vertically */
  void filterVertical( arma::mat &mat );

  /** Set limits based on max and min value */
  void setMaxMinColors( arma::mat &mat );
};
}; // namespace
#endif
<|endoftext|>


<commit_before>/**
 * C S O U N D   V S T
 *
 * A VST plugin version of Csound, with Python scripting.
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "CppSound.hpp"

extern "C"
{
  int PyRun_SimpleString(const char *string);
}

static void pythonMessageCallback(CSOUND *csound, int attr, const char *format, va_list valist)
{
  static char buffer[0x1000];
  static char buffer1[0x1000];
  vsprintf(buffer, format, valist);
  static std::string actualBuffer;
  static std::string lineBuffer;
  actualBuffer.append(buffer);
  size_t position = 0;
  while((position = actualBuffer.find("\n")) != std::string::npos)
    {
      lineBuffer = actualBuffer.substr(0, position);
      actualBuffer.erase(0, position + 1);
#ifndef MSVC
      actualBuffer.clear();
#endif
      sprintf(buffer1, "print '''%s'''", lineBuffer.c_str());
      PyRun_SimpleString(buffer1);
    }
}

void CppSound::setPythonMessageCallback()
{
  SetMessageCallback(pythonMessageCallback);
}

<commit_msg>Attempt to fix ' and \ in messages<commit_after>/**
 * C S O U N D   V S T
 *
 * A VST plugin version of Csound, with Python scripting.
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software 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 software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "CppSound.hpp"

extern "C"
{
  int PyRun_SimpleString(const char *string);
}

static void pythonMessageCallback(CSOUND *csound,
                                  int attr, const char *format, va_list valist)
{
  char          buffer[8192];
  static std::string  lineBuffer = "print '''";     // FIXME
  unsigned int  i, len;
#ifdef HAVE_C99
  len = (unsigned int) vsnprintf(&(buffer[0]), (size_t) 8192, format, valist);
  if (len >= 8192U)
    {
      PyRun_SimpleString("print '''Error: message buffer overflow'''");
      return;
    }
#else
  len = (unsigned int) vsprintf(&(buffer[0]), format, valist);
  if (len >= 8192U)
    {
      PyRun_SimpleString("print '''Error: message buffer overflow'''");
      exit(-1);
    }
#endif
  for (i = 0; i < len; i++) {
    if (buffer[i] == '\n') {
      lineBuffer += "'''";
      PyRun_SimpleString(lineBuffer.c_str());
      lineBuffer = "print '''";
      continue;
    }
    if (buffer[i] == '\'' || buffer[i] == '\\')
      lineBuffer += '\\';
    lineBuffer += buffer[i];
  }
}

void CppSound::setPythonMessageCallback()
{
  SetMessageCallback(pythonMessageCallback);
}

<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <utility>

#define PAM_SM_AUTH
#include <security/pam_modules.h>
#include <security/pam_ext.h>

#define LDAP_DEPRECATED 1
#include <ldap.h>

typedef std::map<std::string, std::string> ArgMap;

static int ldap_to_pam_rc(int ldap_rc)
{
    switch (ldap_rc) {
    case LDAP_SUCCESS:
        /* everything was fine */
        return PAM_SUCCESS;
    case LDAP_UNAVAILABLE:
    case LDAP_TIMELIMIT_EXCEEDED:
    case LDAP_OPERATIONS_ERROR:
    case LDAP_BUSY:
    case LDAP_LOOP_DETECT:
    case LDAP_SERVER_DOWN:
    case LDAP_TIMEOUT:
    case LDAP_CONNECT_ERROR:
    case LDAP_NO_RESULTS_RETURNED:
        /* cannot access LDAP correctly */
        return PAM_AUTHINFO_UNAVAIL;
    }

    /* something else went wrong */
    return PAM_AUTH_ERR;
}

static int verify(const char* host,
                  const char* binddn,
                  const char* pw)
{
    LDAP* ld;
    int ldap_rc, pam_rc;

    ldap_rc = ldap_initialize(&ld, host);
    pam_rc = ldap_to_pam_rc(ldap_rc);
    if (pam_rc != PAM_SUCCESS)
        return pam_rc;

    ldap_rc = ldap_simple_bind_s(ld, binddn, pw);
    return ldap_to_pam_rc(ldap_rc);
}

static ArgMap get_args(int argc,
                       const char** argv)
{
    ArgMap arguments;

    for (int i = 0; i < argc; i++) {
        std::string arg(argv[i]);
        std::string::size_type pos = arg.find("=");
        if (pos != std::string::npos) {
            std::string key = arg.substr(0, pos);
            std::string value = "";

            if (arg.length() > pos+1) {
                value = arg.substr(pos+1);
            }

            arguments.insert(std::make_pair(key, value));
        }
    }

    return arguments;
}

static void replace_all(std::string& s,
                        const std::string& search_s,
                        const std::string& replace_s)
{
    std::string::size_type last_pos = 0;
    while ((last_pos = s.find(search_s, last_pos)) != std::string::npos) {
        s.replace(last_pos, search_s.length(), replace_s);
    }
}

PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh,
                                   int /* flags */,
                                   int argc,
                                   const char** argv)
{
    const char* user;
    const char* pass;
    ArgMap arguments = get_args(argc, argv);

    if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }
    if (pam_get_authtok(pamh, PAM_AUTHTOK, &pass, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }

    // ensure uri and binddn PAM parameters were specified
    if (arguments.find("uri") == arguments.end() ||
        arguments.find("binddn") == arguments.end()) {
        return PAM_AUTH_ERR;
    }

    std::string binddn = arguments["binddn"];
    replace_all(binddn, "%s", user);

    // check against ldap database
    return verify(arguments["uri"].c_str(), binddn.c_str(), pass);
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t* /* pamh */,
                              int /* flags */,
                              int /* argc */,
                              const char** /* argv */)
{
    return PAM_SUCCESS;
}
<commit_msg>fix return values for pam_get_user & pam_get_authtok<commit_after>#include <map>
#include <string>
#include <utility>

#define PAM_SM_AUTH
#include <security/pam_modules.h>
#include <security/pam_ext.h>

#define LDAP_DEPRECATED 1
#include <ldap.h>

typedef std::map<std::string, std::string> ArgMap;

static int ldap_to_pam_rc(int ldap_rc)
{
    switch (ldap_rc) {
    case LDAP_SUCCESS:
        /* everything was fine */
        return PAM_SUCCESS;
    case LDAP_UNAVAILABLE:
    case LDAP_TIMELIMIT_EXCEEDED:
    case LDAP_OPERATIONS_ERROR:
    case LDAP_BUSY:
    case LDAP_LOOP_DETECT:
    case LDAP_SERVER_DOWN:
    case LDAP_TIMEOUT:
    case LDAP_CONNECT_ERROR:
    case LDAP_NO_RESULTS_RETURNED:
        /* cannot access LDAP correctly */
        return PAM_AUTHINFO_UNAVAIL;
    }

    /* something else went wrong */
    return PAM_AUTH_ERR;
}

static int verify(const char* host,
                  const char* binddn,
                  const char* pw)
{
    LDAP* ld;
    int ldap_rc, pam_rc;

    ldap_rc = ldap_initialize(&ld, host);
    pam_rc = ldap_to_pam_rc(ldap_rc);
    if (pam_rc != PAM_SUCCESS)
        return pam_rc;

    ldap_rc = ldap_simple_bind_s(ld, binddn, pw);
    return ldap_to_pam_rc(ldap_rc);
}

static ArgMap get_args(int argc,
                       const char** argv)
{
    ArgMap arguments;

    for (int i = 0; i < argc; i++) {
        std::string arg(argv[i]);
        std::string::size_type pos = arg.find("=");
        if (pos != std::string::npos) {
            std::string key = arg.substr(0, pos);
            std::string value = "";

            if (arg.length() > pos+1) {
                value = arg.substr(pos+1);
            }

            arguments.insert(std::make_pair(key, value));
        }
    }

    return arguments;
}

static void replace_all(std::string& s,
                        const std::string& search_s,
                        const std::string& replace_s)
{
    std::string::size_type last_pos = 0;
    while ((last_pos = s.find(search_s, last_pos)) != std::string::npos) {
        s.replace(last_pos, search_s.length(), replace_s);
    }
}

PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh,
                                   int /* flags */,
                                   int argc,
                                   const char** argv)
{
    const char* user;
    const char* pass;
    int ret;
    ArgMap arguments = get_args(argc, argv);

    ret = pam_get_user(pamh, &user, NULL);
    if (ret != PAM_SUCCESS) {
        return ret;
    }

    ret = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, NULL);
    if (ret != PAM_SUCCESS) {
        return ret;
    }

    // ensure uri and binddn PAM parameters were specified
    if (arguments.find("uri") == arguments.end() ||
        arguments.find("binddn") == arguments.end()) {
        return PAM_AUTH_ERR;
    }

    std::string binddn = arguments["binddn"];
    replace_all(binddn, "%s", user);

    // check against ldap database
    return verify(arguments["uri"].c_str(), binddn.c_str(), pass);
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t* /* pamh */,
                              int /* flags */,
                              int /* argc */,
                              const char** /* argv */)
{
    return PAM_SUCCESS;
}
<|endoftext|>


<commit_before>/// \file TFile.cxx
/// \ingroup Base ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-31
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOT/TFile.h"
#include "TFile.h"

#include <mutex>

ROOT::Experimental::TDirectory& ROOT::Experimental::TDirectory::Heap() {
  static TDirectory heapDir;
  return heapDir;
}

namespace {
/// We cannot afford users not closing their files. Yes, we return a unique_ptr -
/// but that might be stored in an object that itself leaks. That would leave
/// the TFile unclosed and data corrupted / not written. Instead, keep a
/// collection of all opened writable TFiles and close them at destruction time,
/// explicitly.
static void AddFilesToClose(std::weak_ptr<ROOT::Experimental::Internal::TFileImplBase> pFile) {
  struct CloseFiles_t {
    std::vector<std::weak_ptr<ROOT::Experimental::Internal::TFileImplBase>> fFiles;
    std::mutex fMutex;
    ~CloseFiles_t() {
      for (auto& wFile: fFiles) {
        if (auto sFile = wFile.lock()) {
          sFile->Flush(); // or Close()? but what if there's still a Write()?
        }
      }
    }
  };
  static CloseFiles_t closer;

  std::lock_guard<std::mutex> lock(closer.fMutex);
  closer.fFiles.emplace_back(pFile);
}

/** \class TFSFile
 TFileImplBase for a file-system (POSIX) style TFile.
 */
class TFileSystemFile: public ROOT::Experimental::Internal::TFileImplBase {
  ::TFile* fOldFile;

public:
  TFileSystemFile(const std::string& name, const char* mode):
    fOldFile(::TFile::Open(name.c_str(), mode)) {
  }

  void Flush() final { fOldFile->Flush(); }

  void Close() final { fOldFile->Close(); }

  ~TFileSystemFile() {
    delete fOldFile;
  }
};
}

ROOT::Experimental::TFilePtr::TFilePtr(std::unique_ptr<ROOT::Experimental::Internal::TFileImplBase>&& impl):
fImpl(std::move(impl))
{
  AddFilesToClose(fImpl);
}

ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::OpenForRead(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "READ"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::Create(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "CREATE"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::Recreate(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "RECREATE"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::OpenForUpdate(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "UPDATE"));
}
<commit_msg>Fix \file to match doxygen expectation.<commit_after>/// \file v7/src/TFile.cxx
/// \ingroup Base ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-31
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOT/TFile.h"
#include "TFile.h"

#include <mutex>

ROOT::Experimental::TDirectory& ROOT::Experimental::TDirectory::Heap() {
  static TDirectory heapDir;
  return heapDir;
}

namespace {
/// We cannot afford users not closing their files. Yes, we return a unique_ptr -
/// but that might be stored in an object that itself leaks. That would leave
/// the TFile unclosed and data corrupted / not written. Instead, keep a
/// collection of all opened writable TFiles and close them at destruction time,
/// explicitly.
static void AddFilesToClose(std::weak_ptr<ROOT::Experimental::Internal::TFileImplBase> pFile) {
  struct CloseFiles_t {
    std::vector<std::weak_ptr<ROOT::Experimental::Internal::TFileImplBase>> fFiles;
    std::mutex fMutex;
    ~CloseFiles_t() {
      for (auto& wFile: fFiles) {
        if (auto sFile = wFile.lock()) {
          sFile->Flush(); // or Close()? but what if there's still a Write()?
        }
      }
    }
  };
  static CloseFiles_t closer;

  std::lock_guard<std::mutex> lock(closer.fMutex);
  closer.fFiles.emplace_back(pFile);
}

/** \class TFSFile
 TFileImplBase for a file-system (POSIX) style TFile.
 */
class TFileSystemFile: public ROOT::Experimental::Internal::TFileImplBase {
  ::TFile* fOldFile;

public:
  TFileSystemFile(const std::string& name, const char* mode):
    fOldFile(::TFile::Open(name.c_str(), mode)) {
  }

  void Flush() final { fOldFile->Flush(); }

  void Close() final { fOldFile->Close(); }

  ~TFileSystemFile() {
    delete fOldFile;
  }
};
}

ROOT::Experimental::TFilePtr::TFilePtr(std::unique_ptr<ROOT::Experimental::Internal::TFileImplBase>&& impl):
fImpl(std::move(impl))
{
  AddFilesToClose(fImpl);
}

ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::OpenForRead(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "READ"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::Create(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "CREATE"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::Recreate(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "RECREATE"));
}
ROOT::Experimental::TFilePtr ROOT::Experimental::TFilePtr::OpenForUpdate(std::string_view name) {
  // will become delegation to TFileSystemFile, TWebFile etc.
  return TFilePtr(std::make_unique<TFileSystemFile>(name.to_string(), "UPDATE"));
}
<|endoftext|>


<commit_before>

/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include "pcl/impl/instantiate.hpp"
#include "pcl/point_types.h"

#include "pcl/octree/octree.h"
#include "pcl/octree/octree_impl.h"

#include "pcl/compression/entropy_range_coder.h"
#include "pcl/compression/impl/entropy_range_coder.hpp"

#include "pcl/compression/octree_pointcloud_compression.h"
#include "pcl/compression/impl/octree_pointcloud_compression.hpp"

template class pcl::octree::OctreePointCloudCompression<pcl::PointXYZRGB>;

<commit_msg>removed unused includes<commit_after>

/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include "pcl/impl/instantiate.hpp"
#include "pcl/point_types.h"

#include "pcl/octree/octree.h"
#include "pcl/octree/octree_impl.h"

#include "pcl/compression/entropy_range_coder.h"
#include "pcl/compression/impl/entropy_range_coder.hpp"

//#include "pcl/compression/octree_pointcloud_compression.h"
//#include "pcl/compression/impl/octree_pointcloud_compression.hpp"

//template class pcl::octree::OctreePointCloudCompression<pcl::PointXYZRGB>;

<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
#ifndef DTK_DETAILS_PRIORITY_QUEUE_HPP
#define DTK_DETAILS_PRIORITY_QUEUE_HPP

#include <Kokkos_Macros.hpp>

#include <cassert>
#include <cstdlib>
#include <utility>

namespace DataTransferKit
{
namespace Details
{

template <typename T>
struct Less
{
  public:
    KOKKOS_INLINE_FUNCTION bool operator()( T const &x, T const &y )
    {
        return x < y;
    }
};

template <typename T, typename Compare = Less<T>>
class PriorityQueue
{
  public:
    using SizeType = size_t;

    KOKKOS_FUNCTION PriorityQueue() = default;

    KOKKOS_INLINE_FUNCTION bool empty() const { return _size == 0; }

    template <typename... Args>
    KOKKOS_INLINE_FUNCTION void push( Args &&... args )
    {
        // ensure the heap is not already full
        assert( _size < _max_size );

        // add the element to the bottom level of the heap
        SizeType pos = _size;
        T elem{std::forward<Args>( args )...};

        // perform up-heap operation
        while ( pos > 0 )
        {
            // compare the added element with its parent
            // if they are in correct order, stop
            // if not, swap them and continue
            SizeType const parent = ( pos - 1 ) / 2;
            if ( !_compare( _heap[parent], elem ) )
                break;
            _heap[pos] = _heap[parent];
            pos = parent;
        }

        _heap[pos] = elem;

        // update the size of the heap
        ++_size;
    }

    KOKKOS_INLINE_FUNCTION void pop()
    {
        // ensure that the heap is not empty
        assert( _size > 0 );

        // replace the root with the last element on the last level
        SizeType pos = 0;

        // perform down-heap operation
        while ( true )
        {
            // compare the new root with its children
            // if they are in the correct order, stop
            // if not, swap the element with one of its children and continue
            SizeType const left_child = 2 * pos + 1;
            SizeType const right_child = 2 * pos + 2;
            SizeType next_pos = _size - 1;
            for ( SizeType child : {left_child, right_child} )
                if ( child < _size - 1 &&
                     _compare( _heap[next_pos], _heap[child] ) )
                    next_pos = child;
            if ( next_pos == _size - 1 )
                break;
            _heap[pos] = _heap[next_pos];
            pos = next_pos;
        }

        _heap[pos] = _heap[_size - 1];

        // update the size of the heap
        _size--;
    }

    KOKKOS_INLINE_FUNCTION T const &top() const
    {
        assert( _size > 0 );
        return _heap[0];
    }

  private:
    static SizeType constexpr _max_size = 256;
    T _heap[_max_size];
    SizeType _size = 0;
    Compare _compare;
};

} // namespace Details
} // namespace DataTransferKit

#endif
<commit_msg>Add ValueType alias and size() to PriorityQueue<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
#ifndef DTK_DETAILS_PRIORITY_QUEUE_HPP
#define DTK_DETAILS_PRIORITY_QUEUE_HPP

#include <Kokkos_Macros.hpp>

#include <cassert>
#include <cstdlib>
#include <utility>

namespace DataTransferKit
{
namespace Details
{

template <typename T>
struct Less
{
  public:
    KOKKOS_INLINE_FUNCTION bool operator()( T const &x, T const &y )
    {
        return x < y;
    }
};

template <typename T, typename Compare = Less<T>>
class PriorityQueue
{
  public:
    using SizeType = size_t;
    using ValueType = T;

    KOKKOS_FUNCTION PriorityQueue() = default;

    KOKKOS_INLINE_FUNCTION bool empty() const { return _size == 0; }

    KOKKOS_INLINE_FUNCTION IndexType size() const { return _size; }

    template <typename... Args>
    KOKKOS_INLINE_FUNCTION void push( Args &&... args )
    {
        // ensure the heap is not already full
        assert( _size < _max_size );

        // add the element to the bottom level of the heap
        SizeType pos = _size;
        T elem{std::forward<Args>( args )...};

        // perform up-heap operation
        while ( pos > 0 )
        {
            // compare the added element with its parent
            // if they are in correct order, stop
            // if not, swap them and continue
            SizeType const parent = ( pos - 1 ) / 2;
            if ( !_compare( _heap[parent], elem ) )
                break;
            _heap[pos] = _heap[parent];
            pos = parent;
        }

        _heap[pos] = elem;

        // update the size of the heap
        ++_size;
    }

    KOKKOS_INLINE_FUNCTION void pop()
    {
        // ensure that the heap is not empty
        assert( _size > 0 );

        // replace the root with the last element on the last level
        SizeType pos = 0;

        // perform down-heap operation
        while ( true )
        {
            // compare the new root with its children
            // if they are in the correct order, stop
            // if not, swap the element with one of its children and continue
            SizeType const left_child = 2 * pos + 1;
            SizeType const right_child = 2 * pos + 2;
            SizeType next_pos = _size - 1;
            for ( SizeType child : {left_child, right_child} )
                if ( child < _size - 1 &&
                     _compare( _heap[next_pos], _heap[child] ) )
                    next_pos = child;
            if ( next_pos == _size - 1 )
                break;
            _heap[pos] = _heap[next_pos];
            pos = next_pos;
        }

        _heap[pos] = _heap[_size - 1];

        // update the size of the heap
        _size--;
    }

    KOKKOS_INLINE_FUNCTION T const &top() const
    {
        assert( _size > 0 );
        return _heap[0];
    }

  private:
    static SizeType constexpr _max_size = 256;
    T _heap[_max_size];
    SizeType _size = 0;
    Compare _compare;
};

} // namespace Details
} // namespace DataTransferKit

#endif
<|endoftext|>


<commit_before>#include "common.h"
#include "resource_stream.h"
#include "../res/resources.h"

#include "iolib/file_stream.h"
#include "iolib/string_view.h"

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

using namespace std;
using namespace iolib;

struct section_header_t
{
	char name[8];
	uint32_t virtual_size;
	uint32_t virtual_address;
	uint32_t raw_data_size;
	uint32_t raw_data_offset;
	uint32_t relocations_offset;
	uint32_t line_numbers_offset;
	uint16_t relocation_count;
	uint16_t line_number_count;
	uint32_t characteristics;
};

struct import_entry_t
{
	uint32_t lookup_virtual_address;
	uint32_t timestamp;
	uint32_t forwarder_chain;
	uint32_t dllname_virtual_address;
	uint32_t import_table_virtual_address;
};

static bool patch_image(seekable_stream& file_data);
static bool apply_dif(seekable_stream& file_data);

static string read_line(seekable_input_stream& is);

static const import_entry_t import_entry_null = { };

static const char PESignature[] = { 'P', 'E', '\0', '\0' };
static const uint16_t OptionalHeader_PE32Signature = 0x10B;
static const uint16_t OptionalHeader_PE32PlusSignature = 0x20B;

int wmain(int argc, wchar_t* argv[])
{
#if _DEBUG
	at_scope_exit([&]{ system("pause"); });
#endif

	const wchar_t* input_path = nullptr;
	const wchar_t* output_path = nullptr;
	bool headers_only = false;

	for (const wchar_t* const* arg = argv + 1; *arg != nullptr; ++arg)
	{
		switch (**arg)
		{
		case L'\0':
			continue;

		case L'-':
		case L'/':
			if (wcscmp(*arg + 1, L"headers-only") == 0)
				headers_only = true;
			break;

		default:
			if (input_path == nullptr)
				input_path = *arg;
			else if (output_path == nullptr)
				output_path = *arg;
			else
			{
				wcout << L"Usage:\n\t" << argv[0] << L" <input_path> <output_path>" << endl;
				return EXIT_FAILURE;
			}
		}
	}

	try
	{
		// Read the input file into an in-memory buffer.
		vector<uint8_t> file_buffer;
		{
			file input_file(input_path, file::mode::open | file::mode::read);
			input_file.seek(0, file::seek_from::end);
			size_t size = size_t(input_file.position());
			file_buffer.resize(size);
			input_file.seek(0, file::seek_from::beginning);
			input_file.read(file_buffer.data(), file_buffer.size());
		}

		// iolib streams are very good for reading and writing heterogeneous data.
		memory_stream file_data(file_buffer.data(), file_buffer.size());

		if (!patch_image(file_data))
			return EXIT_FAILURE;

		if (!headers_only && !apply_dif(file_data))
			return EXIT_FAILURE;

		file output_file(output_path, file::mode::open_or_create | file::mode::write);
		output_file.write(file_buffer.data(), file_buffer.size());
		return EXIT_SUCCESS;
	}
	catch (...)
	{
	}

	return EXIT_FAILURE;
}

bool patch_image(seekable_stream& file_data)
{
	// Read offset of PE header
	file_data.seek(0x3C);
	uint32_t offset;
	file_data.read(offset);

	// Read PE signature
	file_data.seek(offset, seekable_stream::seek_from::beginning);
	char signature[4];
	file_data.read(signature);
	if (!equal(begin(signature), end(signature), begin(PESignature)))
	{
		wcerr << L"Error: Input file is not a valid executable." << endl;
		return false;
	}

	// Read number of sections
	file_data.seek(2);
	uint16_t section_count;
	file_data.read(section_count);

	// Read optional header size
	file_data.seek(12);
	uint16_t header_size;
	file_data.read(header_size);

	// Set the IMAGE_FILE_RELOCS_STRIPPED flag
	uint16_t flags;
	file_data.read(flags);
	file_data.seek(-2);
	file_data.write(uint16_t(flags | 1));

	uint16_t pe_type_signature;
	file_data.read(pe_type_signature);
	if (pe_type_signature != OptionalHeader_PE32Signature && pe_type_signature != OptionalHeader_PE32PlusSignature)
	{
		wcerr << L"Error: Input file is not a valid executable." << endl;
		return false;
	}

	// Set the minimum OS fields to Windows XP
	file_data.seek(38);
	file_data.write(uint16_t(5));
	file_data.write(uint16_t(1));
	file_data.seek(4);
	file_data.write(uint16_t(5));
	file_data.write(uint16_t(1));

	// Skip to the data directories and clear out the relocation table entry.
	file_data.seek(40);
	uint32_t count;
	file_data.read(count);
	if (count >= 6)
	{
		file_data.seek(5 * 8);
		file_data.write(uint32_t(0));	// relocation data offset
		file_data.write(uint32_t(0));	// relocation data size

		// Skip to the section tables.
		file_data.seek(header_size - 96 - (6 * 8));	// seek past the optional header
	}
	else
		file_data.seek(header_size - 96);	// Skip to the section tables.

	section_header_t section_header;
	for (unsigned section_header_index = 0; section_header_index < section_count; ++section_header_index)
	{
		file_data.read(section_header);
		if (strcmp(section_header.name, ".idata") == 0)
			break;
	}

	// Skip to the import tables.
	file_data.seek(section_header.raw_data_offset, file::seek_from::beginning);

	// The import tables specify RVAs for import entries, so we'll need the base
	// address of the section in order to locate the imports in the input file.
	uint32_t idata_base_rva = section_header.virtual_address;

	// Skip past the directory tables.
	import_entry_t import_entry;
	while (true)
	{
		file_data.read(import_entry);
		if (memcmp(&import_entry, &import_entry_null, sizeof(import_entry_t)) == 0)
			return false;

		auto import_entry_position = file_data.position();
		file_data.seek(section_header.raw_data_offset + import_entry.dllname_virtual_address - idata_base_rva, file::seek_from::beginning);
		auto import_name_position = file_data.position();
		string dll_name;
		char ch;
		while ((file_data.read(ch), ch) != '\0')
			dll_name += ch;
		if (_stricmp(dll_name.c_str(), "ddraw.dll") == 0)
		{
			file_data.set_position(import_name_position);
			const char import_name[] = "wcdx.dll";
			file_data.write(import_name, lengthof(import_name));
			break;
		}

		file_data.set_position(import_entry_position);
	}

	file_data.seek(section_header.raw_data_offset + import_entry.lookup_virtual_address - idata_base_rva, file::seek_from::beginning);
	if (pe_type_signature != OptionalHeader_PE32Signature)
		return false;

	uint32_t lookup;
	memory_stream::position_type lookup_position;
	while (true)
	{
		if (!file_data.read(lookup) || lookup == 0)
			return false;

		if ((lookup & 0x80000000) == 0)
		{
			lookup_position = file_data.position();
			file_data.seek(section_header.raw_data_offset + lookup - idata_base_rva + 2, file::seek_from::beginning);
			auto name_position = file_data.position();

			string name;
			char ch;
			while ((file_data.read(ch), ch) != '\0')
				name += ch;
			if (name == "DirectDrawCreate")
			{
				file_data.set_position(name_position);
				file_data.seek(-2);
				break;
			}
			file_data.set_position(lookup_position);
		}
	}

	file_data.write(uint16_t(0));
	string_view function_name = "WcdxCreate";
	file_data.write(function_name.data(), function_name.length() * sizeof(char));
	file_data.write('\0');

	file_data.set_position(lookup_position);
	file_data.write(0);
	return true;
}

bool apply_dif(seekable_stream& file_data)
{
	resource_stream resource(RESOURCE_ID_WING1_DIFF);
	string line = read_line(resource);
	if (line != "This difference file has been created by IDA Pro")
		return false;

	while (!resource.at_end())
	{
		line = read_line(resource);
		if (line.empty())
			continue;
		if (line == "Wing1.exe")
			continue;

		auto n = line.find(':');
		if (n == string::npos)
			return false;
		string_view address_str(line, 0, n);

		n = line.find_first_not_of(' ', n + 1);
		if (n == string::npos)
			return false;
		auto m = line.find(' ', n);
		if (n == string::npos)
			return false;
		string_view original_value_str(line, n, m - n);

		n = line.find_first_not_of(' ', m + 1);
		if (n == string::npos)
			return false;
		m = line.find(' ', n);
		if (m == string::npos)
			m = line.length();
		string_view replacement_value_str(line, n, m - n);

		if (line.find_first_not_of(' ', m + 1) != string::npos)
			return false;

		if (original_value_str == "FFFFFFFF")
			continue;

		uint32_t offset = stoul(address_str, nullptr, 16);
		uint8_t original_value = uint8_t(stoul(original_value_str, nullptr, 16));
		uint8_t replacement_value = uint8_t(stoul(replacement_value_str, nullptr, 16));

		file_data.seek(offset, seekable_stream::seek_from::beginning);
		uint8_t value;
		if (!file_data.read(value) || value != original_value)
			return false;
		file_data.seek(-1);
		file_data.write(replacement_value);
	}

	return true;
}

string read_line(seekable_input_stream& is)
{
	auto position = is.position();
	size_t length = 0;
	char ch;
	while (is.read(ch) && (ch != '\r') && (ch != '\n'))
		++length;
	is.set_position(position);

	string line;
	line.reserve(length);
	while (is.read(ch) && (ch != '\r') && (ch != '\n'))
		line += ch;

	if ((ch == '\r') && is.read(ch) && (ch != '\n'))
		is.seek(-1);

	return line;
}
<commit_msg>Set the NX-compatible bit for patched executables. If something goes wrong while patching, print it out.<commit_after>#include "common.h"
#include "resource_stream.h"
#include "../res/resources.h"

#include "iolib/file_stream.h"
#include "iolib/string_view.h"

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

using namespace std;
using namespace iolib;

struct section_header_t
{
	char name[8];
	uint32_t virtual_size;
	uint32_t virtual_address;
	uint32_t raw_data_size;
	uint32_t raw_data_offset;
	uint32_t relocations_offset;
	uint32_t line_numbers_offset;
	uint16_t relocation_count;
	uint16_t line_number_count;
	uint32_t characteristics;
};

struct import_entry_t
{
	uint32_t lookup_virtual_address;
	uint32_t timestamp;
	uint32_t forwarder_chain;
	uint32_t dllname_virtual_address;
	uint32_t import_table_virtual_address;
};

static bool patch_image(seekable_stream& file_data);
static bool apply_dif(seekable_stream& file_data);

static string read_line(seekable_input_stream& is);

static const import_entry_t import_entry_null = { };

static const char PESignature[] = { 'P', 'E', '\0', '\0' };
static const uint16_t OptionalHeader_PE32Signature = 0x10B;
static const uint16_t OptionalHeader_PE32PlusSignature = 0x20B;

int wmain(int argc, wchar_t* argv[])
{
#if _DEBUG
	at_scope_exit([&]{ system("pause"); });
#endif

	const wchar_t* input_path = nullptr;
	const wchar_t* output_path = nullptr;
	bool headers_only = false;

	for (const wchar_t* const* arg = argv + 1; *arg != nullptr; ++arg)
	{
		switch (**arg)
		{
		case L'\0':
			continue;

		case L'-':
		case L'/':
			if (wcscmp(*arg + 1, L"headers-only") == 0)
				headers_only = true;
			break;

		default:
			if (input_path == nullptr)
				input_path = *arg;
			else if (output_path == nullptr)
				output_path = *arg;
			else
			{
				wcout << L"Usage:\n\t" << argv[0] << L" <input_path> <output_path>" << endl;
				return EXIT_FAILURE;
			}
		}
	}

	try
	{
		// Read the input file into an in-memory buffer.
		vector<uint8_t> file_buffer;
		{
			file input_file(input_path, file::mode::open | file::mode::read);
			input_file.seek(0, file::seek_from::end);
			size_t size = size_t(input_file.position());
			file_buffer.resize(size);
			input_file.seek(0, file::seek_from::beginning);
			input_file.read(file_buffer.data(), file_buffer.size());
		}

		// iolib streams are very good for reading and writing heterogeneous data.
		memory_stream file_data(file_buffer.data(), file_buffer.size());

		if (!patch_image(file_data))
			return EXIT_FAILURE;

		if (!headers_only && !apply_dif(file_data))
			return EXIT_FAILURE;

		file output_file(output_path, file::mode::open_or_create | file::mode::write);
		output_file.write(file_buffer.data(), file_buffer.size());
		return EXIT_SUCCESS;
	}
	catch (const exception& e)
	{
		cerr << e.what() << endl;
	}
	catch (...)
	{
	}

	return EXIT_FAILURE;
}

bool patch_image(seekable_stream& file_data)
{
	// Read offset of PE header
	file_data.seek(0x3C);
	uint32_t offset;
	file_data.read(offset);

	// Read PE signature
	file_data.seek(offset, seekable_stream::seek_from::beginning);
	char signature[4];
	file_data.read(signature);
	if (!equal(begin(signature), end(signature), begin(PESignature)))
	{
		wcerr << L"Error: Input file is not a valid executable." << endl;
		return false;
	}

	// Read number of sections
	file_data.seek(2);
	uint16_t section_count;
	file_data.read(section_count);

	// Read optional header size
	file_data.seek(12);
	uint16_t header_size;
	file_data.read(header_size);

	// Set the IMAGE_FILE_RELOCS_STRIPPED flag
	uint16_t flags;
	file_data.read(flags);
	file_data.seek(-2);
	file_data.write(uint16_t(flags | 1));

	uint16_t pe_type_signature;
	file_data.read(pe_type_signature);
	if (pe_type_signature != OptionalHeader_PE32Signature && pe_type_signature != OptionalHeader_PE32PlusSignature)
	{
		wcerr << L"Error: Input file is not a valid executable." << endl;
		return false;
	}

	// Set the minimum OS fields to Windows XP
	file_data.seek(38);
	file_data.write(uint16_t(5));
	file_data.write(uint16_t(1));
	file_data.seek(4);
	file_data.write(uint16_t(5));
	file_data.write(uint16_t(1));

	// Set the NX-compatible bit
	file_data.seek(18);
	file_data.read(flags);
	flags |= 0x0100;
	file_data.seek(-2);
	file_data.write(flags);

	// Skip to the data directories and clear out the relocation table entry.
	file_data.seek(20);
	uint32_t count;
	file_data.read(count);
	if (count >= 6)
	{
		file_data.seek(5 * 8);
		file_data.write(uint32_t(0));	// relocation data offset
		file_data.write(uint32_t(0));	// relocation data size

		// Skip to the section tables.
		file_data.seek(header_size - 96 - (6 * 8));	// seek past the optional header
	}
	else
		file_data.seek(header_size - 96);	// Skip to the section tables.

	section_header_t section_header;
	for (unsigned section_header_index = 0; section_header_index < section_count; ++section_header_index)
	{
		file_data.read(section_header);
		if (strcmp(section_header.name, ".idata") == 0)
			break;
	}

	// Skip to the import tables.
	file_data.seek(section_header.raw_data_offset, file::seek_from::beginning);

	// The import tables specify RVAs for import entries, so we'll need the base
	// address of the section in order to locate the imports in the input file.
	uint32_t idata_base_rva = section_header.virtual_address;

	// Skip past the directory tables.
	import_entry_t import_entry;
	while (true)
	{
		file_data.read(import_entry);
		if (memcmp(&import_entry, &import_entry_null, sizeof(import_entry_t)) == 0)
			return false;

		auto import_entry_position = file_data.position();
		file_data.seek(section_header.raw_data_offset + import_entry.dllname_virtual_address - idata_base_rva, file::seek_from::beginning);
		auto import_name_position = file_data.position();
		string dll_name;
		char ch;
		while ((file_data.read(ch), ch) != '\0')
			dll_name += ch;
		if (_stricmp(dll_name.c_str(), "ddraw.dll") == 0)
		{
			file_data.set_position(import_name_position);
			const char import_name[] = "wcdx.dll";
			file_data.write(import_name, lengthof(import_name));
			break;
		}

		file_data.set_position(import_entry_position);
	}

	file_data.seek(section_header.raw_data_offset + import_entry.lookup_virtual_address - idata_base_rva, file::seek_from::beginning);
	if (pe_type_signature != OptionalHeader_PE32Signature)
		return false;

	uint32_t lookup;
	memory_stream::position_type lookup_position;
	while (true)
	{
		if (!file_data.read(lookup) || lookup == 0)
			return false;

		if ((lookup & 0x80000000) == 0)
		{
			lookup_position = file_data.position();
			file_data.seek(section_header.raw_data_offset + lookup - idata_base_rva + 2, file::seek_from::beginning);
			auto name_position = file_data.position();

			string name;
			char ch;
			while ((file_data.read(ch), ch) != '\0')
				name += ch;
			if (name == "DirectDrawCreate")
			{
				file_data.set_position(name_position);
				file_data.seek(-2);
				break;
			}
			file_data.set_position(lookup_position);
		}
	}

	file_data.write(uint16_t(0));
	string_view function_name = "WcdxCreate";
	file_data.write(function_name.data(), function_name.length() * sizeof(char));
	file_data.write('\0');

	file_data.set_position(lookup_position);
	file_data.write(0);
	return true;
}

bool apply_dif(seekable_stream& file_data)
{
	resource_stream resource(RESOURCE_ID_WING1_DIFF);
	string line = read_line(resource);
	if (line != "This difference file has been created by IDA Pro")
		return false;

	while (!resource.at_end())
	{
		line = read_line(resource);
		if (line.empty())
			continue;
		if (line == "Wing1.exe")
			continue;

		auto n = line.find(':');
		if (n == string::npos)
			return false;
		string_view address_str(line, 0, n);

		n = line.find_first_not_of(' ', n + 1);
		if (n == string::npos)
			return false;
		auto m = line.find(' ', n);
		if (n == string::npos)
			return false;
		string_view original_value_str(line, n, m - n);

		n = line.find_first_not_of(' ', m + 1);
		if (n == string::npos)
			return false;
		m = line.find(' ', n);
		if (m == string::npos)
			m = line.length();
		string_view replacement_value_str(line, n, m - n);

		if (line.find_first_not_of(' ', m + 1) != string::npos)
			return false;

		if (original_value_str == "FFFFFFFF")
			continue;

		uint32_t offset = stoul(address_str, nullptr, 16);
		uint8_t original_value = uint8_t(stoul(original_value_str, nullptr, 16));
		uint8_t replacement_value = uint8_t(stoul(replacement_value_str, nullptr, 16));

		file_data.seek(offset, seekable_stream::seek_from::beginning);
		uint8_t value;
		if (!file_data.read(value) || value != original_value)
			return false;
		file_data.seek(-1);
		file_data.write(replacement_value);
	}

	return true;
}

string read_line(seekable_input_stream& is)
{
	auto position = is.position();
	size_t length = 0;
	char ch;
	while (is.read(ch) && (ch != '\r') && (ch != '\n'))
		++length;
	is.set_position(position);

	string line;
	line.reserve(length);
	while (is.read(ch) && (ch != '\r') && (ch != '\n'))
		line += ch;

	if ((ch == '\r') && is.read(ch) && (ch != '\n'))
		is.seek(-1);

	return line;
}
<|endoftext|>