<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/ValueGrammar.hpp"
#include "parser/Utils.hpp"

#include "lexer/adapttokens.hpp"
#include "lexer/position.hpp"

using namespace eddic;

parser::ValueGrammar::ValueGrammar(const lexer::Lexer& lexer, const lexer::pos_iterator_type& position_begin) :
        ValueGrammar::base_type(value, "_value Grammar"),
        type(lexer, position_begin),
        position_begin(position_begin){

    /* Match operators into symbols */

    unary_op.add
        ("+", ast::Operator::ADD)
        ("-", ast::Operator::SUB)
        ("!", ast::Operator::NOT)
        ("*", ast::Operator::STAR)
        ("&", ast::Operator::ADDRESS)
        ;

    additive_op.add
        ("+", ast::Operator::ADD)
        ("-", ast::Operator::SUB)
        ;

    multiplicative_op.add
        ("/", ast::Operator::DIV)
        ("*", ast::Operator::MUL)
        ("%", ast::Operator::MOD)
        ;

    relational_op.add
        (">=", ast::Operator::GREATER_EQUALS)
        (">", ast::Operator::GREATER)
        ("<=", ast::Operator::LESS_EQUALS)
        ("<", ast::Operator::LESS)
        ("!=", ast::Operator::NOT_EQUALS)
        ("==", ast::Operator::EQUALS)
        ;

    logical_and_op.add
        ("&&", ast::Operator::AND)
        ;

    logical_or_op.add
        ("||", ast::Operator::OR)
        ;

    postfix_op.add
        ("++", ast::Operator::INC)
        ("--", ast::Operator::DEC)
        ;

    prefix_op.add
        ("++", ast::Operator::INC)
        ("--", ast::Operator::DEC)
        ;

    builtin_op.add
        ("size", ast::BuiltinType::SIZE)
        ("length", ast::BuiltinType::LENGTH)
        ;

    assign_op.add
        ("=",  ast::Operator::ASSIGN)
        ("+=", ast::Operator::ADD)
        ("-=", ast::Operator::SUB)
        ("/=", ast::Operator::DIV)
        ("*=", ast::Operator::MUL)
        ("%=", ast::Operator::MOD)
        ;

    //Only here to cast ast::Value to ast::OperationValue via the the boost::phoenix function

    casted_value = value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_call_value = call_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_identifier = lexer.identifier[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_cast_expression = cast_expression[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_multiplicative_value = multiplicative_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_additive_value = additive_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_relational_value = relational_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_logicalAnd_value = logicalAnd_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];

    /* Terminal values */

    new_array %=
            qi::position(position_begin)
        >>  lexer.new_
        >>  type.type
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket;

    new_ %=
            qi::position(position_begin)
        >>  lexer.new_
        >>  type.type
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    variable_value %=
            qi::position(position_begin)
        >>
            (
                    lexer.this_
                |   lexer.identifier
            );

    null %=
            qi::eps
        >>  lexer.null;

    true_ %=
            qi::eps
        >>  lexer.true_;

    false_ %=
            qi::eps
        >>  lexer.false_;

    integer %=
            qi::eps
        >>  lexer.integer;

    integer_suffix %=
            qi::eps
        >>  lexer.integer
        >>  lexer.identifier;

    float_ %=
            qi::eps
        >>  lexer.float_;

    string_literal %=
            qi::eps
        >> lexer.string_literal;

    char_literal %=
            qi::eps
        >> lexer.char_literal;

    /* Define values */

    primary_value =
            integer_suffix
        |   integer
        |   float_
        |   string_literal
        |   char_literal
        |   builtin_operator
        |   function_call
        |   new_array
        |   new_
        |   variable_value
        |   null
        |   true_
        |   false_
        |   (lexer.left_parenth >> value >> lexer.right_parenth);

    call_value %=
            lexer.identifier
        >>  -(
                    qi::omit[lexer.less]
                >>  type >> *(lexer.comma > type)
                >>  qi::omit[lexer.greater]
            )
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    postfix_expression %=
            qi::position(position_begin)
        >>  primary_value
        >>  +(
                         lexer.left_bracket
                     >>  boost::spirit::attr(ast::Operator::BRACKET)
                     >>  casted_value
                     >>  lexer.right_bracket
                |
                         lexer.dot
                     >>  boost::spirit::attr(ast::Operator::CALL)
                     >>  casted_call_value
                |
                         lexer.dot
                     >>  boost::spirit::attr(ast::Operator::DOT)
                     >>  casted_identifier
                |
                    qi::adapttokens[postfix_op]
            );

    prefix_operation %=
            qi::position(position_begin)
        >>  qi::adapttokens[prefix_op]
        >>  unary_expression;

    unary_operation %=
            qi::position(position_begin)
        >>  qi::adapttokens[unary_op]
        >>  cast_expression;

    unary_expression %=
            postfix_expression
        |   prefix_operation
        |   unary_operation
        |   primary_value;

    cast_value %=
            qi::position(position_begin)
        >>  lexer.left_parenth
        >>  type.type
        >>  lexer.right_parenth
        >>  cast_expression;

    cast_expression %=
            cast_value
        |   unary_expression;

    multiplicative_value %=
            qi::position(position_begin)
        >>  cast_expression
        >>  *(qi::adapttokens[multiplicative_op] >> casted_cast_expression);

    additive_value %=
            qi::position(position_begin)
        >>  multiplicative_value
        >>  *(qi::adapttokens[additive_op] >> casted_multiplicative_value);

    relational_value %=
            qi::position(position_begin)
        >>  additive_value
        >>  *(qi::adapttokens[relational_op] >> casted_additive_value);

    logicalAnd_value %=
            qi::position(position_begin)
        >>  relational_value
        >>  *(qi::adapttokens[logical_and_op] >> casted_relational_value);

    logicalOr_value %=
            qi::position(position_begin)
        >>  logicalAnd_value
        >>  *(qi::adapttokens[logical_or_op] >> casted_logicalAnd_value);

    ternary %=
            qi::position(position_begin)
        >>  logicalOr_value
        >>  lexer.question_mark
        >>  conditional_expression
        >>  lexer.double_dot
        >>  conditional_expression;

    conditional_expression =
            ternary
         |  logicalOr_value;

    assignment_expression %=
            assignment
        |   conditional_expression;

    assignment %=
            qi::position(position_begin)
        >>  unary_expression
        >>  qi::adapttokens[assign_op]
        >>  assignment_expression;

    value = assignment_expression.alias();

    function_call %=
            qi::position(position_begin)
        >>  lexer.identifier
        >>  -(
                    qi::omit[lexer.less]
                >>  type >> *(lexer.comma > type)
                >>  qi::omit[lexer.greater]
            )
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    builtin_operator %=
            qi::position(position_begin)
        >>  qi::adapttokens[builtin_op]
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    //Configure debugging and rule naming

    DEBUG_RULE(value);
    DEBUG_RULE(primary_value);
    DEBUG_RULE(cast_value);
    DEBUG_RULE(conditional_expression);
    DEBUG_RULE(additive_value);
    DEBUG_RULE(multiplicative_value);
    DEBUG_RULE(relational_value);
    DEBUG_RULE(logicalAnd_value);
    DEBUG_RULE(logicalOr_value);
    DEBUG_RULE(integer);
    DEBUG_RULE(integer_suffix);
    DEBUG_RULE(float_);
    DEBUG_RULE(builtin_operator);
    DEBUG_RULE(function_call);
    DEBUG_RULE(true_);
    DEBUG_RULE(false_);
    DEBUG_RULE(null);
    DEBUG_RULE(new_);
    DEBUG_RULE(new_array);
    DEBUG_RULE(unary_operation);
    DEBUG_RULE(assignment);
    DEBUG_RULE(prefix_operation);
    DEBUG_RULE(builtin_operator);
    DEBUG_RULE(variable_value);
    DEBUG_RULE(ternary);
    DEBUG_RULE(string_literal);
    DEBUG_RULE(char_literal);
    DEBUG_RULE(call_value);

    DEBUG_RULE(assignment_expression);
    DEBUG_RULE(unary_expression);
    DEBUG_RULE(cast_expression);
    DEBUG_RULE(postfix_expression);

    DEBUG_RULE(casted_value);
    DEBUG_RULE(casted_call_value);
    DEBUG_RULE(casted_identifier);
    DEBUG_RULE(casted_cast_expression);
    DEBUG_RULE(casted_additive_value);
    DEBUG_RULE(casted_multiplicative_value);
    DEBUG_RULE(casted_relational_value);
    DEBUG_RULE(casted_logicalAnd_value);
}
<commit_msg>Fix grammar with builtin<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "parser/ValueGrammar.hpp"
#include "parser/Utils.hpp"

#include "lexer/adapttokens.hpp"
#include "lexer/position.hpp"

using namespace eddic;

parser::ValueGrammar::ValueGrammar(const lexer::Lexer& lexer, const lexer::pos_iterator_type& position_begin) :
        ValueGrammar::base_type(value, "_value Grammar"),
        type(lexer, position_begin),
        position_begin(position_begin){

    /* Match operators into symbols */

    unary_op.add
        ("+", ast::Operator::ADD)
        ("-", ast::Operator::SUB)
        ("!", ast::Operator::NOT)
        ("*", ast::Operator::STAR)
        ("&", ast::Operator::ADDRESS)
        ;

    additive_op.add
        ("+", ast::Operator::ADD)
        ("-", ast::Operator::SUB)
        ;

    multiplicative_op.add
        ("/", ast::Operator::DIV)
        ("*", ast::Operator::MUL)
        ("%", ast::Operator::MOD)
        ;

    relational_op.add
        (">=", ast::Operator::GREATER_EQUALS)
        (">", ast::Operator::GREATER)
        ("<=", ast::Operator::LESS_EQUALS)
        ("<", ast::Operator::LESS)
        ("!=", ast::Operator::NOT_EQUALS)
        ("==", ast::Operator::EQUALS)
        ;

    logical_and_op.add
        ("&&", ast::Operator::AND)
        ;

    logical_or_op.add
        ("||", ast::Operator::OR)
        ;

    postfix_op.add
        ("++", ast::Operator::INC)
        ("--", ast::Operator::DEC)
        ;

    prefix_op.add
        ("++", ast::Operator::INC)
        ("--", ast::Operator::DEC)
        ;

    builtin_op.add
        ("size", ast::BuiltinType::SIZE)
        ("length", ast::BuiltinType::LENGTH)
        ;

    assign_op.add
        ("=",  ast::Operator::ASSIGN)
        ("+=", ast::Operator::ADD)
        ("-=", ast::Operator::SUB)
        ("/=", ast::Operator::DIV)
        ("*=", ast::Operator::MUL)
        ("%=", ast::Operator::MOD)
        ;

    //Only here to cast ast::Value to ast::OperationValue via the the boost::phoenix function

    casted_value = value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_call_value = call_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_identifier = lexer.identifier[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_cast_expression = cast_expression[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_multiplicative_value = multiplicative_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_additive_value = additive_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_relational_value = relational_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];
    casted_logicalAnd_value = logicalAnd_value[boost::spirit::qi::_val = cast(boost::spirit::qi::_1)];

    /* Terminal values */

    new_array %=
            qi::position(position_begin)
        >>  lexer.new_
        >>  type.type
        >>  lexer.left_bracket
        >>  value
        >>  lexer.right_bracket;

    new_ %=
            qi::position(position_begin)
        >>  lexer.new_
        >>  type.type
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    variable_value %=
            qi::position(position_begin)
        >>
            (
                    lexer.this_
                |   lexer.identifier
            );

    null %=
            qi::eps
        >>  lexer.null;

    true_ %=
            qi::eps
        >>  lexer.true_;

    false_ %=
            qi::eps
        >>  lexer.false_;

    integer %=
            qi::eps
        >>  lexer.integer;

    integer_suffix %=
            qi::eps
        >>  lexer.integer
        >>  lexer.identifier;

    float_ %=
            qi::eps
        >>  lexer.float_;

    string_literal %=
            qi::eps
        >> lexer.string_literal;

    char_literal %=
            qi::eps
        >> lexer.char_literal;

    /* Define values */

    primary_value =
            integer_suffix
        |   integer
        |   float_
        |   string_literal
        |   char_literal
        |   builtin_operator
        |   function_call
        |   new_array
        |   new_
        |   variable_value
        |   null
        |   true_
        |   false_
        |   (lexer.left_parenth >> value >> lexer.right_parenth);

    call_value %=
            lexer.identifier
        >>  -(
                    qi::omit[lexer.less]
                >>  type >> *(lexer.comma > type)
                >>  qi::omit[lexer.greater]
            )
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    postfix_expression %=
            qi::position(position_begin)
        >>  primary_value
        >>  +(
                         lexer.left_bracket
                     >>  boost::spirit::attr(ast::Operator::BRACKET)
                     >>  casted_value
                     >>  lexer.right_bracket
                |
                         lexer.dot
                     >>  boost::spirit::attr(ast::Operator::CALL)
                     >>  casted_call_value
                |
                         lexer.dot
                     >>  boost::spirit::attr(ast::Operator::DOT)
                     >>  casted_identifier
                |
                    qi::adapttokens[postfix_op]
            );

    prefix_operation %=
            qi::position(position_begin)
        >>  qi::adapttokens[prefix_op]
        >>  unary_expression;

    unary_operation %=
            qi::position(position_begin)
        >>  qi::adapttokens[unary_op]
        >>  cast_expression;

    unary_expression %=
            postfix_expression
        |   prefix_operation
        |   unary_operation
        |   primary_value;

    cast_value %=
            qi::position(position_begin)
        >>  lexer.left_parenth
        >>  type.type
        >>  lexer.right_parenth
        >>  cast_expression;

    cast_expression %=
            cast_value
        |   unary_expression;

    multiplicative_value %=
            qi::position(position_begin)
        >>  cast_expression
        >>  *(qi::adapttokens[multiplicative_op] >> casted_cast_expression);

    additive_value %=
            qi::position(position_begin)
        >>  multiplicative_value
        >>  *(qi::adapttokens[additive_op] >> casted_multiplicative_value);

    relational_value %=
            qi::position(position_begin)
        >>  additive_value
        >>  *(qi::adapttokens[relational_op] >> casted_additive_value);

    logicalAnd_value %=
            qi::position(position_begin)
        >>  relational_value
        >>  *(qi::adapttokens[logical_and_op] >> casted_relational_value);

    logicalOr_value %=
            qi::position(position_begin)
        >>  logicalAnd_value
        >>  *(qi::adapttokens[logical_or_op] >> casted_logicalAnd_value);

    ternary %=
            qi::position(position_begin)
        >>  logicalOr_value
        >>  lexer.question_mark
        >>  conditional_expression
        >>  lexer.double_dot
        >>  conditional_expression;

    conditional_expression =
            ternary
         |  logicalOr_value;

    assignment_expression %=
            assignment
        |   conditional_expression;

    assignment %=
            qi::position(position_begin)
        >>  unary_expression
        >>  qi::adapttokens[assign_op]
        >>  assignment_expression;

    value = assignment_expression.alias();

    function_call %=
            qi::position(position_begin)
        >>  lexer.identifier
        >>  -(
                    qi::omit[lexer.less]
                >>  type >> *(lexer.comma > type)
                >>  qi::omit[lexer.greater]
            )
        >>  lexer.left_parenth
        >>  -( value >> *( lexer.comma > value))
        >>  lexer.right_parenth;

    builtin_operator %=
            qi::position(position_begin)
        >>  qi::adapttokens[builtin_op]
        >>  lexer.left_parenth
        >>  value >> *( lexer.comma > value)
        >>  lexer.right_parenth;

    //Configure debugging and rule naming

    DEBUG_RULE(value);
    DEBUG_RULE(primary_value);
    DEBUG_RULE(cast_value);
    DEBUG_RULE(conditional_expression);
    DEBUG_RULE(additive_value);
    DEBUG_RULE(multiplicative_value);
    DEBUG_RULE(relational_value);
    DEBUG_RULE(logicalAnd_value);
    DEBUG_RULE(logicalOr_value);
    DEBUG_RULE(integer);
    DEBUG_RULE(integer_suffix);
    DEBUG_RULE(float_);
    DEBUG_RULE(builtin_operator);
    DEBUG_RULE(function_call);
    DEBUG_RULE(true_);
    DEBUG_RULE(false_);
    DEBUG_RULE(null);
    DEBUG_RULE(new_);
    DEBUG_RULE(new_array);
    DEBUG_RULE(unary_operation);
    DEBUG_RULE(assignment);
    DEBUG_RULE(prefix_operation);
    DEBUG_RULE(builtin_operator);
    DEBUG_RULE(variable_value);
    DEBUG_RULE(ternary);
    DEBUG_RULE(string_literal);
    DEBUG_RULE(char_literal);
    DEBUG_RULE(call_value);

    DEBUG_RULE(assignment_expression);
    DEBUG_RULE(unary_expression);
    DEBUG_RULE(cast_expression);
    DEBUG_RULE(postfix_expression);

    DEBUG_RULE(casted_value);
    DEBUG_RULE(casted_call_value);
    DEBUG_RULE(casted_identifier);
    DEBUG_RULE(casted_cast_expression);
    DEBUG_RULE(casted_additive_value);
    DEBUG_RULE(casted_multiplicative_value);
    DEBUG_RULE(casted_relational_value);
    DEBUG_RULE(casted_logicalAnd_value);
}
<|endoftext|>


<commit_before>#ifndef ENTT_LOCATOR_LOCATOR_HPP
#define ENTT_LOCATOR_LOCATOR_HPP

#include <memory>
#include <utility>
#include "../config/config.h"

namespace entt {

/**
 * @brief Service locator, nothing more.
 *
 * A service locator is used to do what it promises: locate services.

 * Usually service locators are tightly bound to the services they expose and
 * thus it's hard to define a general purpose class to do that. This tiny class
 * tries to fill the gap and to get rid of the burden of defining a different
 * specific locator for each application.
 *
 * @note
 * Users shouldn't retain references to a service. The recommended way is to
 * retrieve the service implementation currently set each and every time the
 * need for it arises. The risk is to incur in unexpected behaviors otherwise.
 *
 * @tparam Service Service type.
 */
template<typename Service>
class locator final {
    class service_handle {
        friend class locator<Service>;
        std::shared_ptr<Service> value{};
    };

public:
    /*! @brief Service type. */
    using type = Service;
    /*! @brief Service node type. */
    using node_type = service_handle;

    /*! @brief Default constructor, deleted on purpose. */
    locator() = delete;
    /*! @brief Default destructor, deleted on purpose. */
    ~locator() = delete;

    /**
     * @brief Checks whether a service locator contains a value.
     * @return True if the service locator contains a value, false otherwise.
     */
    [[nodiscard]] static bool has_value() noexcept {
        return (service.value != nullptr);
    }

    /**
     * @brief Returns a reference to a valid service, if any.
     *
     * @warning
     * Invoking this function can result in undefined behavior if the service
     * hasn't been set yet.
     *
     * @return A reference to the service currently set, if any.
     */
    [[nodiscard]] static Service &value() noexcept {
        ENTT_ASSERT(has_value(), "Service not available");
        return *service.value;
    }

    /**
     * @brief Returns a service if available or sets it from a fallback type.
     *
     * Arguments are used only if a service doesn't already exist. In all other
     * cases, they are discarded.
     *
     * @tparam Args Types of arguments to use to construct the fallback service.
     * @tparam Impl Fallback service type.
     * @param args Parameters to use to construct the fallback service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename... Args>
    [[nodiscard]] static Service &value_or(Args &&...args) {
        return service.value ? *service.value : emplace<Impl>(std::forward<Args>(args)...);
    }

    /**
     * @brief Sets or replaces a service.
     * @tparam Impl Service type.
     * @tparam Args Types of arguments to use to construct the service.
     * @param args Parameters to use to construct the service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename... Args>
    static Service &emplace(Args &&...args) {
        service.value = std::make_shared<Impl>(std::forward<Args>(args)...);
        return *service.value;
    }

    /**
     * @brief Sets or replaces a service using a given allocator.
     * @tparam Impl Service type.
     * @tparam Allocator Type of allocator used to manage memory and elements.
     * @tparam Args Types of arguments to use to construct the service.
     * @param alloc The allocator to use.
     * @param args Parameters to use to construct the service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename Allocator, typename... Args>
    static Service &allocate_emplace(Allocator alloc, Args &&...args) {
        service.value = std::allocate_shared<Impl>(alloc, std::forward<Args>(args)...);
        return *service.value;
    }

    /**
     * @brief Returns a handle to the underlying service.
     * @return A handle to the underlying service.
     */
    static node_type handle() noexcept {
        return service;
    }

    /**
     * @brief Resets or replaces a service.
     * @param handle Optional handle with which to replace the service.
     */
    static void reset(const node_type &handle = {}) noexcept {
        service = handle;
    }

private:
    inline static service_handle service{};
};

} // namespace entt

#endif
<commit_msg>locator: avoid shadow warnings<commit_after>#ifndef ENTT_LOCATOR_LOCATOR_HPP
#define ENTT_LOCATOR_LOCATOR_HPP

#include <memory>
#include <utility>
#include "../config/config.h"

namespace entt {

/**
 * @brief Service locator, nothing more.
 *
 * A service locator is used to do what it promises: locate services.

 * Usually service locators are tightly bound to the services they expose and
 * thus it's hard to define a general purpose class to do that. This tiny class
 * tries to fill the gap and to get rid of the burden of defining a different
 * specific locator for each application.
 *
 * @note
 * Users shouldn't retain references to a service. The recommended way is to
 * retrieve the service implementation currently set each and every time the
 * need for it arises. The risk is to incur in unexpected behaviors otherwise.
 *
 * @tparam Service Service type.
 */
template<typename Service>
class locator final {
    class service_handle {
        friend class locator<Service>;
        std::shared_ptr<Service> value{};
    };

public:
    /*! @brief Service type. */
    using type = Service;
    /*! @brief Service node type. */
    using node_type = service_handle;

    /*! @brief Default constructor, deleted on purpose. */
    locator() = delete;
    /*! @brief Default destructor, deleted on purpose. */
    ~locator() = delete;

    /**
     * @brief Checks whether a service locator contains a value.
     * @return True if the service locator contains a value, false otherwise.
     */
    [[nodiscard]] static bool has_value() noexcept {
        return (service.value != nullptr);
    }

    /**
     * @brief Returns a reference to a valid service, if any.
     *
     * @warning
     * Invoking this function can result in undefined behavior if the service
     * hasn't been set yet.
     *
     * @return A reference to the service currently set, if any.
     */
    [[nodiscard]] static Service &value() noexcept {
        ENTT_ASSERT(has_value(), "Service not available");
        return *service.value;
    }

    /**
     * @brief Returns a service if available or sets it from a fallback type.
     *
     * Arguments are used only if a service doesn't already exist. In all other
     * cases, they are discarded.
     *
     * @tparam Args Types of arguments to use to construct the fallback service.
     * @tparam Impl Fallback service type.
     * @param args Parameters to use to construct the fallback service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename... Args>
    [[nodiscard]] static Service &value_or(Args &&...args) {
        return service.value ? *service.value : emplace<Impl>(std::forward<Args>(args)...);
    }

    /**
     * @brief Sets or replaces a service.
     * @tparam Impl Service type.
     * @tparam Args Types of arguments to use to construct the service.
     * @param args Parameters to use to construct the service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename... Args>
    static Service &emplace(Args &&...args) {
        service.value = std::make_shared<Impl>(std::forward<Args>(args)...);
        return *service.value;
    }

    /**
     * @brief Sets or replaces a service using a given allocator.
     * @tparam Impl Service type.
     * @tparam Allocator Type of allocator used to manage memory and elements.
     * @tparam Args Types of arguments to use to construct the service.
     * @param alloc The allocator to use.
     * @param args Parameters to use to construct the service.
     * @return A reference to a valid service.
     */
    template<typename Impl = Service, typename Allocator, typename... Args>
    static Service &allocate_emplace(Allocator alloc, Args &&...args) {
        service.value = std::allocate_shared<Impl>(alloc, std::forward<Args>(args)...);
        return *service.value;
    }

    /**
     * @brief Returns a handle to the underlying service.
     * @return A handle to the underlying service.
     */
    static node_type handle() noexcept {
        return service;
    }

    /**
     * @brief Resets or replaces a service.
     * @param other Optional handle with which to replace the service.
     */
    static void reset(const node_type &other = {}) noexcept {
        service = other;
    }

private:
    inline static service_handle service{};
};

} // namespace entt

#endif
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 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
//
//  Current versions can be found at www.libavg.de
//

#include "DisplayInfo.h"
#include "Bitmap.h"

#include "../base/Exception.h"

#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>

#ifdef AVG_ENABLE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __APPLE__
#include <ApplicationServices/ApplicationServices.h>
#endif

#include <iostream>

using namespace std;

namespace avg {

DisplayInfo::DisplayInfo()
{
    m_ScreenResolution = queryScreenResolution();
    m_PPMM = queryPPMM();
}

DisplayInfo::~DisplayInfo()
{
}

IntPoint DisplayInfo::getScreenResolution()
{
    return m_ScreenResolution;
}

float DisplayInfo::getPixelsPerMM()
{
    return m_PPMM;
}

void DisplayInfo::assumePixelsPerMM(float ppmm)
{
    m_PPMM = ppmm;
}

glm::vec2 DisplayInfo::getPhysicalScreenDimensions()
{
    glm::vec2 size;
    glm::vec2 screenRes = glm::vec2(getScreenResolution());
    size.x = screenRes.x/m_PPMM;
    size.y = screenRes.y/m_PPMM;
    return size;
}

float DisplayInfo::queryPPMM()
{
#ifdef WIN32
    HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
    return GetDeviceCaps(hdc, LOGPIXELSX)/25.4f;
#else
#ifdef linux
    Display * pDisplay = XOpenDisplay(0);
    glm::vec2 displayMM(DisplayWidthMM(pDisplay,0), DisplayHeightMM(pDisplay,0));
#elif defined __APPLE__
    CGSize size = CGDisplayScreenSize(CGMainDisplayID());
    glm::vec2 displayMM(size.width, size.height);
#endif
    // Non-Square pixels cause errors here. We'll fix that when it happens.
    return m_ScreenResolution.x/displayMM.x;
#endif
}

IntPoint DisplayInfo::queryScreenResolution()
{
#ifdef AVG_ENABLE_XINERAMA
    Display * pDisplay = XOpenDisplay(0);
    int dummy1, dummy2;
    Bool bXinerama = XineramaQueryExtension(pDisplay, &dummy1, &dummy2);
    if (bXinerama) {
        bXinerama = XineramaIsActive(pDisplay);
    }
    if (bXinerama) {
        int numHeads = 0;
        XineramaScreenInfo * pScreenInfo = XineramaQueryScreens(pDisplay, &numHeads);
        AVG_ASSERT(numHeads >= 1);
        /*
        cerr << "Num heads: " << numHeads << endl;
        for (int x=0; x<numHeads; ++x) {
            cout << "Head " << x+1 << ": " <<
                pScreenInfo[x].width << "x" << pScreenInfo[x].height << " at " <<
                pScreenInfo[x].x_org << "," << pScreenInfo[x].y_org << endl;
        }
        */
        return IntPoint(pScreenInfo[0].width, pScreenInfo[0].height);
        XFree(pScreenInfo);
    } else {
        const SDL_VideoInfo* pInfo = SDL_GetVideoInfo();
        return IntPoint(pInfo->current_w, pInfo->current_h);
    }
    XCloseDisplay(pDisplay);
#else
    const SDL_VideoInfo* pInfo = SDL_GetVideoInfo();
    return IntPoint(pInfo->current_w, pInfo->current_h);
#endif
}

}
<commit_msg>egl2 branch: Fixed pixelspermm calculation.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 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
//
//  Current versions can be found at www.libavg.de
//

#include "DisplayInfo.h"
#include "Bitmap.h"

#include "../base/Exception.h"

#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>

#ifdef AVG_ENABLE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __APPLE__
#include <ApplicationServices/ApplicationServices.h>
#endif

#include <iostream>

using namespace std;

namespace avg {

DisplayInfo::DisplayInfo()
{
    m_ScreenResolution = queryScreenResolution();
    m_PPMM = queryPPMM();
}

DisplayInfo::~DisplayInfo()
{
}

IntPoint DisplayInfo::getScreenResolution()
{
    return m_ScreenResolution;
}

float DisplayInfo::getPixelsPerMM()
{
    return m_PPMM;
}

void DisplayInfo::assumePixelsPerMM(float ppmm)
{
    if (ppmm != 0) {
        m_PPMM = ppmm;
    }
}

glm::vec2 DisplayInfo::getPhysicalScreenDimensions()
{
    glm::vec2 size;
    glm::vec2 screenRes = glm::vec2(getScreenResolution());
    size.x = screenRes.x/m_PPMM;
    size.y = screenRes.y/m_PPMM;
    return size;
}

float DisplayInfo::queryPPMM()
{
#ifdef WIN32
    HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
    return GetDeviceCaps(hdc, LOGPIXELSX)/25.4f;
#else
#ifdef linux
    Display * pDisplay = XOpenDisplay(0);
    glm::vec2 displayMM(DisplayWidthMM(pDisplay,0), DisplayHeightMM(pDisplay,0));
#elif defined __APPLE__
    CGSize size = CGDisplayScreenSize(CGMainDisplayID());
    glm::vec2 displayMM(size.width, size.height);
#endif
    // Non-Square pixels cause errors here. We'll fix that when it happens.
    return m_ScreenResolution.x/displayMM.x;
#endif
}

IntPoint DisplayInfo::queryScreenResolution()
{
#ifdef AVG_ENABLE_XINERAMA
    Display * pDisplay = XOpenDisplay(0);
    int dummy1, dummy2;
    Bool bXinerama = XineramaQueryExtension(pDisplay, &dummy1, &dummy2);
    if (bXinerama) {
        bXinerama = XineramaIsActive(pDisplay);
    }
    if (bXinerama) {
        int numHeads = 0;
        XineramaScreenInfo * pScreenInfo = XineramaQueryScreens(pDisplay, &numHeads);
        AVG_ASSERT(numHeads >= 1);
        /*
        cerr << "Num heads: " << numHeads << endl;
        for (int x=0; x<numHeads; ++x) {
            cout << "Head " << x+1 << ": " <<
                pScreenInfo[x].width << "x" << pScreenInfo[x].height << " at " <<
                pScreenInfo[x].x_org << "," << pScreenInfo[x].y_org << endl;
        }
        */
        return IntPoint(pScreenInfo[0].width, pScreenInfo[0].height);
        XFree(pScreenInfo);
    } else {
        const SDL_VideoInfo* pInfo = SDL_GetVideoInfo();
        return IntPoint(pInfo->current_w, pInfo->current_h);
    }
    XCloseDisplay(pDisplay);
#else
    const SDL_VideoInfo* pInfo = SDL_GetVideoInfo();
    return IntPoint(pInfo->current_w, pInfo->current_h);
#endif
}

}
<|endoftext|>


<commit_before>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker 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 Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <stdio.h>
#include <map>
#include <string>
#include <vector>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/globals.h"
#include "common/tag.h"
#include "common/string.h"
#include "common/RenderFormat.h"
#include "ngsi/ContextAttributeVector.h"
#include "ngsi/Request.h"
#include "rest/ConnectionInfo.h"
#include "rest/uriParamNames.h"

/* ****************************************************************************
*
* ContextAttributeVector::ContextAttributeVector -
*/
ContextAttributeVector::ContextAttributeVector()
{
  vec.clear();
}

/* ****************************************************************************
*
* addedLookup -
*/
static std::string addedLookup(const std::vector<std::string>& added, std::string value)
{
  for (unsigned int ix = 0; ix < added.size(); ++ix)
  {
    if (added[ix] == value)
    {
      return value;
    }
  }

  return "";
}

/* ****************************************************************************
*
* ContextAttributeVector::toJsonTypes -
*/
std::string ContextAttributeVector::toJsonTypes(void)
{
  // Pass 1 - get per-attribute types
  std::map<std::string, std::map<std::string, int> > perAttrTypes;

  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    ContextAttribute* caP = vec[ix];
    perAttrTypes[caP->name][caP->type] = 1;   // just to mark that type exists
  }

  // Pass 2 - generate JSON
  std::string out;

  std::map<std::string, std::map<std::string, int> >::iterator it;
  unsigned int                                                 ix;
  for (it = perAttrTypes.begin(), ix = 0; it != perAttrTypes.end(); ++it, ++ix)
  {
    std::string                 attrName  = it->first;
    std::map<std::string, int>  attrTypes = it->second;

    out += JSON_STR(attrName) + ":{" + JSON_STR("types") + ":[";

    std::map<std::string, int>::iterator jt;
    unsigned int                         jx;

    for (jt = attrTypes.begin(), jx = 0; jt != attrTypes.end(); ++jt, ++jx)
    {
      std::string type = jt->first;

      //
      // Special condition for 'options=noAttrDetail':
      //   When the 'options' URI parameter contains 'noAttrDetail',
      //   mongoBackend fills the attribute type vector with *just one item* (that is an empty string).
      //   This special condition is checked for here, to produce a [] for the vector for the response.
      //
      // See the origin of this in mongoQueryTypes.cpp. Look for "NOTE: here we add", in two locations.
      //
      if ((type != "") || (attrTypes.size() != 1))
      {
        out += JSON_STR(type);
      }

      if (jx != attrTypes.size() - 1)
      {
        out += ",";
      }
    }

    out += "]}";

    if (ix != perAttrTypes.size() - 1)
    {
      out += ",";
    }
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::toJson -
*
* Attributes named 'id' or 'type' are not rendered in API version 2, due to the
* compact way in which API v2 is rendered. Attributes named 'id' or 'type' would simply
* collide with the 'id' and 'type' of the entity itself (holder of the attribute).
*
* If anybody needs an attribute named 'id' or 'type', then API v1
* will have to be used to retrieve that information.
*/
std::string ContextAttributeVector::toJson
(
  RenderFormat                     renderFormat,
  const std::vector<std::string>&  attrsFilter,
  const std::vector<std::string>&  metadataFilter,
  bool                             blacklist
) const
{
  if (vec.size() == 0)
  {
    return "";
  }

  //
  // Pass 1 - count the total number of attributes valid for rendering.
  //
  // Attributes named 'id' or 'type' are not rendered.
  // This gives us a small problem in the logic here, about knowing whether the
  // comma should be rendered or not.
  //
  // To fix this problem we need to do two passes over the vector, the first pass to
  // count the number of valid attributes and the second to do the work.
  // In the second pass, if the number of rendered attributes "so far" is less than the total
  // number of valid attributes, then the comma must be rendered.
  //
  int validAttributes = 0;
  std::map<std::string, bool>  uniqueMap;
  if ((attrsFilter.size() == 0) || (std::find(attrsFilter.begin(), attrsFilter.end(), ALL_ATTRS) != attrsFilter.end()))
  {
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if ((vec[ix]->name == "id") || (vec[ix]->name == "type"))
      {
        continue;
      }

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        if (uniqueMap[vec[ix]->stringValue] == true)
        {
          continue;
        }
      }

      ++validAttributes;

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        uniqueMap[vec[ix]->stringValue] = true;
      }
    }
  }
  else if (!blacklist)
  {
    for (std::vector<std::string>::const_iterator it = attrsFilter.begin(); it != attrsFilter.end(); ++it)
    {
      if (lookup(*it) != NULL)
      {
        ++validAttributes;
      }
    }
  }
  else // attrsFilter is black list
  {
    for (unsigned ix = 0; ix < vec.size(); ++ix)
    {
      if (std::find(attrsFilter.begin(), attrsFilter.end(), vec[ix]->name) == attrsFilter.end())
      {
         ++validAttributes;
      }
    }
  }

  //
  // Pass 2 - do the work, helped by the value of 'validAttributes'.
  //
  std::string  out;
  int          renderedAttributes = 0;

  uniqueMap.clear();

  if (attrsFilter.size() == 0 || (std::find(attrsFilter.begin(), attrsFilter.end(), ALL_ATTRS) != attrsFilter.end()))
  {
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if ((vec[ix]->name == "id") || (vec[ix]->name == "type"))
      {
        continue;
      }

      ++renderedAttributes;

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        if (uniqueMap[vec[ix]->stringValue] == true)
        {
          continue;
        }
      }

      out += vec[ix]->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        uniqueMap[vec[ix]->stringValue] = true;
      }
    }
  }
  else if (!blacklist)
  {
    for (std::vector<std::string>::const_iterator it = attrsFilter.begin(); it != attrsFilter.end(); ++it)
    {
      ContextAttribute* caP = lookup(*it);
      if (caP != NULL)
      {
        ++renderedAttributes;
        out += caP->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);
      }
    }
  }
  else // attrsFilter is black list
  {
    for (unsigned ix = 0; ix < vec.size(); ++ix)
    {
      if (std::find(attrsFilter.begin(), attrsFilter.end(), vec[ix]->name) == attrsFilter.end())
      {
        ++renderedAttributes;
        out += vec[ix]->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);
      }
    }
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::render -
*/
std::string ContextAttributeVector::render
(
  const std::string&  apiVersion,
  bool                asJsonObject,
  RequestType         request,
  const std::string&  indent,
  bool                comma,
  bool                omitValue,
  bool                attrsAsName
)
{
  std::string out = "";
  std::string key = "attributes";

  if (vec.size() == 0)
  {
    return "";
  }

  //
  // NOTE:
  // If the URI parameter 'attributeFormat' is set to 'object', then the attribute vector
  // is to be rendered as objects for JSON, and not as a vector.
  // Also, if we have more than one attribute with the same name (possible if different metaID),
  // only one of them should be included in the vector. Any one of them.
  // So, step 1 is to purge the context attribute vector from 'copies'.
  //
  if (asJsonObject)
  {
    std::vector<std::string> added;

    // 1. Remove attributes with attribute names already used.
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (addedLookup(added, vec[ix]->name) == "")
      {
        added.push_back(vec[ix]->name);
        LM_T(LmtJsonAttributes, ("Keeping attribute '%s'", vec[ix]->name.c_str()));
      }
      else
      {
        LM_T(LmtJsonAttributes, ("Removing attribute '%s'", vec[ix]->name.c_str()));
        vec[ix]->release();
        delete vec[ix];
        vec.erase(vec.begin() + ix);
      }
    }

    // 2. Now it's time to render
    // Note that in the case of attribute as name, we have to use a vector, thus using
    // attrsAsName variable as value for isVector parameter
    out += startTag2(indent, key, attrsAsName, true);
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (attrsAsName)
      {
        out += vec[ix]->renderAsNameString(apiVersion, request);
      }
      else
      {
        out += vec[ix]->render(apiVersion, asJsonObject, request, indent + "  ", ix != vec.size() - 1, omitValue);
      }
    }
    out += endTag(indent, comma, attrsAsName);
  }
  else
  {
    out += startTag2(indent, key, true, true);
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (attrsAsName)
      {
        out += vec[ix]->renderAsNameString(apiVersion, request);
      }
      else
      {
        out += vec[ix]->render(apiVersion, asJsonObject, request, indent + "  ", ix != vec.size() - 1, omitValue);
      }
    }
    out += endTag(indent, comma, true);
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::check -
*/
std::string ContextAttributeVector::check(const std::string& apiVersion, RequestType requestType)
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    std::string res;

    if ((res = vec[ix]->check(apiVersion, requestType)) != "OK")
      return res;
  }

  return "OK";
}

/* ****************************************************************************
*
* ContextAttributeVector::present -
*/
void ContextAttributeVector::present(const std::string& indent)
{
  LM_T(LmtPresent, ("%s%lu ContextAttributes",
		    indent.c_str(),
		    (uint64_t) vec.size()));

  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    vec[ix]->present(indent + "  ", ix);
  }
}

/* ****************************************************************************
*
* ContextAttributeVector::push_back -
*/
void ContextAttributeVector::push_back(ContextAttribute* item)
{
  vec.push_back(item);
}

/* ****************************************************************************
*
* ContextAttributeVector::push_back -
*/
void ContextAttributeVector::push_back(ContextAttributeVector* aVec)
{
  for (unsigned int ix = 0; ix < aVec->size(); ++ix)
  {
    vec.push_back(new ContextAttribute((*aVec)[ix]));
  }
}

/* ****************************************************************************
*
* ContextAttributeVector::size -
*/
unsigned int ContextAttributeVector::size(void) const
{
  return vec.size();
}

/* ****************************************************************************
*
* ContextAttributeVector::operator[] -
*/
ContextAttribute*  ContextAttributeVector::operator[](unsigned int ix) const
{
  if (ix < vec.size())
  {
    return vec[ix];
  }
  return NULL;
}

/* ****************************************************************************
*
* ContextAttributeVector::release -
*/
void ContextAttributeVector::release(void)
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    vec[ix]->release();
    delete vec[ix];
  }

  vec.clear();
}

/* ****************************************************************************
*
* ContextAttributeVector::fill -
*/
void ContextAttributeVector::fill(ContextAttributeVector* cavP, bool useDefaultType)
{
  if (cavP == NULL)
  {
    return;
  }

  for (unsigned int ix = 0; ix < cavP->size(); ++ix)
  {
    ContextAttribute* from = (*cavP)[ix];
    ContextAttribute* caP = new ContextAttribute(from, useDefaultType);

    push_back(caP);
  }
}

/* ****************************************************************************
*
* lookup -
*/
ContextAttribute* ContextAttributeVector::lookup(const std::string& attributeName) const
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    if (vec[ix]->name == attributeName)
    {
      return vec[ix];
    }
  }

  return NULL;
}
<commit_msg>FIX renderAsNameString() call<commit_after>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker 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 Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Ken Zangelin
*/
#include <stdio.h>
#include <map>
#include <string>
#include <vector>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/globals.h"
#include "common/tag.h"
#include "common/string.h"
#include "common/RenderFormat.h"
#include "ngsi/ContextAttributeVector.h"
#include "ngsi/Request.h"
#include "rest/ConnectionInfo.h"
#include "rest/uriParamNames.h"

/* ****************************************************************************
*
* ContextAttributeVector::ContextAttributeVector -
*/
ContextAttributeVector::ContextAttributeVector()
{
  vec.clear();
}

/* ****************************************************************************
*
* addedLookup -
*/
static std::string addedLookup(const std::vector<std::string>& added, std::string value)
{
  for (unsigned int ix = 0; ix < added.size(); ++ix)
  {
    if (added[ix] == value)
    {
      return value;
    }
  }

  return "";
}

/* ****************************************************************************
*
* ContextAttributeVector::toJsonTypes -
*/
std::string ContextAttributeVector::toJsonTypes(void)
{
  // Pass 1 - get per-attribute types
  std::map<std::string, std::map<std::string, int> > perAttrTypes;

  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    ContextAttribute* caP = vec[ix];
    perAttrTypes[caP->name][caP->type] = 1;   // just to mark that type exists
  }

  // Pass 2 - generate JSON
  std::string out;

  std::map<std::string, std::map<std::string, int> >::iterator it;
  unsigned int                                                 ix;
  for (it = perAttrTypes.begin(), ix = 0; it != perAttrTypes.end(); ++it, ++ix)
  {
    std::string                 attrName  = it->first;
    std::map<std::string, int>  attrTypes = it->second;

    out += JSON_STR(attrName) + ":{" + JSON_STR("types") + ":[";

    std::map<std::string, int>::iterator jt;
    unsigned int                         jx;

    for (jt = attrTypes.begin(), jx = 0; jt != attrTypes.end(); ++jt, ++jx)
    {
      std::string type = jt->first;

      //
      // Special condition for 'options=noAttrDetail':
      //   When the 'options' URI parameter contains 'noAttrDetail',
      //   mongoBackend fills the attribute type vector with *just one item* (that is an empty string).
      //   This special condition is checked for here, to produce a [] for the vector for the response.
      //
      // See the origin of this in mongoQueryTypes.cpp. Look for "NOTE: here we add", in two locations.
      //
      if ((type != "") || (attrTypes.size() != 1))
      {
        out += JSON_STR(type);
      }

      if (jx != attrTypes.size() - 1)
      {
        out += ",";
      }
    }

    out += "]}";

    if (ix != perAttrTypes.size() - 1)
    {
      out += ",";
    }
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::toJson -
*
* Attributes named 'id' or 'type' are not rendered in API version 2, due to the
* compact way in which API v2 is rendered. Attributes named 'id' or 'type' would simply
* collide with the 'id' and 'type' of the entity itself (holder of the attribute).
*
* If anybody needs an attribute named 'id' or 'type', then API v1
* will have to be used to retrieve that information.
*/
std::string ContextAttributeVector::toJson
(
  RenderFormat                     renderFormat,
  const std::vector<std::string>&  attrsFilter,
  const std::vector<std::string>&  metadataFilter,
  bool                             blacklist
) const
{
  if (vec.size() == 0)
  {
    return "";
  }

  //
  // Pass 1 - count the total number of attributes valid for rendering.
  //
  // Attributes named 'id' or 'type' are not rendered.
  // This gives us a small problem in the logic here, about knowing whether the
  // comma should be rendered or not.
  //
  // To fix this problem we need to do two passes over the vector, the first pass to
  // count the number of valid attributes and the second to do the work.
  // In the second pass, if the number of rendered attributes "so far" is less than the total
  // number of valid attributes, then the comma must be rendered.
  //
  int validAttributes = 0;
  std::map<std::string, bool>  uniqueMap;
  if ((attrsFilter.size() == 0) || (std::find(attrsFilter.begin(), attrsFilter.end(), ALL_ATTRS) != attrsFilter.end()))
  {
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if ((vec[ix]->name == "id") || (vec[ix]->name == "type"))
      {
        continue;
      }

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        if (uniqueMap[vec[ix]->stringValue] == true)
        {
          continue;
        }
      }

      ++validAttributes;

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        uniqueMap[vec[ix]->stringValue] = true;
      }
    }
  }
  else if (!blacklist)
  {
    for (std::vector<std::string>::const_iterator it = attrsFilter.begin(); it != attrsFilter.end(); ++it)
    {
      if (lookup(*it) != NULL)
      {
        ++validAttributes;
      }
    }
  }
  else // attrsFilter is black list
  {
    for (unsigned ix = 0; ix < vec.size(); ++ix)
    {
      if (std::find(attrsFilter.begin(), attrsFilter.end(), vec[ix]->name) == attrsFilter.end())
      {
         ++validAttributes;
      }
    }
  }

  //
  // Pass 2 - do the work, helped by the value of 'validAttributes'.
  //
  std::string  out;
  int          renderedAttributes = 0;

  uniqueMap.clear();

  if (attrsFilter.size() == 0 || (std::find(attrsFilter.begin(), attrsFilter.end(), ALL_ATTRS) != attrsFilter.end()))
  {
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if ((vec[ix]->name == "id") || (vec[ix]->name == "type"))
      {
        continue;
      }

      ++renderedAttributes;

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        if (uniqueMap[vec[ix]->stringValue] == true)
        {
          continue;
        }
      }

      out += vec[ix]->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);

      if ((renderFormat == NGSI_V2_UNIQUE_VALUES) && (vec[ix]->valueType == orion::ValueTypeString))
      {
        uniqueMap[vec[ix]->stringValue] = true;
      }
    }
  }
  else if (!blacklist)
  {
    for (std::vector<std::string>::const_iterator it = attrsFilter.begin(); it != attrsFilter.end(); ++it)
    {
      ContextAttribute* caP = lookup(*it);
      if (caP != NULL)
      {
        ++renderedAttributes;
        out += caP->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);
      }
    }
  }
  else // attrsFilter is black list
  {
    for (unsigned ix = 0; ix < vec.size(); ++ix)
    {
      if (std::find(attrsFilter.begin(), attrsFilter.end(), vec[ix]->name) == attrsFilter.end())
      {
        ++renderedAttributes;
        out += vec[ix]->toJson(renderedAttributes == validAttributes, renderFormat, metadataFilter);
      }
    }
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::render -
*/
std::string ContextAttributeVector::render
(
  const std::string&  apiVersion,
  bool                asJsonObject,
  RequestType         request,
  const std::string&  indent,
  bool                comma,
  bool                omitValue,
  bool                attrsAsName
)
{
  std::string out = "";
  std::string key = "attributes";

  if (vec.size() == 0)
  {
    return "";
  }

  //
  // NOTE:
  // If the URI parameter 'attributeFormat' is set to 'object', then the attribute vector
  // is to be rendered as objects for JSON, and not as a vector.
  // Also, if we have more than one attribute with the same name (possible if different metaID),
  // only one of them should be included in the vector. Any one of them.
  // So, step 1 is to purge the context attribute vector from 'copies'.
  //
  if (asJsonObject)
  {
    std::vector<std::string> added;

    // 1. Remove attributes with attribute names already used.
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (addedLookup(added, vec[ix]->name) == "")
      {
        added.push_back(vec[ix]->name);
        LM_T(LmtJsonAttributes, ("Keeping attribute '%s'", vec[ix]->name.c_str()));
      }
      else
      {
        LM_T(LmtJsonAttributes, ("Removing attribute '%s'", vec[ix]->name.c_str()));
        vec[ix]->release();
        delete vec[ix];
        vec.erase(vec.begin() + ix);
      }
    }

    // 2. Now it's time to render
    // Note that in the case of attribute as name, we have to use a vector, thus using
    // attrsAsName variable as value for isVector parameter
    out += startTag2(indent, key, attrsAsName, true);
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (attrsAsName)
      {
        out += vec[ix]->renderAsNameString(indent + "  ", ix != vec.size() - 1);
      }
      else
      {
        out += vec[ix]->render(apiVersion, asJsonObject, request, indent + "  ", ix != vec.size() - 1, omitValue);
      }
    }
    out += endTag(indent, comma, attrsAsName);
  }
  else
  {
    out += startTag2(indent, key, true, true);
    for (unsigned int ix = 0; ix < vec.size(); ++ix)
    {
      if (attrsAsName)
      {
        out += vec[ix]->renderAsNameString(indent + "  ", ix != vec.size() - 1);
      }
      else
      {
        out += vec[ix]->render(apiVersion, asJsonObject, request, indent + "  ", ix != vec.size() - 1, omitValue);
      }
    }
    out += endTag(indent, comma, true);
  }

  return out;
}

/* ****************************************************************************
*
* ContextAttributeVector::check -
*/
std::string ContextAttributeVector::check(const std::string& apiVersion, RequestType requestType)
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    std::string res;

    if ((res = vec[ix]->check(apiVersion, requestType)) != "OK")
      return res;
  }

  return "OK";
}

/* ****************************************************************************
*
* ContextAttributeVector::present -
*/
void ContextAttributeVector::present(const std::string& indent)
{
  LM_T(LmtPresent, ("%s%lu ContextAttributes",
		    indent.c_str(),
		    (uint64_t) vec.size()));

  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    vec[ix]->present(indent + "  ", ix);
  }
}

/* ****************************************************************************
*
* ContextAttributeVector::push_back -
*/
void ContextAttributeVector::push_back(ContextAttribute* item)
{
  vec.push_back(item);
}

/* ****************************************************************************
*
* ContextAttributeVector::push_back -
*/
void ContextAttributeVector::push_back(ContextAttributeVector* aVec)
{
  for (unsigned int ix = 0; ix < aVec->size(); ++ix)
  {
    vec.push_back(new ContextAttribute((*aVec)[ix]));
  }
}

/* ****************************************************************************
*
* ContextAttributeVector::size -
*/
unsigned int ContextAttributeVector::size(void) const
{
  return vec.size();
}

/* ****************************************************************************
*
* ContextAttributeVector::operator[] -
*/
ContextAttribute*  ContextAttributeVector::operator[](unsigned int ix) const
{
  if (ix < vec.size())
  {
    return vec[ix];
  }
  return NULL;
}

/* ****************************************************************************
*
* ContextAttributeVector::release -
*/
void ContextAttributeVector::release(void)
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    vec[ix]->release();
    delete vec[ix];
  }

  vec.clear();
}

/* ****************************************************************************
*
* ContextAttributeVector::fill -
*/
void ContextAttributeVector::fill(ContextAttributeVector* cavP, bool useDefaultType)
{
  if (cavP == NULL)
  {
    return;
  }

  for (unsigned int ix = 0; ix < cavP->size(); ++ix)
  {
    ContextAttribute* from = (*cavP)[ix];
    ContextAttribute* caP = new ContextAttribute(from, useDefaultType);

    push_back(caP);
  }
}

/* ****************************************************************************
*
* lookup -
*/
ContextAttribute* ContextAttributeVector::lookup(const std::string& attributeName) const
{
  for (unsigned int ix = 0; ix < vec.size(); ++ix)
  {
    if (vec[ix]->name == attributeName)
    {
      return vec[ix];
    }
  }

  return NULL;
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real

    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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decoders/RafDecoder.h"
#include "common/Common.h"                          // for uint32, ushort16
#include "common/Point.h"                           // for iPoint2D, iRecta...
#include "decoders/RawDecoderException.h"           // for RawDecoderExcept...
#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
#include "decompressors/FujiDecompressor.h"
#include "io/Buffer.h"                              // for Buffer
#include "io/ByteStream.h"                          // for ByteStream
#include "io/Endianness.h"                          // for getHostEndianness
#include "metadata/BlackArea.h"                     // for BlackArea
#include "metadata/Camera.h"                        // for Camera, Hints
#include "metadata/CameraMetaData.h"                // for CameraMetaData
#include "metadata/CameraSensorInfo.h"              // for CameraSensorInfo
#include "metadata/ColorFilterArray.h"              // for ColorFilterArray
#include "tiff/TiffEntry.h"                         // for TiffEntry
#include "tiff/TiffIFD.h"                           // for TiffRootIFD, Tif...
#include "tiff/TiffTag.h"                           // for TiffTag::FUJIOLDWB
#include <cassert>                                  // for assert
#include <cstdio>                                   // for size_t
#include <cstring>                                  // for memcmp
#include <memory>                                   // for unique_ptr, allo...
#include <string>                                   // for string
#include <vector>                                   // for vector

namespace rawspeed {

bool RafDecoder::isRAF(const Buffer* input) {
  static const char magic[] = "FUJIFILMCCD-RAW ";
  static const size_t magic_size = sizeof(magic) - 1; // excluding \0
  const unsigned char* data = input->getData(0, magic_size);
  return 0 == memcmp(&data[0], magic, magic_size);
}

bool RafDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
                                      const Buffer* file) {
  const auto id = rootIFD->getID();
  const std::string& make = id.make;

  // FIXME: magic

  return make == "FUJIFILM";
}

RawImage RafDecoder::decodeRawInternal() {
  auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
  uint32 height = 0;
  uint32 width = 0;
  bool isCompressed = false;

  if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
    height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
    width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
  } else if (raw->hasEntry(IMAGEWIDTH)) {
    TiffEntry *e = raw->getEntry(IMAGEWIDTH);
    height = e->getU16(0);
    width = e->getU16(1);
  } else
    ThrowRDE("Unable to locate image size");

  if (height < 1 || width < 1)
    ThrowRDE("Bad image dimensions");

  if (raw->hasEntry(FUJI_LAYOUT)) {
    TiffEntry *e = raw->getEntry(FUJI_LAYOUT);
    alt_layout = !(e->getByte(0) >> 7);
  }

  TiffEntry *offsets = raw->getEntry(FUJI_STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(FUJI_STRIPBYTECOUNTS);

  if (offsets->count != 1 || counts->count != 1)
    ThrowRDE("Multiple Strips found: %u %u", offsets->count, counts->count);

  if (counts->getU32() * 8 / (width * height) < 10)
    isCompressed = true;

  ByteStream input(offsets->getRootIfdData());
  input = input.getSubStream(offsets->getU32(), counts->getU32());

  // x-trans sensors report 14bpp, but data isn't packed
  // thus, unless someone has any better ideas, let's autodetect it.
  int bps;

  // Some fuji SuperCCD cameras include a second raw image next to the first one
  // that is identical but darker to the first. The two combined can produce
  // a higher dynamic range image. Right now we're ignoring it.
  bool double_width;

  if (8UL * counts->getU32() >= 2UL * 16UL * width * height) {
    bps = 16;
    double_width = true;
  } else if (8UL * counts->getU32() >= 2UL * 14UL * width * height) {
    bps = 14;
    double_width = true;
  } else if (8UL * counts->getU32() >= 2UL * 12UL * width * height) {
    bps = 12;
    double_width = true;
  } else if (8UL * counts->getU32() >= 16UL * width * height) {
    bps = 16;
    double_width = false;
  } else if (8UL * counts->getU32() >= 14UL * width * height) {
    bps = 14;
    double_width = false;
  } else if (8UL * counts->getU32() >= 12UL * width * height) {
    bps = 12;
    double_width = false;
  } else if (isCompressed) {
    bps = 16;
    double_width = false;
  } else {
    ThrowRDE("Can not detect bitdepth. StripByteCounts = %u, width = %u, "
             "height = %u",
             counts->getU32(), width, height);
  }

  double_width = hints.has("double_width_unpacked");
  const uint32 real_width = double_width ? 2U * width : width;

  mRaw->dim = iPoint2D(real_width, height);
  mRaw->createData();

  UncompressedDecompressor u(input, mRaw);

  iPoint2D pos(0, 0);

  if (isCompressed) {
    mRaw->metadata.mode = "compressed";

    FujiDecompressor fujiDecompress(input, mRaw, 0);
    fujiDecompress.fuji_compressed_load_raw();
  } else if (double_width) {
    u.decodeRawUnpacked<16, little>(width * 2, height);
  } else if (input.isInNativeByteOrder() == (getHostEndianness() == big)) {
    u.decodeRawUnpacked<16, big>(width, height);
  } else {
    if (hints.has("jpeg32_bitorder")) {
      u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps,
                            BitOrder_MSB32);
    } else {
      u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps, BitOrder_LSB);
    }
  }

  return mRaw;
}

void RafDecoder::checkSupportInternal(const CameraMetaData* meta) {
  if (!this->checkCameraSupported(meta, mRootIFD->getID(), ""))
    ThrowRDE("Unknown camera. Will not guess.");

  if (isCompressed()) {
    mRaw->metadata.mode = "compressed";

    auto id = mRootIFD->getID();
    const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
    if (!cam)
      ThrowRDE("Couldn't find camera %s %s", id.make.c_str(), id.model.c_str());

    mRaw->cfa = cam->cfa;
  }
}

void RafDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
  int iso = 0;
  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
  mRaw->metadata.isoSpeed = iso;

  // This is where we'd normally call setMetaData but since we may still need
  // to rotate the image for SuperCCD cameras we do everything ourselves
  auto id = mRootIFD->getID();
  const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
  if (!cam)
    ThrowRDE("Couldn't find camera");

  assert(cam != nullptr);

  iPoint2D new_size(mRaw->dim);
  iPoint2D crop_offset = iPoint2D(0,0);

  if (applyCrop) {
    new_size = cam->cropSize;
    crop_offset = cam->cropPos;
    bool double_width = hints.has("double_width_unpacked");
    // If crop size is negative, use relative cropping
    if (new_size.x <= 0)
      new_size.x = mRaw->dim.x / (double_width ? 2 : 1) - cam->cropPos.x + new_size.x;
    else
      new_size.x /= (double_width ? 2 : 1);
    if (new_size.y <= 0)
      new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
  }

  bool rotate = hints.has("fuji_rotate");
  rotate = rotate && fujiRotate;

  // Rotate 45 degrees - could be multithreaded.
  if (rotate && !this->uncorrectedRawValues) {
    // Calculate the 45 degree rotated size;
    uint32 rotatedsize;
    uint32 rotationPos;
    if (alt_layout) {
      rotatedsize = new_size.y+new_size.x/2;
      rotationPos = new_size.x/2 - 1;
    }
    else {
      rotatedsize = new_size.x+new_size.y/2;
      rotationPos = new_size.x - 1;
    }

    iPoint2D final_size(rotatedsize, rotatedsize-1);
    RawImage rotated = RawImage::create(final_size, TYPE_USHORT16, 1);
    rotated->clearArea(iRectangle2D(iPoint2D(0,0), rotated->dim));
    rotated->metadata = mRaw->metadata;
    rotated->metadata.fujiRotationPos = rotationPos;

    int dest_pitch = static_cast<int>(rotated->pitch) / 2;
    auto* dst = reinterpret_cast<ushort16*>(rotated->getData(0, 0));

    for (int y = 0; y < new_size.y; y++) {
      auto* src = reinterpret_cast<ushort16*>(
          mRaw->getData(crop_offset.x, crop_offset.y + y));
      for (int x = 0; x < new_size.x; x++) {
        int h;
        int w;
        if (alt_layout) { // Swapped x and y
          h = rotatedsize - (new_size.y + 1 - y + (x >> 1));
          w = ((x+1) >> 1) + y;
        } else {
          h = new_size.x - 1 - x + (y >> 1);
          w = ((y+1) >> 1) + x;
        }
        if (h < rotated->dim.y && w < rotated->dim.x)
          dst[w + h * dest_pitch] = src[x];
        else
          ThrowRDE("Trying to write out of bounds");
      }
    }
    mRaw = rotated;
  } else if (applyCrop) {
    mRaw->subFrame(iRectangle2D(crop_offset, new_size));
  }

  const CameraSensorInfo *sensor = cam->getSensorInfo(iso);
  mRaw->blackLevel = sensor->mBlackLevel;

  // at least the (bayer sensor) X100 comes with a tag like this:
  if (mRootIFD->hasEntryRecursive(FUJI_BLACKLEVEL)) {
    TiffEntry* sep_black = mRootIFD->getEntryRecursive(FUJI_BLACKLEVEL);
    if (sep_black->count == 4)
    {
      for(int k=0;k<4;k++)
        mRaw->blackLevelSeparate[k] = sep_black->getU32(k);
    } else if (sep_black->count == 36) {
      for (int& k : mRaw->blackLevelSeparate)
        k = 0;

      for (int y = 0; y < 6; y++) {
        for (int x = 0; x < 6; x++)
          mRaw->blackLevelSeparate[2 * (y % 2) + (x % 2)] +=
              sep_black->getU32(6 * y + x);
      }

      for (int& k : mRaw->blackLevelSeparate)
        k /= 9;
    }
  }

  mRaw->whitePoint = sensor->mWhiteLevel;
  mRaw->blackAreas = cam->blackAreas;
  mRaw->cfa = cam->cfa;
  mRaw->metadata.canonical_make = cam->canonical_make;
  mRaw->metadata.canonical_model = cam->canonical_model;
  mRaw->metadata.canonical_alias = cam->canonical_alias;
  mRaw->metadata.canonical_id = cam->canonical_id;
  mRaw->metadata.make = id.make;
  mRaw->metadata.model = id.model;

  if (mRootIFD->hasEntryRecursive(FUJI_WB_GRBLEVELS)) {
    TiffEntry *wb = mRootIFD->getEntryRecursive(FUJI_WB_GRBLEVELS);
    if (wb->count == 3) {
      mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
      mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
      mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
    }
  } else if (mRootIFD->hasEntryRecursive(FUJIOLDWB)) {
    TiffEntry *wb = mRootIFD->getEntryRecursive(FUJIOLDWB);
    if (wb->count == 8) {
      mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
      mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
      mRaw->metadata.wbCoeffs[2] = wb->getFloat(3);
    }
  }
}

int RafDecoder::isCompressed() {
  auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
  uint32 height = 0;
  uint32 width = 0;

  if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
    height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
    width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
  } else if (raw->hasEntry(IMAGEWIDTH)) {
    TiffEntry* e = raw->getEntry(IMAGEWIDTH);
    height = e->getU16(0);
    width = e->getU16(1);
  } else
    ThrowRDE("Unable to locate image size");

  uint32 count = raw->getEntry(FUJI_STRIPBYTECOUNTS)->getU32();

  return count * 8 / (width * height) < 10;
}

} // namespace rawspeed
<commit_msg>RafDecoder::decodeRawInternal(): reorganize stuff a bit.<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real

    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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decoders/RafDecoder.h"
#include "common/Common.h"                          // for uint32, ushort16
#include "common/Point.h"                           // for iPoint2D, iRecta...
#include "decoders/RawDecoderException.h"           // for RawDecoderExcept...
#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
#include "decompressors/FujiDecompressor.h"
#include "io/Buffer.h"                              // for Buffer
#include "io/ByteStream.h"                          // for ByteStream
#include "io/Endianness.h"                          // for getHostEndianness
#include "metadata/BlackArea.h"                     // for BlackArea
#include "metadata/Camera.h"                        // for Camera, Hints
#include "metadata/CameraMetaData.h"                // for CameraMetaData
#include "metadata/CameraSensorInfo.h"              // for CameraSensorInfo
#include "metadata/ColorFilterArray.h"              // for ColorFilterArray
#include "tiff/TiffEntry.h"                         // for TiffEntry
#include "tiff/TiffIFD.h"                           // for TiffRootIFD, Tif...
#include "tiff/TiffTag.h"                           // for TiffTag::FUJIOLDWB
#include <cassert>                                  // for assert
#include <cstdio>                                   // for size_t
#include <cstring>                                  // for memcmp
#include <memory>                                   // for unique_ptr, allo...
#include <string>                                   // for string
#include <vector>                                   // for vector

namespace rawspeed {

bool RafDecoder::isRAF(const Buffer* input) {
  static const char magic[] = "FUJIFILMCCD-RAW ";
  static const size_t magic_size = sizeof(magic) - 1; // excluding \0
  const unsigned char* data = input->getData(0, magic_size);
  return 0 == memcmp(&data[0], magic, magic_size);
}

bool RafDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
                                      const Buffer* file) {
  const auto id = rootIFD->getID();
  const std::string& make = id.make;

  // FIXME: magic

  return make == "FUJIFILM";
}

RawImage RafDecoder::decodeRawInternal() {
  auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
  uint32 height = 0;
  uint32 width = 0;
  bool isCompressed = false;

  if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
    height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
    width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
  } else if (raw->hasEntry(IMAGEWIDTH)) {
    TiffEntry *e = raw->getEntry(IMAGEWIDTH);
    height = e->getU16(0);
    width = e->getU16(1);
  } else
    ThrowRDE("Unable to locate image size");

  if (height < 1 || width < 1)
    ThrowRDE("Bad image dimensions");

  if (raw->hasEntry(FUJI_LAYOUT)) {
    TiffEntry *e = raw->getEntry(FUJI_LAYOUT);
    alt_layout = !(e->getByte(0) >> 7);
  }

  TiffEntry *offsets = raw->getEntry(FUJI_STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(FUJI_STRIPBYTECOUNTS);

  if (offsets->count != 1 || counts->count != 1)
    ThrowRDE("Multiple Strips found: %u %u", offsets->count, counts->count);

  if (counts->getU32() * 8 / (width * height) < 10)
    isCompressed = true;

  ByteStream input(offsets->getRootIfdData());
  input = input.getSubStream(offsets->getU32(), counts->getU32());

  // x-trans sensors report 14bpp, but data isn't packed
  // thus, unless someone has any better ideas, let's autodetect it.
  int bps;

  // Some fuji SuperCCD cameras include a second raw image next to the first one
  // that is identical but darker to the first. The two combined can produce
  // a higher dynamic range image. Right now we're ignoring it.
  bool double_width;

  if (8UL * counts->getU32() >= 2UL * 16UL * width * height) {
    bps = 16;
    double_width = true;
  } else if (8UL * counts->getU32() >= 2UL * 14UL * width * height) {
    bps = 14;
    double_width = true;
  } else if (8UL * counts->getU32() >= 2UL * 12UL * width * height) {
    bps = 12;
    double_width = true;
  } else if (8UL * counts->getU32() >= 16UL * width * height) {
    bps = 16;
    double_width = false;
  } else if (8UL * counts->getU32() >= 14UL * width * height) {
    bps = 14;
    double_width = false;
  } else if (8UL * counts->getU32() >= 12UL * width * height) {
    bps = 12;
    double_width = false;
  } else if (isCompressed) {
    bps = 16;
    double_width = false;
  } else {
    ThrowRDE("Can not detect bitdepth. StripByteCounts = %u, width = %u, "
             "height = %u",
             counts->getU32(), width, height);
  }

  double_width = hints.has("double_width_unpacked");
  const uint32 real_width = double_width ? 2U * width : width;

  mRaw->dim = iPoint2D(real_width, height);
  mRaw->createData();

  if (isCompressed) {
    mRaw->metadata.mode = "compressed";

    FujiDecompressor fujiDecompress(input.getBuffer(input.getSize()), mRaw, 0);
    fujiDecompress.fuji_compressed_load_raw();
  } else {
    UncompressedDecompressor u(input, mRaw);

    if (double_width) {
      u.decodeRawUnpacked<16, little>(width * 2, height);
    } else if (input.isInNativeByteOrder() == (getHostEndianness() == big)) {
      u.decodeRawUnpacked<16, big>(width, height);
    } else {
      iPoint2D pos(0, 0);
      if (hints.has("jpeg32_bitorder")) {
        u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps,
                              BitOrder_MSB32);
      } else {
        u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps,
                              BitOrder_LSB);
      }
    }
  }

  return mRaw;
}

void RafDecoder::checkSupportInternal(const CameraMetaData* meta) {
  if (!this->checkCameraSupported(meta, mRootIFD->getID(), ""))
    ThrowRDE("Unknown camera. Will not guess.");

  if (isCompressed()) {
    mRaw->metadata.mode = "compressed";

    auto id = mRootIFD->getID();
    const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
    if (!cam)
      ThrowRDE("Couldn't find camera %s %s", id.make.c_str(), id.model.c_str());

    mRaw->cfa = cam->cfa;
  }
}

void RafDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
  int iso = 0;
  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
  mRaw->metadata.isoSpeed = iso;

  // This is where we'd normally call setMetaData but since we may still need
  // to rotate the image for SuperCCD cameras we do everything ourselves
  auto id = mRootIFD->getID();
  const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
  if (!cam)
    ThrowRDE("Couldn't find camera");

  assert(cam != nullptr);

  iPoint2D new_size(mRaw->dim);
  iPoint2D crop_offset = iPoint2D(0,0);

  if (applyCrop) {
    new_size = cam->cropSize;
    crop_offset = cam->cropPos;
    bool double_width = hints.has("double_width_unpacked");
    // If crop size is negative, use relative cropping
    if (new_size.x <= 0)
      new_size.x = mRaw->dim.x / (double_width ? 2 : 1) - cam->cropPos.x + new_size.x;
    else
      new_size.x /= (double_width ? 2 : 1);
    if (new_size.y <= 0)
      new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
  }

  bool rotate = hints.has("fuji_rotate");
  rotate = rotate && fujiRotate;

  // Rotate 45 degrees - could be multithreaded.
  if (rotate && !this->uncorrectedRawValues) {
    // Calculate the 45 degree rotated size;
    uint32 rotatedsize;
    uint32 rotationPos;
    if (alt_layout) {
      rotatedsize = new_size.y+new_size.x/2;
      rotationPos = new_size.x/2 - 1;
    }
    else {
      rotatedsize = new_size.x+new_size.y/2;
      rotationPos = new_size.x - 1;
    }

    iPoint2D final_size(rotatedsize, rotatedsize-1);
    RawImage rotated = RawImage::create(final_size, TYPE_USHORT16, 1);
    rotated->clearArea(iRectangle2D(iPoint2D(0,0), rotated->dim));
    rotated->metadata = mRaw->metadata;
    rotated->metadata.fujiRotationPos = rotationPos;

    int dest_pitch = static_cast<int>(rotated->pitch) / 2;
    auto* dst = reinterpret_cast<ushort16*>(rotated->getData(0, 0));

    for (int y = 0; y < new_size.y; y++) {
      auto* src = reinterpret_cast<ushort16*>(
          mRaw->getData(crop_offset.x, crop_offset.y + y));
      for (int x = 0; x < new_size.x; x++) {
        int h;
        int w;
        if (alt_layout) { // Swapped x and y
          h = rotatedsize - (new_size.y + 1 - y + (x >> 1));
          w = ((x+1) >> 1) + y;
        } else {
          h = new_size.x - 1 - x + (y >> 1);
          w = ((y+1) >> 1) + x;
        }
        if (h < rotated->dim.y && w < rotated->dim.x)
          dst[w + h * dest_pitch] = src[x];
        else
          ThrowRDE("Trying to write out of bounds");
      }
    }
    mRaw = rotated;
  } else if (applyCrop) {
    mRaw->subFrame(iRectangle2D(crop_offset, new_size));
  }

  const CameraSensorInfo *sensor = cam->getSensorInfo(iso);
  mRaw->blackLevel = sensor->mBlackLevel;

  // at least the (bayer sensor) X100 comes with a tag like this:
  if (mRootIFD->hasEntryRecursive(FUJI_BLACKLEVEL)) {
    TiffEntry* sep_black = mRootIFD->getEntryRecursive(FUJI_BLACKLEVEL);
    if (sep_black->count == 4)
    {
      for(int k=0;k<4;k++)
        mRaw->blackLevelSeparate[k] = sep_black->getU32(k);
    } else if (sep_black->count == 36) {
      for (int& k : mRaw->blackLevelSeparate)
        k = 0;

      for (int y = 0; y < 6; y++) {
        for (int x = 0; x < 6; x++)
          mRaw->blackLevelSeparate[2 * (y % 2) + (x % 2)] +=
              sep_black->getU32(6 * y + x);
      }

      for (int& k : mRaw->blackLevelSeparate)
        k /= 9;
    }
  }

  mRaw->whitePoint = sensor->mWhiteLevel;
  mRaw->blackAreas = cam->blackAreas;
  mRaw->cfa = cam->cfa;
  mRaw->metadata.canonical_make = cam->canonical_make;
  mRaw->metadata.canonical_model = cam->canonical_model;
  mRaw->metadata.canonical_alias = cam->canonical_alias;
  mRaw->metadata.canonical_id = cam->canonical_id;
  mRaw->metadata.make = id.make;
  mRaw->metadata.model = id.model;

  if (mRootIFD->hasEntryRecursive(FUJI_WB_GRBLEVELS)) {
    TiffEntry *wb = mRootIFD->getEntryRecursive(FUJI_WB_GRBLEVELS);
    if (wb->count == 3) {
      mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
      mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
      mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
    }
  } else if (mRootIFD->hasEntryRecursive(FUJIOLDWB)) {
    TiffEntry *wb = mRootIFD->getEntryRecursive(FUJIOLDWB);
    if (wb->count == 8) {
      mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
      mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
      mRaw->metadata.wbCoeffs[2] = wb->getFloat(3);
    }
  }
}

int RafDecoder::isCompressed() {
  auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
  uint32 height = 0;
  uint32 width = 0;

  if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
    height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
    width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
  } else if (raw->hasEntry(IMAGEWIDTH)) {
    TiffEntry* e = raw->getEntry(IMAGEWIDTH);
    height = e->getU16(0);
    width = e->getU16(1);
  } else
    ThrowRDE("Unable to locate image size");

  uint32 count = raw->getEntry(FUJI_STRIPBYTECOUNTS)->getU32();

  return count * 8 / (width * height) < 10;
}

} // namespace rawspeed
<|endoftext|>