<commit_before>#ifndef STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP
#define STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/prim/err/check_matching_dims.hpp>
#include <stan/math/rev/core/callback_vari.hpp>
#include <stan/math/prim/fun/constants.hpp>

namespace stan {
namespace math {

/**
 * Addition operator for variables (C++).
 *
 * The partial derivatives are defined by
 *
 * \f$\frac{\partial}{\partial x} (x+y) = 1\f$, and
 *
 * \f$\frac{\partial}{\partial y} (x+y) = 1\f$.
 *
 *
   \f[
   \mbox{operator+}(x, y) =
   \begin{cases}
     x+y & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator+}(x, y)}{\partial x} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator+}(x, y)}{\partial y} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
inline var operator+(const var& a, const var& b) {
  return make_callback_vari(a.vi_->val_ + b.vi_->val_,
                            [avi = a.vi_, bvi = b.vi_](const auto& vi) mutable {
                              if (unlikely(std::isnan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                                bvi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Addition operator for variable and scalar (C++).
 *
 * The derivative with respect to the variable is
 *
 * \f$\frac{d}{dx} (x + c) = 1\f$.
 *
 * @tparam Arith An arithmetic type
 * @param a First variable operand.
 * @param b Second scalar operand.
 * @return Result of adding variable and scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator+(const var& a, Arith b) {
  if (unlikely(b == 0.0)) {
    return a;
  }
  return make_callback_vari(a.vi_->val_ + b,
                            [avi = a.vi_, b](const auto& vi) mutable {
                              if (unlikely(std::isnan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Addition operator for scalar and variable (C++).
 *
 * The derivative with respect to the variable is
 *
 * \f$\frac{d}{dy} (c + y) = 1\f$.
 *
 * @tparam Arith An arithmetic type
 * @param a First scalar operand.
 * @param b Second variable operand.
 * @return Result of adding variable and scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator+(Arith a, const var& b) {
  return b + a;  // by symmetry
}

/**
 * Addition operator for matrix variables (C++).
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_all_rev_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto add(const VarMat1& a, const VarMat2& b) {
  check_matching_dims("add", "a", a, "b", b);
  using op_ret_type = decltype(a.val() + b.val());
  using ret_type = promote_var_matrix_t<op_ret_type, VarMat1, VarMat2>;
  arena_t<VarMat1> arena_a(a);
  arena_t<VarMat2> arena_b(b);
  arena_t<ret_type> ret(arena_a.val() + arena_b.val());
  reverse_pass_callback([ret, arena_a, arena_b]() mutable {
    for (Eigen::Index i = 0; i < ret.size(); ++i) {
      const auto ref_adj = ret.adj().coeffRef(i);
      arena_a.adj().coeffRef(i) += ref_adj;
      arena_b.adj().coeffRef(i) += ref_adj;
    }
  });
  return ret_type(ret);
}

/**
 * Addition operator for a matrix variable and arithmetic (C++).
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const VarMat& a, const Arith& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("add", "a", a, "b", b);
  }
  using op_ret_type
      = decltype((a.val().array() + as_array_or_scalar(b)).matrix());
  using ret_type = promote_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_a(a);
  arena_t<ret_type> ret(arena_a.val().array() + as_array_or_scalar(b));
  reverse_pass_callback(
      [ret, arena_a]() mutable { arena_a.adj() += ret.adj_op(); });
  return ret_type(ret);
}

/**
 * Addition operator for an arithmetic type and matrix variable (C++).
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const Arith& a, const VarMat& b) {
  return add(b, a);
}

/**
 * Addition operator for an arithmetic matrix and variable (C++).
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename EigMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr>
inline auto add(const Var& a, const EigMat& b) {
  using ret_type = promote_scalar_t<var, EigMat>;
  arena_t<ret_type> ret(a.val() + b.array());
  reverse_pass_callback([ret, a]() mutable { a.adj() += ret.adj().sum(); });
  return ret_type(ret);
}

/**
 * Addition operator for a variable and arithmetic matrix (C++).
 *
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename EigMat, typename Var,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto add(const EigMat& a, const Var& b) {
  return add(b, a);
}

/**
 * Addition operator for a variable and variable matrix (C++).
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const Var& a, const VarMat& b) {
  arena_t<VarMat> arena_b(b);
  arena_t<VarMat> ret(a.val() + arena_b.val().array());
  reverse_pass_callback([ret, a, arena_b]() mutable {
    for (Eigen::Index i = 0; i < arena_b.size(); ++i) {
      const auto ret_adj = ret.adj().coeffRef(i);
      a.adj() += ret_adj;
      arena_b.adj().coeffRef(i) += ret_adj;
    }
  });
  return plain_type_t<VarMat>(ret);
}

/**
 * Addition operator for a variable matrix and variable (C++).
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const VarMat& a, const Var& b) {
  return add(b, a);
}

template <typename T1, typename T2,
          require_any_var_vt<std::is_arithmetic, T1, T2>* = nullptr,
          require_any_arithmetic_t<T1, T2>* = nullptr>
inline auto add(const T1& a, const T2& b) {
  return a + b;
}

template <typename T1, typename T2,
          require_all_var_vt<std::is_arithmetic, T1, T2>* = nullptr>
inline auto add(const T1& a, const T2& b) {
  return a + b;
}

/**
 * Addition operator for matrix variables (C++).
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_any_var_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto operator+(const VarMat1& a, const VarMat2& b) {
  return add(a, b);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>kickoff jenkins<commit_after>#ifndef STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP
#define STAN_MATH_REV_CORE_OPERATOR_ADDITION_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/prim/err/check_matching_dims.hpp>
#include <stan/math/rev/core/callback_vari.hpp>
#include <stan/math/prim/fun/constants.hpp>

namespace stan {
namespace math {

/**
 * Addition operator for variables (C++).
 *
 * The partial derivatives are defined by
 *
 * \f$\frac{\partial}{\partial x} (x+y) = 1\f$, and
 *
 * \f$\frac{\partial}{\partial y} (x+y) = 1\f$.
 *
 *
   \f[
   \mbox{operator+}(x, y) =
   \begin{cases}
     x+y & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator+}(x, y)}{\partial x} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator+}(x, y)}{\partial y} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
inline var operator+(const var& a, const var& b) {
  return make_callback_vari(a.vi_->val_ + b.vi_->val_,
                            [avi = a.vi_, bvi = b.vi_](const auto& vi) mutable {
                              if (unlikely(std::isnan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                                bvi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Addition operator for variable and scalar (C++).
 *
 * The derivative with respect to the variable is
 *
 * \f$\frac{d}{dx} (x + c) = 1\f$.
 *
 * @tparam Arith An arithmetic type
 * @param a First variable operand.
 * @param b Second scalar operand.
 * @return Result of adding variable and scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator+(const var& a, Arith b) {
  if (unlikely(b == 0.0)) {
    return a;
  }
  return make_callback_vari(a.vi_->val_ + b,
                            [avi = a.vi_, b](const auto& vi) mutable {
                              if (unlikely(std::isnan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Addition operator for scalar and variable (C++).
 *
 * The derivative with respect to the variable is
 *
 * \f$\frac{d}{dy} (c + y) = 1\f$.
 *
 * @tparam Arith An arithmetic type
 * @param a First scalar operand.
 * @param b Second variable operand.
 * @return Result of adding variable and scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator+(Arith a, const var& b) {
  return b + a;  // by symmetry
}

/**
 * Addition operator for matrix variables (C++).
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_all_rev_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto add(const VarMat1& a, const VarMat2& b) {
  check_matching_dims("add", "a", a, "b", b);
  using op_ret_type = decltype(a.val() + b.val());
  using ret_type = promote_var_matrix_t<op_ret_type, VarMat1, VarMat2>;
  arena_t<VarMat1> arena_a(a);
  arena_t<VarMat2> arena_b(b);
  arena_t<ret_type> ret(arena_a.val() + arena_b.val());
  reverse_pass_callback([ret, arena_a, arena_b]() mutable {
    for (Eigen::Index i = 0; i < ret.size(); ++i) {
      const auto ref_adj = ret.adj().coeffRef(i);
      arena_a.adj().coeffRef(i) += ref_adj;
      arena_b.adj().coeffRef(i) += ref_adj;
    }
  });
  return ret_type(ret);
}

/**
 * Addition operator for a matrix variable and arithmetic (C++).
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const VarMat& a, const Arith& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("add", "a", a, "b", b);
  }
  using op_ret_type
      = decltype((a.val().array() + as_array_or_scalar(b)).matrix());
  using ret_type = promote_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_a(a);
  arena_t<ret_type> ret(arena_a.val().array() + as_array_or_scalar(b));
  reverse_pass_callback(
      [ret, arena_a]() mutable { arena_a.adj() += ret.adj_op(); });
  return ret_type(ret);
}

/**
 * Addition operator for an arithmetic type and matrix variable (C++).
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const Arith& a, const VarMat& b) {
  return add(b, a);
}

/**
 * Addition operator for an arithmetic matrix and variable (C++).
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename EigMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr>
inline auto add(const Var& a, const EigMat& b) {
  using ret_type = promote_scalar_t<var, EigMat>;
  arena_t<ret_type> ret(a.val() + b.array());
  reverse_pass_callback([ret, a]() mutable { a.adj() += ret.adj().sum(); });
  return ret_type(ret);
}

/**
 * Addition operator for a variable and arithmetic matrix (C++).
 *
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename EigMat, typename Var,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto add(const EigMat& a, const Var& b) {
  return add(b, a);
}

/**
 * Addition operator for a variable and variable matrix (C++).
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const Var& a, const VarMat& b) {
  arena_t<VarMat> arena_b(b);
  arena_t<VarMat> ret(a.val() + arena_b.val().array());
  reverse_pass_callback([ret, a, arena_b]() mutable {
    for (Eigen::Index i = 0; i < arena_b.size(); ++i) {
      const auto ret_adj = ret.adj().coeffRef(i);
      a.adj() += ret_adj;
      arena_b.adj().coeffRef(i) += ret_adj;
    }
  });
  return plain_type_t<VarMat>(ret);
}

/**
 * Addition operator for a variable matrix and variable (C++).
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto add(const VarMat& a, const Var& b) {
  return add(b, a);
}

template <typename T1, typename T2,
          require_any_var_vt<std::is_arithmetic, T1, T2>* = nullptr,
          require_any_arithmetic_t<T1, T2>* = nullptr>
inline auto add(const T1& a, const T2& b) {
  return a + b;
}

template <typename T1, typename T2,
          require_all_var_vt<std::is_arithmetic, T1, T2>* = nullptr>
inline auto add(const T1& a, const T2& b) {
  return a + b;
}

/**
 * Addition operator for matrix variables.
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_any_var_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto operator+(const VarMat1& a, const VarMat2& b) {
  return add(a, b);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
Licensed Materials - Property of IBM
DB2 Storage Engine Enablement
Copyright IBM Corporation 2007,2008
All rights reserved

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
 (a) Redistributions of source code must retain this list of conditions, the
     copyright notice in section {d} below, and the disclaimer following this
     list of conditions.
 (b) Redistributions in binary form must reproduce this list of conditions, the
     copyright notice in section (d) below, and the disclaimer following this
     list of conditions, in the documentation and/or other materials provided
     with the distribution.
 (c) The name of IBM may not be used to endorse or promote products derived from
     this software without specific prior written permission.
 (d) The text of the required copyright notice is:
       Licensed Materials - Property of IBM
       DB2 Storage Engine Enablement
       Copyright IBM Corporation 2007,2008
       All rights reserved

THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "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 IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "db2i_collationSupport.h"
#include "db2i_errors.h"

/*
  The following arrays define a mapping between MySQL collation names and
  corresponding IBM i sort sequences. The mapping is a 1-to-1 correlation
  between corresponding array slots but is incomplete without case-sensitivity
  markers dynamically added to the mySqlSortSequence names.
*/
#define MAX_COLLATION 89
static const char* mySQLCollation[MAX_COLLATION] =
{
    {"ascii_general"},
    {"ascii"},
    {"big5_chinese"},
    {"big5"},
    {"cp1250_croatian"},
    {"cp1250_czech"},
    {"cp1250_general"},
    {"cp1250_polish"},
    {"cp1250"},
    {"cp1251_bulgarian"},
    {"cp1251_general"},
    {"cp1251"},
    {"cp1256_general"},
    {"cp1256"},
    {"cp850_general"},
    {"cp850"},
    {"cp852_general"},
    {"cp852"},
    {"cp932_japanese"},
    {"cp932"},
    {"euckr_korean"},
    {"euckr"},
    {"gb2312_chinese"},
    {"gb2312"},
    {"gbk_chinese"},
    {"gbk"},
    {"greek_general"},
    {"greek"},
    {"hebrew_general"},
    {"hebrew"},
    {"latin1_danish"},
    {"latin1_general"},
    {"latin1_german1"},
    {"latin1_spanish"},
    {"latin1_swedish"},
    {"latin1"},
    {"latin2_croatian"},
    {"latin2_czech"},
    {"latin2_general"},
    {"latin2_hungarian"},
    {"latin2"},
    {"latin5_turkish"},
    {"latin5"},
    {"macce_general"},
    {"macce"},
    {"sjis_japanese"},
    {"sjis"},
    {"tis620_thai"},
    {"tis620"},
    {"ucs2_czech"},
    {"ucs2_danish"},
    {"ucs2_esperanto"},
    {"ucs2_estonian"},
    {"ucs2_general"},
    {"ucs2_hungarian"},
    {"ucs2_icelandic"},
    {"ucs2_latvian"},
    {"ucs2_lithuanian"},
    {"ucs2_persian"},
    {"ucs2_polish"},
    {"ucs2_romanian"},
    {"ucs2_slovak"},
    {"ucs2_slovenian"},
    {"ucs2_spanish"},
    {"ucs2_spanish2"},
    {"ucs2_turkish"},
    {"ucs2_unicode"},
    {"ucs2"},
    {"ujis_japanese"},
    {"ujis"},
    {"utf8_czech"},
    {"utf8_danish"},
    {"utf8_esperanto"},
    {"utf8_estonian"},
    {"utf8_general"},
    {"utf8_hungarian"},
    {"utf8_icelandic"},
    {"utf8_latvian"},
    {"utf8_lithuanian"},
    {"utf8_persian"},
    {"utf8_polish"},
    {"utf8_romanian"},
    {"utf8_slovak"},
    {"utf8_slovenian"},
    {"utf8_spanish"},
    {"utf8_spanish2"},
    {"utf8_turkish"},
    {"utf8_unicode"},
    {"utf8"}
};

static const char* mySqlSortSequence[MAX_COLLATION] =
{
    {"QALA101F4"},
    {"QBLA101F4"},
    {"QACHT04B0"},
    {"QBCHT04B0"},
    {"QALA20481"},
    {"QBLA20481"},
    {"QCLA20481"},
    {"QDLA20481"},
    {"QELA20481"},
    {"QACYR0401"},
    {"QBCYR0401"},
    {"QCCYR0401"},
    {"QAARA01A4"},
    {"QBARA01A4"},
    {"QCLA101F4"},
    {"QDLA101F4"},
    {"QALA20366"},
    {"QBLA20366"},
    {"QAJPN04B0"},
    {"QBJPN04B0"},
    {"QAKOR04B0"},
    {"QBKOR04B0"},
    {"QACHS04B0"},
    {"QBCHS04B0"},
    {"QCCHS04B0"},
    {"QDCHS04B0"},
    {"QAELL036B"},
    {"QBELL036B"},
    {"QAHEB01A8"},
    {"QBHEB01A8"},
    {"QALA1047C"},
    {"QBLA1047C"},
    {"QCLA1047C"},
    {"QDLA1047C"},
    {"QELA1047C"},
    {"QFLA1047C"},
    {"QCLA20366"},
    {"QDLA20366"},
    {"QELA20366"},
    {"QFLA20366"},
    {"QGLA20366"},
    {"QATRK0402"},
    {"QBTRK0402"},
    {"QHLA20366"},
    {"QILA20366"},
    {"QCJPN04B0"},
    {"QDJPN04B0"},
    {"QATHA0346"},
    {"QBTHA0346"},
    {"ACS"},
    {"ADA"},
    {"AEO"},
    {"AET"},
    {"QAUCS04B0"},
    {"AHU"},
    {"AIS"},
    {"ALV"},
    {"ALT"},
    {"AFA"},
    {"APL"},
    {"ARO"},
    {"ASK"},
    {"ASL"},
    {"AES"},
    {"AES__TRADIT"},
    {"ATR"},
    {"AEN"},
    {"*HEX"},
    {"QEJPN04B0"},
    {"QFJPN04B0"},
    {"ACS"},
    {"ADA"},
    {"AEO"},
    {"AET"},
    {"QAUCS04B0"},
    {"AHU"},
    {"AIS"},
    {"ALV"},
    {"ALT"},
    {"AFA"},
    {"APL"},
    {"ARO"},
    {"ASK"},
    {"ASL"},
    {"AES"},
    {"AES__TRADIT"},
    {"ATR"},
    {"AEN"},
    {"*HEX"}
};

/**
  Get the IBM i sort sequence that corresponds to the given MySQL collation.

  @param fieldCharSet  The collated character set
  @param[out] rtnSortSequence  The corresponding sort sequence

  @return  0 if successful. Failure otherwise
*/
static int32 getAssociatedSortSequence(const CHARSET_INFO *fieldCharSet, const char** rtnSortSequence)
{
  DBUG_ENTER("ha_ibmdb2i::getAssociatedSortSequence");

  if (strcmp(fieldCharSet->csname,"binary") != 0)
  {
    int collationSearchLen = strlen(fieldCharSet->name);
    if (fieldCharSet->state & MY_CS_BINSORT)
      collationSearchLen -= 4;
    else
      collationSearchLen -= 3;

    uint16 loopCnt = 0;
    for (loopCnt; loopCnt < MAX_COLLATION; ++loopCnt)
    {
      if ((strlen(mySQLCollation[loopCnt]) == collationSearchLen) &&
          (strncmp((char*)mySQLCollation[loopCnt], fieldCharSet->name, collationSearchLen) == 0))
        break;
    }
    if (loopCnt == MAX_COLLATION)  // Did not find associated sort sequence
    {
      getErrTxt(DB2I_ERR_SRTSEQ);
      DBUG_RETURN(DB2I_ERR_SRTSEQ);
    }
    *rtnSortSequence = mySqlSortSequence[loopCnt];
  }

  DBUG_RETURN(0);
}

/**
  Update sort sequence information for a key.

  This function accumulates information about a key as it is called for each
  field composing the key. The caller should invoke the function for each field
  and (with the exception of the charset parm) preserve the values for the
  parms across invocations, until a particular key has been evaluated. Once
  the last field in the key has been evaluated, the fileSortSequence and
  fileSortSequenceLibrary parms will contain the correct information for
  creating the corresponding DB2 key.

  @param charset  The character set under consideration
  @param[in, out] fileSortSequenceType  The type of the current key's sort seq
  @param[in, out] fileSortSequence  The IBM i identifier for the DB2 sort sequence
                                    that corresponds

  @return  0 if successful. Failure otherwise
*/
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
                                   char* fileSortSequenceType,
                                   char* fileSortSequence,
                                   char* fileSortSequenceLibrary)
{
  DBUG_ENTER("ha_ibmdb2i::updateAssociatedSortSequence");
  DBUG_ASSERT(charset);
  if (strcmp(charset->csname,"binary") != 0)
  {
    char newSortSequence[11] = "";
    char newSortSequenceType = ' ';
    const char* foundSortSequence;
    int rc = getAssociatedSortSequence(charset, &foundSortSequence);
    if (rc) DBUG_RETURN (rc);
    switch(foundSortSequence[0])
    {
      case '*': // Binary
        strcat(newSortSequence,foundSortSequence);
        newSortSequenceType = 'B';
        break;
      case 'Q': // Non-ICU sort sequence
        strcat(newSortSequence,foundSortSequence);
        if ((charset->state & MY_CS_BINSORT) != 0)
        {
          strcat(newSortSequence,"U");
        }
        else if ((charset->state & MY_CS_CSSORT) != 0)
        {
          strcat(newSortSequence,"U");
        }
        else
        {
          strcat(newSortSequence,"S");
        }
        newSortSequenceType = 'N';
        break;
      default: // ICU sort sequence
	{
          if ((charset->state & MY_CS_CSSORT) == 0)
          {
            if (osVersion.v >= 6)
              strcat(newSortSequence,"I34"); // ICU 3.4
            else
              strcat(newSortSequence,"I26"); // ICU 2.6.1
          }
          strcat(newSortSequence,foundSortSequence);
          newSortSequenceType = 'I';
        }
        break;
    }
    if (*fileSortSequenceType == ' ') // If no sort sequence has been set yet
    {
      // Set associated sort sequence
      strcpy(fileSortSequence,newSortSequence);
      strcpy(fileSortSequenceLibrary,"QSYS");
      *fileSortSequenceType = newSortSequenceType;
    }
    else if (strcmp(fileSortSequence,newSortSequence) != 0)
    {
      // Only one sort sequence/collation is supported for each DB2 index.
      getErrTxt(DB2I_ERR_MIXED_COLLATIONS);
      DBUG_RETURN(DB2I_ERR_MIXED_COLLATIONS);
    }
  }

  DBUG_RETURN(0);
}
<commit_msg>merging with mysql-5.1-bugteam tree<commit_after>/*
Licensed Materials - Property of IBM
DB2 Storage Engine Enablement
Copyright IBM Corporation 2007,2008
All rights reserved

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
 (a) Redistributions of source code must retain this list of conditions, the
     copyright notice in section {d} below, and the disclaimer following this
     list of conditions.
 (b) Redistributions in binary form must reproduce this list of conditions, the
     copyright notice in section (d) below, and the disclaimer following this
     list of conditions, in the documentation and/or other materials provided
     with the distribution.
 (c) The name of IBM may not be used to endorse or promote products derived from
     this software without specific prior written permission.
 (d) The text of the required copyright notice is:
       Licensed Materials - Property of IBM
       DB2 Storage Engine Enablement
       Copyright IBM Corporation 2007,2008
       All rights reserved

THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "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 IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "db2i_collationSupport.h"
#include "db2i_errors.h"

/*
  The following arrays define a mapping between MySQL collation names and
  corresponding IBM i sort sequences. The mapping is a 1-to-1 correlation
  between corresponding array slots but is incomplete without case-sensitivity
  markers dynamically added to the mySqlSortSequence names.
*/
#define MAX_COLLATION 89
static const char* mySQLCollation[MAX_COLLATION] =
{
    {"ascii_general"},
    {"ascii"},
    {"big5_chinese"},
    {"big5"},
    {"cp1250_croatian"},
    {"cp1250_czech"},
    {"cp1250_general"},
    {"cp1250_polish"},
    {"cp1250"},
    {"cp1251_bulgarian"},
    {"cp1251_general"},
    {"cp1251"},
    {"cp1256_general"},
    {"cp1256"},
    {"cp850_general"},
    {"cp850"},
    {"cp852_general"},
    {"cp852"},
    {"cp932_japanese"},
    {"cp932"},
    {"euckr_korean"},
    {"euckr"},
    {"gb2312_chinese"},
    {"gb2312"},
    {"gbk_chinese"},
    {"gbk"},
    {"greek_general"},
    {"greek"},
    {"hebrew_general"},
    {"hebrew"},
    {"latin1_danish"},
    {"latin1_general"},
    {"latin1_german1"},
    {"latin1_spanish"},
    {"latin1_swedish"},
    {"latin1"},
    {"latin2_croatian"},
    {"latin2_czech"},
    {"latin2_general"},
    {"latin2_hungarian"},
    {"latin2"},
    {"latin5_turkish"},
    {"latin5"},
    {"macce_general"},
    {"macce"},
    {"sjis_japanese"},
    {"sjis"},
    {"tis620_thai"},
    {"tis620"},
    {"ucs2_czech"},
    {"ucs2_danish"},
    {"ucs2_esperanto"},
    {"ucs2_estonian"},
    {"ucs2_general"},
    {"ucs2_hungarian"},
    {"ucs2_icelandic"},
    {"ucs2_latvian"},
    {"ucs2_lithuanian"},
    {"ucs2_persian"},
    {"ucs2_polish"},
    {"ucs2_romanian"},
    {"ucs2_slovak"},
    {"ucs2_slovenian"},
    {"ucs2_spanish"},
    {"ucs2_swedish"},
    {"ucs2_turkish"},
    {"ucs2_unicode"},
    {"ucs2"},
    {"ujis_japanese"},
    {"ujis"},
    {"utf8_czech"},
    {"utf8_danish"},
    {"utf8_esperanto"},
    {"utf8_estonian"},
    {"utf8_general"},
    {"utf8_hungarian"},
    {"utf8_icelandic"},
    {"utf8_latvian"},
    {"utf8_lithuanian"},
    {"utf8_persian"},
    {"utf8_polish"},
    {"utf8_romanian"},
    {"utf8_slovak"},
    {"utf8_slovenian"},
    {"utf8_spanish"},
    {"utf8_swedish"},
    {"utf8_turkish"},
    {"utf8_unicode"},
    {"utf8"}
};

static const char* mySqlSortSequence[MAX_COLLATION] =
{
    {"QALA101F4"},
    {"QBLA101F4"},
    {"QACHT04B0"},
    {"QBCHT04B0"},
    {"QALA20481"},
    {"QBLA20481"},
    {"QCLA20481"},
    {"QDLA20481"},
    {"QELA20481"},
    {"QACYR0401"},
    {"QBCYR0401"},
    {"QCCYR0401"},
    {"QAARA01A4"},
    {"QBARA01A4"},
    {"QCLA101F4"},
    {"QDLA101F4"},
    {"QALA20366"},
    {"QBLA20366"},
    {"QAJPN04B0"},
    {"QBJPN04B0"},
    {"QAKOR04B0"},
    {"QBKOR04B0"},
    {"QACHS04B0"},
    {"QBCHS04B0"},
    {"QCCHS04B0"},
    {"QDCHS04B0"},
    {"QAELL036B"},
    {"QBELL036B"},
    {"QAHEB01A8"},
    {"QBHEB01A8"},
    {"QALA1047C"},
    {"QBLA1047C"},
    {"QCLA1047C"},
    {"QDLA1047C"},
    {"QELA1047C"},
    {"QFLA1047C"},
    {"QCLA20366"},
    {"QDLA20366"},
    {"QELA20366"},
    {"QFLA20366"},
    {"QGLA20366"},
    {"QATRK0402"},
    {"QBTRK0402"},
    {"QHLA20366"},
    {"QILA20366"},
    {"QCJPN04B0"},
    {"QDJPN04B0"},
    {"QATHA0346"},
    {"QBTHA0346"},
    {"ACS"},
    {"ADA"},
    {"AEO"},
    {"AET"},
    {"QAUCS04B0"},
    {"AHU"},
    {"AIS"},
    {"ALV"},
    {"ALT"},
    {"AFA"},
    {"APL"},
    {"ARO"},
    {"ASK"},
    {"ASL"},
    {"AES"},
    {"ASW"},
    {"ATR"},
    {"AEN"},
    {"*HEX"},
    {"QEJPN04B0"},
    {"QFJPN04B0"},
    {"ACS"},
    {"ADA"},
    {"AEO"},
    {"AET"},
    {"QAUCS04B0"},
    {"AHU"},
    {"AIS"},
    {"ALV"},
    {"ALT"},
    {"AFA"},
    {"APL"},
    {"ARO"},
    {"ASK"},
    {"ASL"},
    {"AES"},
    {"ASW"},
    {"ATR"},
    {"AEN"},
    {"*HEX"}
};

/**
  Get the IBM i sort sequence that corresponds to the given MySQL collation.

  @param fieldCharSet  The collated character set
  @param[out] rtnSortSequence  The corresponding sort sequence

  @return  0 if successful. Failure otherwise
*/
static int32 getAssociatedSortSequence(const CHARSET_INFO *fieldCharSet, const char** rtnSortSequence)
{
  DBUG_ENTER("ha_ibmdb2i::getAssociatedSortSequence");

  if (strcmp(fieldCharSet->csname,"binary") != 0)
  {
    int collationSearchLen = strlen(fieldCharSet->name);
    if (fieldCharSet->state & MY_CS_BINSORT)
      collationSearchLen -= 4;
    else
      collationSearchLen -= 3;

    uint16 loopCnt = 0;
    for (loopCnt; loopCnt < MAX_COLLATION; ++loopCnt)
    {
      if ((strlen(mySQLCollation[loopCnt]) == collationSearchLen) &&
          (strncmp((char*)mySQLCollation[loopCnt], fieldCharSet->name, collationSearchLen) == 0))
        break;
    }
    if (loopCnt == MAX_COLLATION)  // Did not find associated sort sequence
    {
      getErrTxt(DB2I_ERR_SRTSEQ);
      DBUG_RETURN(DB2I_ERR_SRTSEQ);
    }
    *rtnSortSequence = mySqlSortSequence[loopCnt];
  }

  DBUG_RETURN(0);
}

/**
  Update sort sequence information for a key.

  This function accumulates information about a key as it is called for each
  field composing the key. The caller should invoke the function for each field
  and (with the exception of the charset parm) preserve the values for the
  parms across invocations, until a particular key has been evaluated. Once
  the last field in the key has been evaluated, the fileSortSequence and
  fileSortSequenceLibrary parms will contain the correct information for
  creating the corresponding DB2 key.

  @param charset  The character set under consideration
  @param[in, out] fileSortSequenceType  The type of the current key's sort seq
  @param[in, out] fileSortSequence  The IBM i identifier for the DB2 sort sequence
                                    that corresponds

  @return  0 if successful. Failure otherwise
*/
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
                                   char* fileSortSequenceType,
                                   char* fileSortSequence,
                                   char* fileSortSequenceLibrary)
{
  DBUG_ENTER("ha_ibmdb2i::updateAssociatedSortSequence");
  DBUG_ASSERT(charset);
  if (strcmp(charset->csname,"binary") != 0)
  {
    char newSortSequence[11] = "";
    char newSortSequenceType = ' ';
    const char* foundSortSequence;
    int rc = getAssociatedSortSequence(charset, &foundSortSequence);
    if (rc) DBUG_RETURN (rc);
    switch(foundSortSequence[0])
    {
      case '*': // Binary
        strcat(newSortSequence,foundSortSequence);
        newSortSequenceType = 'B';
        break;
      case 'Q': // Non-ICU sort sequence
        strcat(newSortSequence,foundSortSequence);
        if ((charset->state & MY_CS_BINSORT) != 0)
        {
          strcat(newSortSequence,"U");
        }
        else if ((charset->state & MY_CS_CSSORT) != 0)
        {
          strcat(newSortSequence,"U");
        }
        else
        {
          strcat(newSortSequence,"S");
        }
        newSortSequenceType = 'N';
        break;
      default: // ICU sort sequence
	{
          if ((charset->state & MY_CS_CSSORT) == 0)
          {
            if (osVersion.v >= 6)
              strcat(newSortSequence,"I34"); // ICU 3.4
            else
              strcat(newSortSequence,"I26"); // ICU 2.6.1
          }
          strcat(newSortSequence,foundSortSequence);
          newSortSequenceType = 'I';
        }
        break;
    }
    if (*fileSortSequenceType == ' ') // If no sort sequence has been set yet
    {
      // Set associated sort sequence
      strcpy(fileSortSequence,newSortSequence);
      strcpy(fileSortSequenceLibrary,"QSYS");
      *fileSortSequenceType = newSortSequenceType;
    }
    else if (strcmp(fileSortSequence,newSortSequence) != 0)
    {
      // Only one sort sequence/collation is supported for each DB2 index.
      getErrTxt(DB2I_ERR_MIXED_COLLATIONS);
      DBUG_RETURN(DB2I_ERR_MIXED_COLLATIONS);
    }
  }

  DBUG_RETURN(0);
}
<|endoftext|>


<commit_before>/*
    An erlang driver for taglib that outputs JSON.

    This process is passed filenames on stdin (from erlang)
    It uses taglib on the file, and outputs JSON containing the
    metadata, according to taglib. One line of JSON output per file.

*/
#include <taglib/fileref.h>
#include <taglib/tag.h>

#include <iostream>
#include <cstdio>
#include <sstream>
#include <algorithm>
#include <string>

#include <netinet/in.h> // for htonl etc

using namespace std;

#ifdef WIN32
wstring fromUtf8(const string& i);
string toUtf8(const wstring& i);
#else
#define fromUtf8(s) (s)
#define toUtf8(s) (s)
#endif

void trim(string& str)
{
    size_t startpos = str.find_first_not_of(" \t");
    size_t endpos = str.find_last_not_of(" \t");
    if(( string::npos == startpos ) || ( string::npos == endpos))
        str = "";
    else
        str = str.substr( startpos, endpos-startpos+1 );
}

string urlify(const string& p)
{
    // turn it into a url by prepending file://
    // because we pass all urls to curl:
    string urlpath("file://");
    if (p.at(0)=='/') // posix path starting with /
    {
        urlpath += p;
    }
    else if (p.at(1)==':') // windows style filepath
    {
        urlpath += "/" + p;
    }
    else urlpath = p;
    return urlpath;
}

string ext2mime(const string& ext)
{
    if(ext==".mp3") return "audio/mpeg";
    if(ext==".aac") return "audio/mp4";
    if(ext==".mp4") return "audio/mp4";
    if(ext==".m4a") return "audio/mp4";
    if(ext==".ogg") return "application/ogg";
    cerr << "Warning, unhandled file extension. Don't know mimetype for " << ext << endl;
     //generic:
    return "application/octet-stream";
}

// replace whitespace and other control codes with ' ' and replace multiple whitespace with single
string tidy(const string& s)
{
    string r;
    bool prevWasSpace = false;
    r.reserve(s.length());
    for (string::const_iterator i = s.begin(); i != s.end(); i++) {
        if (*i > 0 && *i <= ' ') {
            if (!prevWasSpace) {
                r += ' ';
                prevWasSpace = true;
            }
        } else if (*i == '"') {
            r += '\\';
            r += '"';
            prevWasSpace = false;
        } else {
            r += *i;
            prevWasSpace = false;
        }
    }
    return r;
}

string esc(const string& s)
{
    string r;
    bool prevWasSpace = false;
    r.reserve(s.length()+4);
    for (string::const_iterator i = s.begin(); i != s.end(); i++) {
        if (*i == '"') {
            r += '\\';
            r += '"';
            prevWasSpace = false;
        } else {
            r += *i;
            prevWasSpace = false;
        }
    }
    return r;
}

string scan_file(const char* path)
{
    TagLib::FileRef f(path);
    if (!f.isNull() && f.tag()) {
        TagLib::Tag *tag = f.tag();
        int bitrate = 0;
        int duration = 0;
        if (f.audioProperties()) {
            TagLib::AudioProperties *properties = f.audioProperties();
            duration = properties->length();
            bitrate = properties->bitrate();
        }
        string artist = tag->artist().toCString(true);
        string album  = tag->album().toCString(true);
        string track  = tag->title().toCString(true);
        trim(artist);
        trim(album);
        trim(track);
        if (artist.length()==0 || track.length()==0) {
            return "{\"error\" : \"no tags\"}\n";
        }
        string pathstr(path);
        string ext = pathstr.substr(pathstr.length()-4);
        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
        string mimetype = ext2mime(ext);
        // turn it into a url by prepending file://
        // because we pass all urls to curl:
        string urlpath = urlify( toUtf8(path) );

        ostringstream os;
        os      <<  "{  \"url\" : \"" << esc(urlpath) << "\","
                    "   \"mimetype\" : \"" << mimetype << "\","
                    "   \"artist\" : \"" << tidy(artist) << "\","
                    "   \"album\" : \"" << tidy(album) << "\","
                    "   \"track\" : \"" << tidy(track) << "\","
                    "   \"duration\" : " << duration << ","
                    "   \"bitrate\" : " << bitrate << ","
                    "   \"trackno\" : " << tag->track()

                <<  "}\n";
        return os.str();
    }
    return "{\"error\" : \"no tags\"}\n";
}

int readn(unsigned char *buf, int len)
{
    int i, got = 0;
    do
    {
        if((i=read(0,buf+got, len-got))<=0) return i;
        got += i;
    } while(got<len);
    return len;
}

int writen(unsigned char *buf, int len)
{
  int i, wrote = 0;
  do {
    if ((i = write(1, buf+wrote, len-wrote)) <= 0) return i;
    wrote += i;
  } while (wrote<len);
  return len;
}

#ifdef WIN32
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    //scan_file( argv[1] );
    unsigned char buffer[256];
    unsigned int len0,len;
    while(1)
    {
        if(readn((unsigned char*)&len0,4)!=4) break;
        len = ntohl(len0);
        readn((unsigned char*)&buffer, len);
        buffer[len]='\0';
        string j = scan_file((const char*)&buffer);
        unsigned int l = htonl(j.length());
        writen((unsigned char*)&l,4);
        printf("%s", j.c_str());
        cout.flush();
    }

}

<commit_msg>Port taglib_json_reader to windows<commit_after>/*
    An erlang driver for taglib that outputs JSON.

    This process is passed filenames on stdin (from erlang)
    It uses taglib on the file, and outputs JSON containing the
    metadata, according to taglib. One line of JSON output per file.

*/
#include <taglib/fileref.h>
#include <taglib/tag.h>

#include <cstdio>
#include <sstream>
#include <algorithm>
#include <string>

#ifdef WIN32
#include <Winsock2.h>
#else
#include <netinet/in.h> // for htonl etc
#endif

using namespace std;

#ifdef WIN32
wstring fromUtf8(const string& i);
string toUtf8(const wstring& i);
#else
#define fromUtf8(s) (s)
#define toUtf8(s) (s)
#endif

void trim(string& str)
{
    size_t startpos = str.find_first_not_of(" \t");
    size_t endpos = str.find_last_not_of(" \t");
    if(( string::npos == startpos ) || ( string::npos == endpos))
        str = "";
    else
        str = str.substr( startpos, endpos-startpos+1 );
}

string urlify(const string& p)
{
    // turn it into a url by prepending file://
    // because we pass all urls to curl:
    string urlpath("file://");
    if (p.at(0)=='/') // posix path starting with /
    {
        urlpath += p;
    }
    else if (p.at(1)==':') // windows style filepath
    {
        urlpath += "/" + p;
    }
    else urlpath = p;
    return urlpath;
}

string ext2mime(const string& ext)
{
    if(ext==".mp3") return "audio/mpeg";
    if(ext==".aac") return "audio/mp4";
    if(ext==".mp4") return "audio/mp4";
    if(ext==".m4a") return "audio/mp4";
    if(ext==".ogg") return "application/ogg";
    cerr << "Warning, unhandled file extension. Don't know mimetype for " << ext << endl;
     //generic:
    return "application/octet-stream";
}

// replace whitespace and other control codes with ' ' and replace multiple whitespace with single
string tidy(const string& s)
{
    string r;
    bool prevWasSpace = false;
    r.reserve(s.length());
    for (string::const_iterator i = s.begin(); i != s.end(); i++) {
        if (*i > 0 && *i <= ' ') {
            if (!prevWasSpace) {
                r += ' ';
                prevWasSpace = true;
            }
        } else if (*i == '"') {
            r += '\\';
            r += '"';
            prevWasSpace = false;
        } else {
            r += *i;
            prevWasSpace = false;
        }
    }
    return r;
}

string esc(const string& s)
{
    string r;
    bool prevWasSpace = false;
    r.reserve(s.length()+4);
    for (string::const_iterator i = s.begin(); i != s.end(); i++) {
        if (*i == '"') {
            r += '\\';
            r += '"';
            prevWasSpace = false;
        } else {
            r += *i;
            prevWasSpace = false;
        }
    }
    return r;
}

string scan_file(const char* path)
{
    TagLib::FileRef f(path);
    if (!f.isNull() && f.tag()) {
        TagLib::Tag *tag = f.tag();
        int bitrate = 0;
        int duration = 0;
        if (f.audioProperties()) {
            TagLib::AudioProperties *properties = f.audioProperties();
            duration = properties->length();
            bitrate = properties->bitrate();
        }
        string artist = tag->artist().toCString(true);
        string album  = tag->album().toCString(true);
        string track  = tag->title().toCString(true);
        trim(artist);
        trim(album);
        trim(track);
        if (artist.length()==0 || track.length()==0) {
            return "{\"error\" : \"no tags\"}\n";
        }
        string pathstr(path);
        string ext = pathstr.substr(pathstr.length()-4);
        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
        string mimetype = ext2mime(ext);
        // turn it into a url by prepending file://
        // because we pass all urls to curl:
        string urlpath = urlify( path );

        ostringstream os;
        os      <<  "{  \"url\" : \"" << esc(urlpath) << "\","
                    "   \"mimetype\" : \"" << mimetype << "\","
                    "   \"artist\" : \"" << tidy(artist) << "\","
                    "   \"album\" : \"" << tidy(album) << "\","
                    "   \"track\" : \"" << tidy(track) << "\","
                    "   \"duration\" : " << duration << ","
                    "   \"bitrate\" : " << bitrate << ","
                    "   \"trackno\" : " << tag->track()

                <<  "}\n";
        return os.str();
    }
    return "{\"error\" : \"no tags\"}\n";
}

#ifdef WIN32
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    //scan_file( argv[1] );
    char buffer[256];
    unsigned int len0,len;

    while(1)
    {
        if(fread(&len0, 4, 1, stdin)!=1) break;
        len = ntohl(len0);

        fread(&buffer, 1, len, stdin);
        buffer[len]='\0';

        string j = scan_file((const char*)&buffer);

// newlines
#ifdef WIN32
        unsigned int l = htonl(j.length()+1);
#else
        unsigned int l = htonl(j.length());
#endif
        fwrite(&l,4,1,stdout);
        printf("%s", j.c_str());
        fflush(stdout);
    }
    return 0;
}
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Internal Includes
#include "HDKLedIdentifierFactory.h"
#include "HDKLedIdentifier.h"

// Library/third-party includes
#include <boost/assert.hpp>

// Standard includes
// - none

namespace osvr {
namespace vbtracker {

    /// @brief Helper for factory function.
    static inline LedIdentifierPtr
    createHDKLedIdentifier(const PatternStringList &patterns) {
        LedIdentifierPtr ret{new OsvrHdkLedIdentifier(patterns)};
        return ret;
    }

    // clang-format off
    /// @brief Determines the LED IDs for the OSVR HDK sensor 0 (face plate)
    /// These estimates are from the original documentation, not from the
    /// as-built measurements.
    /// First number in comments is overall LED ID, second is LED ID in the
    /// sensor it was in
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR0_PATTERNS_ORIGINAL = {
              "..*.....*...*..."    //  7  1
            , "...*......*...*."    //  8  2
            , ".......*...*...*"    //  9  3
            , "......*...*..*.."    // 10  4
            , ".......*....*..*"    // 11  5
            , "..*.....*..*...."    // 12  6
            , "....*......*..*."    // 13  7
            , "....*..*....*..."    // 14  8
            , "..*...*........*"    // 15  9
            , "........*..*..*."    // 16 10
            , "..*..*.*........"    // 17 11
            , "....*...*.*....."    // 18 12
            , "...*.*........*."    // 19 13
            , "...*.....*.*...."    // 20 14
            , "....*.*......*.."    // 21 15
            , "*.......*.*....."    // 22 16
            , ".*........*.*..."    // 23 17
            , ".*.........*.*.."    // 24 18
            , "....*.*..*......"    // 25 19
            , ".*.*.*.........."    // 26 20
            , ".........*.**..."    // 27 21
            , "**...........*.."    // 28 22
            , ".*...**........."    // 29 23
            , ".........*....**"    // 30 24
            , "..*.....**......"    // 31 25
            , "*......**......."    // 32 26
            , "...*.......**..."    // 33 27
            , "...**.....*....."    // 34 28
            , ".**....*........"    // 35 29
            , "....**...*......"    // 36 30
            , "*...........**.."    // 37 31
            , "......**.*......"    // 38 32
            , ".............***"    // 39 33
            , "..........*....."    // 40 34
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 1 (back plate)
    /// These estimates are from the original documentation, not from the
    /// as-built measurements.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR1_PATTERNS_ORIGINAL = {
              "***...*........*"    //  1  1
            , "...****..*......"    //  2  2
            , "*.*..........***"    //  3  3
            , "**...........***"    //  4  4
            , "*....*....*....."    //  5  5
            , "...*....*...*..."    //  6  6
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 0 (face plate)
    /// These are from the as-built measurements.
    /// First number in comments is overall LED ID, second is LED ID in the
    /// sensor it was in
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR0_PATTERNS = {
            "..*.....**......"    //  1
          , "*......**......."    //  2
          , ".*...**........."    //  3
          , ".........*....**"    //  4
          , ".**....*........"    //  5
          , "....**...*......"    //  6
          , "**...........*.."    //  7
          , ".*.*.*.........."    //  8
          , ".........*.**..."    //  9
          , "....*.*..*......"    // 10
          , "....*.*......*.."    // 11
          , "*.......*.*....."    // 28
          , ".*........*.*..."    // 27
          , ".*.........*.*.."    // 25
          , "..*..*.*........"    // 15
          , "....*...*.*....."    // 16
          , "...*.*........*."    // 17
          , "...*.....*.*...."    // 18
          , "....*......*..*."    // 19
          , "....*..*....*..."    // 20
          , "..*...*........*"    // 21
          , "........*..*..*."    // 22
          , ".......*...*...*"    // 23
          , "......*...*..*.."    // 24
          , ".......*....*..*"    // 14
          , "..*.....*..*...."    // 26
          , "*....*....*....."    // 13
          , "...*....*...*..."    // 12
          , "..*.....*...*..."    // 29
          , "...*......*...*."    // 30
          , "***...*........*"    // 31
          , "...****..*......"    // 32
          , "*.*..........***"    // 33
          , "**...........***"    // 34
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 1 (back plate)
    /// These are from the as-built measurements.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR1_PATTERNS = {
            "*...........**.."    // 37 31
          , "......**.*......"    // 38 32
          , ".............***"    // 39 33
          , "..........*....."    // 40 34
          , "...*.......**..."    // 33 27
          , "...**.....*....."    // 34 28
    };
    // clang-format on

    LedIdentifierPtr createHDKLedIdentifier(uint8_t sensor) {
        LedIdentifierPtr ret;
        switch (sensor) {
        case 0:
            ret = createHDKLedIdentifier(OsvrHdkLedIdentifier_SENSOR0_PATTERNS);
            break;
        case 1:
            ret = createHDKLedIdentifier(OsvrHdkLedIdentifier_SENSOR1_PATTERNS);
        default:
            BOOST_ASSERT_MSG(sensor < 2, "Valid sensors are only 0 or 1!");
            break;
        }
        return ret;
    }

    // clang-format off
    /// @brief Patterns found in the "HDK_random_images" folder, which has only
    /// 8 images for each and they are a random subset of the actual images.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_RANDOM_IMAGES_PATTERNS = {
              "..*....." // 7
            , "...*...." // 8
            , ".......*" // 9
            , "......*." // 10
            , ".......*" // 11
            , "..*....." // 12
            , "....*..." // 13
            , "....*..*" // 14
            , "********" // 15
            , "........" // 16
            , "********" // 17
            , "....*..." // 18
            , "...*.*.." // 19
            , "...*...." // 20
            , "....*.*." // 21
            , "...*.***" // 22
            , ".*......" // 23
            , "..*...*." // 24
            , "....*.*." // 25
            , ".*.*.*.." // 26
            , "........" // 27
            , "**......" // 28
            , ".*...**." // 29
            , "........" // 30
            , "..*....." // 31
            , "*......*" // 32
            , "...*...." // 33
            , "...**..." // 34
            , ".......*" // 35
            , "*..*..*." // 36
            , "*......." // 37
            , "......**" // 38
            , "........" // 39
            , "........" // 40
    };
    // clang-format on
    LedIdentifierPtr createRandomHDKLedIdentifier() {
        return createHDKLedIdentifier(
            OsvrHdkLedIdentifier_RANDOM_IMAGES_PATTERNS);
    }
} // End namespace vbtracker
} // End namespace osvr
<commit_msg>Now has the LEDs ordered correctly w.r.t. the first HDK shipped in the OSVR packing box, compared to the list of locations in the BeaconBasedPoseEstimator.  Note that a couple of the beacons on the top are not actaully where they were listed on the diagram, so that will need to be changed.<commit_after>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Internal Includes
#include "HDKLedIdentifierFactory.h"
#include "HDKLedIdentifier.h"

// Library/third-party includes
#include <boost/assert.hpp>

// Standard includes
// - none

namespace osvr {
namespace vbtracker {

    /// @brief Helper for factory function.
    static inline LedIdentifierPtr
    createHDKLedIdentifier(const PatternStringList &patterns) {
        LedIdentifierPtr ret{new OsvrHdkLedIdentifier(patterns)};
        return ret;
    }

    // clang-format off
    /// @brief Determines the LED IDs for the OSVR HDK sensor 0 (face plate)
    /// These estimates are from the original documentation, not from the
    /// as-built measurements.
    /// First number in comments is overall LED ID, second is LED ID in the
    /// sensor it was in
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR0_PATTERNS_ORIGINAL = {
              "..*.....*...*..."    //  7  1
            , "...*......*...*."    //  8  2
            , ".......*...*...*"    //  9  3
            , "......*...*..*.."    // 10  4
            , ".......*....*..*"    // 11  5
            , "..*.....*..*...."    // 12  6
            , "....*......*..*."    // 13  7
            , "....*..*....*..."    // 14  8
            , "..*...*........*"    // 15  9
            , "........*..*..*."    // 16 10
            , "..*..*.*........"    // 17 11
            , "....*...*.*....."    // 18 12
            , "...*.*........*."    // 19 13
            , "...*.....*.*...."    // 20 14
            , "....*.*......*.."    // 21 15
            , "*.......*.*....."    // 22 16
            , ".*........*.*..."    // 23 17
            , ".*.........*.*.."    // 24 18
            , "....*.*..*......"    // 25 19
            , ".*.*.*.........."    // 26 20
            , ".........*.**..."    // 27 21
            , "**...........*.."    // 28 22
            , ".*...**........."    // 29 23
            , ".........*....**"    // 30 24
            , "..*.....**......"    // 31 25
            , "*......**......."    // 32 26
            , "...*.......**..."    // 33 27
            , "...**.....*....."    // 34 28
            , ".**....*........"    // 35 29
            , "....**...*......"    // 36 30
            , "*...........**.."    // 37 31
            , "......**.*......"    // 38 32
            , ".............***"    // 39 33
            , "..........*....."    // 40 34
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 1 (back plate)
    /// These estimates are from the original documentation, not from the
    /// as-built measurements.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR1_PATTERNS_ORIGINAL = {
              "***...*........*"    //  1  1
            , "...****..*......"    //  2  2
            , "*.*..........***"    //  3  3
            , "**...........***"    //  4  4
            , "*....*....*....."    //  5  5
            , "...*....*...*..."    //  6  6
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 0 (face plate)
    /// These are from the as-built measurements.
    /// First number in comments is overall LED ID, second is LED ID in the
    /// sensor it was in
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR0_PATTERNS = {
            ".**....*........"    //  5
          , "....**...*......"    //  6
          , ".*...**........."    //  3
          , ".........*....**"    //  4
          , "..*.....**......"    //  1
          , "*......**......."    //  2
          , "....*.*..*......"    // 10
          , ".*.*.*.........."    //  8
          , ".........*.**..."    //  9
          , "**...........*.."    //  7
          , "....*.*......*.."    // 11
          , "*.......*.*....."    // 28
          , ".*........*.*..."    // 27
          , ".*.........*.*.."    // 25
          , "..*..*.*........"    // 15
          , "....*...*.*....."    // 16
          , "...*.*........*."    // 17
          , "...*.....*.*...."    // 18
          , "....*......*..*."    // 19
          , "....*..*....*..."    // 20
          , "..*...*........*"    // 21
          , "........*..*..*."    // 22
          , ".......*...*...*"    // 23
          , "......*...*..*.."    // 24
          , ".......*....*..*"    // 14
          , "..*.....*..*...."    // 26
          , "*....*....*....."    // 13
          , "...*....*...*..."    // 12
          , "..*.....*...*..."    // 29
          , "...*......*...*."    // 30
          , "***...*........*"    // 31
          , "...****..*......"    // 32
          , "*.*..........***"    // 33
          , "**...........***"    // 34
    };

    /// @brief Determines the LED IDs for the OSVR HDK sensor 1 (back plate)
    /// These are from the as-built measurements.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_SENSOR1_PATTERNS = {
            "*...........**.."    // 37 31
          , "......**.*......"    // 38 32
          , ".............***"    // 39 33
          , "..........*....."    // 40 34
          , "...*.......**..."    // 33 27
          , "...**.....*....."    // 34 28
    };
    // clang-format on

    LedIdentifierPtr createHDKLedIdentifier(uint8_t sensor) {
        LedIdentifierPtr ret;
        switch (sensor) {
        case 0:
            ret = createHDKLedIdentifier(OsvrHdkLedIdentifier_SENSOR0_PATTERNS);
            break;
        case 1:
            ret = createHDKLedIdentifier(OsvrHdkLedIdentifier_SENSOR1_PATTERNS);
        default:
            BOOST_ASSERT_MSG(sensor < 2, "Valid sensors are only 0 or 1!");
            break;
        }
        return ret;
    }

    // clang-format off
    /// @brief Patterns found in the "HDK_random_images" folder, which has only
    /// 8 images for each and they are a random subset of the actual images.
    static const std::vector<std::string>
        OsvrHdkLedIdentifier_RANDOM_IMAGES_PATTERNS = {
              "..*....." // 7
            , "...*...." // 8
            , ".......*" // 9
            , "......*." // 10
            , ".......*" // 11
            , "..*....." // 12
            , "....*..." // 13
            , "....*..*" // 14
            , "********" // 15
            , "........" // 16
            , "********" // 17
            , "....*..." // 18
            , "...*.*.." // 19
            , "...*...." // 20
            , "....*.*." // 21
            , "...*.***" // 22
            , ".*......" // 23
            , "..*...*." // 24
            , "....*.*." // 25
            , ".*.*.*.." // 26
            , "........" // 27
            , "**......" // 28
            , ".*...**." // 29
            , "........" // 30
            , "..*....." // 31
            , "*......*" // 32
            , "...*...." // 33
            , "...**..." // 34
            , ".......*" // 35
            , "*..*..*." // 36
            , "*......." // 37
            , "......**" // 38
            , "........" // 39
            , "........" // 40
    };
    // clang-format on
    LedIdentifierPtr createRandomHDKLedIdentifier() {
        return createHDKLedIdentifier(
            OsvrHdkLedIdentifier_RANDOM_IMAGES_PATTERNS);
    }
} // End namespace vbtracker
} // End namespace osvr
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "kiomediastream.h"
#include "kiomediastream_p.h"
#include <kdebug.h>
#include <kprotocolmanager.h>
#include <kio/filejob.h>
#include <kio/job.h>
#include <klocale.h>

namespace Phonon
{

KioMediaStream::KioMediaStream(const QUrl &url, QObject *parent)
    : AbstractMediaStream(*new KioMediaStreamPrivate(url), parent)
{
    reset();
}

void KioMediaStream::reset()
{
    Q_D(KioMediaStream);
    if (d->kiojob) {
        d->kiojob->disconnect(this);
        d->kiojob->kill();

        d->endOfDataSent = false;
        d->seeking = false;
        d->reading = false;
        d->open = false;
        d->seekPosition = 0;
    }

    if (KProtocolManager::supportsOpening(d->url)) {
        d->kiojob = KIO::open(d->url, QIODevice::ReadOnly);
        Q_ASSERT(d->kiojob);
        d->open = false;
        setStreamSeekable(true);
        connect(d->kiojob, SIGNAL(open(KIO::Job *)), this, SLOT(_k_bytestreamFileJobOpen(KIO::Job *)));
        connect(d->kiojob, SIGNAL(position(KIO::Job *, KIO::filesize_t)),
                this, SLOT(_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t)));
    } else {
        d->kiojob = KIO::get(d->url, false, false);
        Q_ASSERT(d->kiojob);
        setStreamSeekable(false);
        connect(d->kiojob, SIGNAL(totalSize(KJob *, qulonglong)),
                this, SLOT(_k_bytestreamTotalSize(KJob *,qulonglong)));
        d->kiojob->suspend();
    }

    d->kiojob->addMetaData("UserAgent", QLatin1String("KDE Phonon"));
    connect(d->kiojob, SIGNAL(data(KIO::Job *,const QByteArray &)),
            this, SLOT(_k_bytestreamData(KIO::Job *,const QByteArray &)));
    connect(d->kiojob, SIGNAL(result(KJob *)), this, SLOT(_k_bytestreamResult(KJob *)));
}

KioMediaStream::~KioMediaStream()
{
}

void KioMediaStream::needData()
{
    Q_D(KioMediaStream);
    if (!d->kiojob) {
        // no job => job is finished and endOfData was already sent
        return;
    }
    KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(d->kiojob);
    if (filejob) {
        // while d->seeking the backend won't get any data
        if (d->seeking || !d->open) {
            d->reading = true;
        } else if (!d->reading) {
            d->reading = true;
            filejob->read(32768);
        }
    } else {
        // KIO::TransferJob
        d->kiojob->resume();
    }
}

void KioMediaStream::enoughData()
{
    Q_D(KioMediaStream);
    kDebug(600) ;
    // Don't suspend when using a FileJob. The FileJob is controlled by calls to
    // FileJob::read()
    if (d->kiojob && !qobject_cast<KIO::FileJob *>(d->kiojob) && !d->kiojob->isSuspended()) {
        d->kiojob->suspend();
    } else {
        d->reading = false;
    }
}

void KioMediaStream::seekStream(qint64 position)
{
    Q_D(KioMediaStream);
    if (!d->kiojob) {
        // no job => job is finished and endOfData was already sent
        reset();
    }
    Q_ASSERT(d->kiojob);
    kDebug(600) << position << " = " << qulonglong(position);
    d->seeking = true;
    if (d->open) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(d->kiojob);
        filejob->seek(position);
    } else {
        d->seekPosition = position;
    }
}

void KioMediaStreamPrivate::_k_bytestreamData(KIO::Job *, const QByteArray &data)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob);
    if (seeking) {
        // seek doesn't block, so don't send data to the backend until it signals us
        // that the seek is done
        kDebug(600) << "seeking: do nothing";
        return;
    }

    if (data.isEmpty()) {
        reading = false;
        if (!endOfDataSent) {
            kDebug(600) << "empty data: stopping the stream";
            endOfDataSent = true;
            q->endOfData();
        }
        return;
    }

    //kDebug(600) << "calling writeData on the Backend ByteStream " << data.size();
    q->writeData(data);
    if (reading) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        Q_ASSERT(filejob);
        filejob->read(32768);
    }
}

void KioMediaStreamPrivate::_k_bytestreamResult(KJob *job)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob == job);
    if (job->error()) {
        QString kioErrorString = job->errorString();
        kDebug(600) << "KIO Job error: " << kioErrorString;
        QObject::disconnect(kiojob, SIGNAL(data(KIO::Job *,const QByteArray &)),
                q, SLOT(_k_bytestreamData(KIO::Job *,const QByteArray &)));
        QObject::disconnect(kiojob, SIGNAL(result(KJob *)),
                q, SLOT(_k_bytestreamResult(KJob *)));
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        if (filejob) {
            QObject::disconnect(kiojob, SIGNAL(open(KIO::Job *)),
                    q, SLOT(_k_bytestreamFileJobOpen(KIO::Job *)));
            QObject::disconnect(kiojob, SIGNAL(position(KIO::Job *, KIO::filesize_t)),
                    q, SLOT(_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t)));
        } else {
            QObject::disconnect(kiojob, SIGNAL(totalSize(KJob *, qulonglong)),
                    q, SLOT(_k_bytestreamTotalSize(KJob *,qulonglong)));
        }
        // go to ErrorState - NormalError
        q->error(NormalError, kioErrorString);
    }
    kiojob = 0;
    kDebug(600) << "KIO Job is done (will delete itself) and d->kiojob reset to 0";
    endOfDataSent = true;
    q->endOfData();
    reading = false;
}

void KioMediaStreamPrivate::_k_bytestreamTotalSize(KJob *, qulonglong size)
{
    Q_Q(KioMediaStream);
    kDebug(600) << size;
    q->setStreamSize(size);
}

void KioMediaStreamPrivate::_k_bytestreamFileJobOpen(KIO::Job *)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob);
    open = true;
    endOfDataSent = false;
    KIO::FileJob *filejob = static_cast<KIO::FileJob *>(kiojob);
    kDebug(600) << filejob->size();
    q->setStreamSize(filejob->size());

    if (seeking) {
        filejob->seek(seekPosition);
    } else if (reading) {
        filejob->read(32768);
    }
}

void KioMediaStreamPrivate::_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t offset)
{
    Q_ASSERT(kiojob);
    kDebug(600) << offset;
    seeking = false;
    endOfDataSent = false;
    if (reading) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        Q_ASSERT(filejob);
        filejob->read(32768);
    }
}

} // namespace Phonon

#include "kiomediastream.moc"
// vim: sw=4 sts=4 et tw=100
<commit_msg>fix race: FileJob would send an empty data QByteArray, meaning it reached EOF and will emit result later and then delete itself, but before result is received the backend requests a seek - the job is still seems to be valid, but really is just about to delete itself<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "kiomediastream.h"
#include "kiomediastream_p.h"
#include <kdebug.h>
#include <kprotocolmanager.h>
#include <kio/filejob.h>
#include <kio/job.h>
#include <klocale.h>

namespace Phonon
{

KioMediaStream::KioMediaStream(const QUrl &url, QObject *parent)
    : AbstractMediaStream(*new KioMediaStreamPrivate(url), parent)
{
    reset();
}

void KioMediaStream::reset()
{
    Q_D(KioMediaStream);
    if (d->kiojob) {
        d->kiojob->disconnect(this);
        d->kiojob->kill();

        d->endOfDataSent = false;
        d->seeking = false;
        d->reading = false;
        d->open = false;
        d->seekPosition = 0;
    }

    if (KProtocolManager::supportsOpening(d->url)) {
        d->kiojob = KIO::open(d->url, QIODevice::ReadOnly);
        Q_ASSERT(d->kiojob);
        d->open = false;
        setStreamSeekable(true);
        connect(d->kiojob, SIGNAL(open(KIO::Job *)), this, SLOT(_k_bytestreamFileJobOpen(KIO::Job *)));
        connect(d->kiojob, SIGNAL(position(KIO::Job *, KIO::filesize_t)),
                this, SLOT(_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t)));
    } else {
        d->kiojob = KIO::get(d->url, false, false);
        Q_ASSERT(d->kiojob);
        setStreamSeekable(false);
        connect(d->kiojob, SIGNAL(totalSize(KJob *, qulonglong)),
                this, SLOT(_k_bytestreamTotalSize(KJob *,qulonglong)));
        d->kiojob->suspend();
    }

    d->kiojob->addMetaData("UserAgent", QLatin1String("KDE Phonon"));
    connect(d->kiojob, SIGNAL(data(KIO::Job *,const QByteArray &)),
            this, SLOT(_k_bytestreamData(KIO::Job *,const QByteArray &)));
    connect(d->kiojob, SIGNAL(result(KJob *)), this, SLOT(_k_bytestreamResult(KJob *)));
}

KioMediaStream::~KioMediaStream()
{
}

void KioMediaStream::needData()
{
    Q_D(KioMediaStream);
    if (!d->kiojob) {
        // no job => job is finished and endOfData was already sent
        return;
    }
    KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(d->kiojob);
    if (filejob) {
        // while d->seeking the backend won't get any data
        if (d->seeking || !d->open) {
            d->reading = true;
        } else if (!d->reading) {
            d->reading = true;
            filejob->read(32768);
        }
    } else {
        // KIO::TransferJob
        d->kiojob->resume();
    }
}

void KioMediaStream::enoughData()
{
    Q_D(KioMediaStream);
    kDebug(600) ;
    // Don't suspend when using a FileJob. The FileJob is controlled by calls to
    // FileJob::read()
    if (d->kiojob && !qobject_cast<KIO::FileJob *>(d->kiojob) && !d->kiojob->isSuspended()) {
        d->kiojob->suspend();
    } else {
        d->reading = false;
    }
}

void KioMediaStream::seekStream(qint64 position)
{
    Q_D(KioMediaStream);
    if (!d->kiojob || d->endOfDataSent) {
        // no job => job is finished and endOfData was already sent
        reset();
    }
    Q_ASSERT(d->kiojob);
    kDebug(600) << position << " = " << qulonglong(position);
    d->seeking = true;
    if (d->open) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(d->kiojob);
        filejob->seek(position);
    } else {
        d->seekPosition = position;
    }
}

void KioMediaStreamPrivate::_k_bytestreamData(KIO::Job *, const QByteArray &data)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob);
    if (seeking) {
        // seek doesn't block, so don't send data to the backend until it signals us
        // that the seek is done
        kDebug(600) << "seeking: do nothing";
        return;
    }

    if (data.isEmpty()) {
        reading = false;
        if (!endOfDataSent) {
            kDebug(600) << "empty data: stopping the stream";
            endOfDataSent = true;
            q->endOfData();
        }
        return;
    }

    //kDebug(600) << "calling writeData on the Backend ByteStream " << data.size();
    q->writeData(data);
    if (reading) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        Q_ASSERT(filejob);
        filejob->read(32768);
    }
}

void KioMediaStreamPrivate::_k_bytestreamResult(KJob *job)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob == job);
    if (job->error()) {
        QString kioErrorString = job->errorString();
        kDebug(600) << "KIO Job error: " << kioErrorString;
        QObject::disconnect(kiojob, SIGNAL(data(KIO::Job *,const QByteArray &)),
                q, SLOT(_k_bytestreamData(KIO::Job *,const QByteArray &)));
        QObject::disconnect(kiojob, SIGNAL(result(KJob *)),
                q, SLOT(_k_bytestreamResult(KJob *)));
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        if (filejob) {
            QObject::disconnect(kiojob, SIGNAL(open(KIO::Job *)),
                    q, SLOT(_k_bytestreamFileJobOpen(KIO::Job *)));
            QObject::disconnect(kiojob, SIGNAL(position(KIO::Job *, KIO::filesize_t)),
                    q, SLOT(_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t)));
        } else {
            QObject::disconnect(kiojob, SIGNAL(totalSize(KJob *, qulonglong)),
                    q, SLOT(_k_bytestreamTotalSize(KJob *,qulonglong)));
        }
        // go to ErrorState - NormalError
        q->error(NormalError, kioErrorString);
    }
    kiojob = 0;
    kDebug(600) << "KIO Job is done (will delete itself) and d->kiojob reset to 0";
    endOfDataSent = true;
    q->endOfData();
    reading = false;
}

void KioMediaStreamPrivate::_k_bytestreamTotalSize(KJob *, qulonglong size)
{
    Q_Q(KioMediaStream);
    kDebug(600) << size;
    q->setStreamSize(size);
}

void KioMediaStreamPrivate::_k_bytestreamFileJobOpen(KIO::Job *)
{
    Q_Q(KioMediaStream);
    Q_ASSERT(kiojob);
    open = true;
    endOfDataSent = false;
    KIO::FileJob *filejob = static_cast<KIO::FileJob *>(kiojob);
    kDebug(600) << filejob->size();
    q->setStreamSize(filejob->size());

    if (seeking) {
        filejob->seek(seekPosition);
    } else if (reading) {
        filejob->read(32768);
    }
}

void KioMediaStreamPrivate::_k_bytestreamSeekDone(KIO::Job *, KIO::filesize_t offset)
{
    Q_ASSERT(kiojob);
    kDebug(600) << offset;
    seeking = false;
    endOfDataSent = false;
    if (reading) {
        KIO::FileJob *filejob = qobject_cast<KIO::FileJob *>(kiojob);
        Q_ASSERT(filejob);
        filejob->read(32768);
    }
}

} // namespace Phonon

#include "kiomediastream.moc"
// vim: sw=4 sts=4 et tw=100
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include "modules/perception/onboard/component/radar_detection_component.h"
#include "modules/perception/common/sensor_manager/sensor_manager.h"
#include "modules/perception/lib/utils/perf.h"

namespace apollo {
namespace perception {
namespace onboard {

bool RadarDetectionComponent::Init() {
  RadarComponentConfig comp_config;
  if (!GetProtoConfig(&comp_config)) {
    return false;
  }
  AINFO << "Radar Component Configs: " << comp_config.DebugString();

  // To load component configs
  tf_child_frame_id_ = comp_config.tf_child_frame_id();
  radar_forward_distance_ = comp_config.radar_forward_distance();
  preprocessor_method_ = comp_config.radar_preprocessor_method();
  perception_method_ = comp_config.radar_perception_method();
  pipeline_name_ = comp_config.radar_pipeline_name();
  odometry_channel_name_ = comp_config.odometry_channel_name();

  if (!common::SensorManager::Instance()->GetSensorInfo(
      comp_config.radar_name(), &radar_info_)) {
    AERROR << "Failed to get sensor info, sensor name: "
           << comp_config.radar_name();
    return false;
  }

  writer_ = node_->CreateWriter<SensorFrameMessage>(
      comp_config.output_channel_name());

  // Init algorithm plugin
  CHECK(InitAlgorithmPlugin() == true) << "Failed to init algorithm plugin.";
  radar2world_trans_.Init(tf_child_frame_id_);
  radar2novatel_trans_.Init(tf_child_frame_id_);
  localization_subscriber_.Init(
      odometry_channel_name_,
      odometry_channel_name_ + '_' + comp_config.radar_name());
  return true;
}

bool RadarDetectionComponent::Proc(const std::shared_ptr<ContiRadar>& message) {
  AINFO << "Enter radar preprocess, message timestamp: "
        << std::to_string(message->header().timestamp_sec())
        << " current timestamp " << lib::TimeUtil::GetCurrentTime();
  std::shared_ptr<SensorFrameMessage> out_message(new (std::nothrow)
                                                      SensorFrameMessage);
  int status = InternalProc(message, out_message);
  if (status) {
    writer_->Write(out_message);
    AINFO << "Send radar processing output message.";
  }
  return status;
}

bool RadarDetectionComponent::InitAlgorithmPlugin() {
  AINFO << "onboard radar_preprocessor: " << preprocessor_method_;
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_ = map::HDMapInput::Instance();
    CHECK(hdmap_input_->Init()) << "Failed to init hdmap input.";
  }
  radar::BasePreprocessor* preprocessor =
      radar::BasePreprocessorRegisterer::GetInstanceByName(
          preprocessor_method_);
  CHECK_NOTNULL(preprocessor);
  radar_preprocessor_.reset(preprocessor);
  CHECK(radar_preprocessor_->Init()) << "Failed to init radar preprocessor.";
  radar::BaseRadarObstaclePerception* radar_perception =
      radar::BaseRadarObstaclePerceptionRegisterer::GetInstanceByName(
          perception_method_);
  CHECK(radar_perception != nullptr)
      << "No radar obstacle perception named: " << perception_method_;
  radar_perception_.reset(radar_perception);
  CHECK(radar_perception_->Init(pipeline_name_))
      << "Failed to init radar perception.";
  AINFO << "Init algorithm plugin successfully.";
  return true;
}

bool RadarDetectionComponent::InternalProc(
    const std::shared_ptr<ContiRadar>& in_message,
    std::shared_ptr<SensorFrameMessage> out_message) {
  PERCEPTION_PERF_FUNCTION_WITH_INDICATOR(radar_info_.name);
  ContiRadar raw_obstacles = *in_message;
  {
    std::unique_lock<std::mutex> lock(_mutex);
    ++seq_num_;
  }
  double timestamp = in_message->header().timestamp_sec();
  const double cur_time = lib::TimeUtil::GetCurrentTime();
  const double start_latency = (cur_time - timestamp) * 1e3;
  AINFO << "FRAME_STATISTICS:Radar:Start:msg_time[" << std::to_string(timestamp)
        << "]:cur_time[" << std::to_string(cur_time) << "]:cur_latency["
        << start_latency << "]";
  PERCEPTION_PERF_BLOCK_START();
  // Init preprocessor_options
  radar::PreprocessorOptions preprocessor_options;
  ContiRadar corrected_obstacles;
  radar_preprocessor_->Preprocess(raw_obstacles, preprocessor_options,
                                  &corrected_obstacles);
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_preprocessor");
  timestamp = corrected_obstacles.header().timestamp_sec();

  out_message->timestamp_ = timestamp;
  out_message->seq_num_ = seq_num_;
  out_message->process_stage_ = ProcessStage::LONG_RANGE_RADAR_DETECTION;
  out_message->sensor_id_ = radar_info_.name;

  // Init radar perception options
  radar::RadarPerceptionOptions options;
  options.sensor_name = radar_info_.name;
  // Init detector_options
  Eigen::Affine3d radar_trans;
  if (!radar2world_trans_.GetSensor2worldTrans(timestamp, &radar_trans)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get pose at time: " << timestamp;
    return true;
  }
  Eigen::Affine3d radar2novatel_trans;
  if (!radar2novatel_trans_.GetTrans(timestamp, &radar2novatel_trans, "novatel",
                                    tf_child_frame_id_)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get radar2novatel trans at time: " << timestamp;
    return true;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetSensor2worldTrans");
  Eigen::Matrix4d radar2world_pose = radar_trans.matrix();
  options.detector_options.radar2world_pose = &radar2world_pose;
  Eigen::Matrix4d radar2novatel_trans_m = radar2novatel_trans.matrix();
  options.detector_options.radar2novatel_trans = &radar2novatel_trans_m;
  if (!GetCarLocalizationSpeed(
          timestamp, &(options.detector_options.car_linear_speed),
          &(options.detector_options.car_angular_speed))) {
    AERROR << "Failed to call get_car_speed. [timestamp: "
           << std::to_string(timestamp);
    // return false;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name, "GetCarSpeed");
  // Init roi_filter_options
  base::PointD position;
  position.x = radar_trans(0, 3);
  position.y = radar_trans(1, 3);
  position.z = radar_trans(2, 3);
  options.roi_filter_options.roi.reset(new base::HdmapStruct());
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_->GetRoiHDMapStruct(position, radar_forward_distance_,
                                    options.roi_filter_options.roi);
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetRoiHDMapStruct");
  // Init object_filter_options
  // Init track_options
  // Init object_builder_options
  std::vector<base::ObjectPtr> radar_objects;
  if (!radar_perception_->Perceive(corrected_obstacles, options,
                                  &radar_objects)) {
    out_message->error_code_ =
        apollo::common::ErrorCode::PERCEPTION_ERROR_PROCESS;
    AERROR << "RadarDetector Proc failed.";
    return true;
  }
  out_message->frame_.reset(new base::Frame());
  out_message->frame_->sensor_info = radar_info_;
  out_message->frame_->timestamp = timestamp;
  out_message->frame_->sensor2world_pose = radar_trans;
  out_message->frame_->objects = radar_objects;

  const double end_timestamp = lib::TimeUtil::GetCurrentTime();
  const double end_latency =
      (end_timestamp - in_message->header().timestamp_sec()) * 1e3;
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_perception");
  AINFO << "FRAME_STATISTICS:Radar:End:msg_time["
        << std::to_string(in_message->header().timestamp_sec()) << "]:cur_time["
        << std::to_string(end_timestamp) << "]:cur_latency[" << end_latency
        << "]";

  return true;
}

bool RadarDetectionComponent::GetCarLocalizationSpeed(
    double timestamp, Eigen::Vector3f* car_linear_speed,
    Eigen::Vector3f* car_angular_speed) {
  CHECK_NOTNULL(car_linear_speed);
  (*car_linear_speed) = Eigen::Vector3f::Zero();
  CHECK_NOTNULL(car_angular_speed);
  (*car_angular_speed) = Eigen::Vector3f::Zero();
  std::shared_ptr<LocalizationEstimate const> loct_ptr;
  if (!localization_subscriber_.LookupNearest(timestamp, &loct_ptr)) {
    AERROR << "Cannot get car speed.";
    return false;
  }
  (*car_linear_speed)[0] =
      static_cast<float>(loct_ptr->pose().linear_velocity().x());
  (*car_linear_speed)[1] =
      static_cast<float>(loct_ptr->pose().linear_velocity().y());
  (*car_linear_speed)[2] =
      static_cast<float>(loct_ptr->pose().linear_velocity().z());
  (*car_angular_speed)[0] =
      static_cast<float>(loct_ptr->pose().angular_velocity().x());
  (*car_angular_speed)[1] =
      static_cast<float>(loct_ptr->pose().angular_velocity().y());
  (*car_angular_speed)[2] =
      static_cast<float>(loct_ptr->pose().angular_velocity().z());

  return true;
}

}  // namespace onboard
}  // namespace perception
}  // namespace apollo
<commit_msg>Update radar_detection_component.cc<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include "modules/perception/onboard/component/radar_detection_component.h"
#include "modules/perception/common/sensor_manager/sensor_manager.h"
#include "modules/perception/lib/utils/perf.h"

namespace apollo {
namespace perception {
namespace onboard {

bool RadarDetectionComponent::Init() {
  RadarComponentConfig comp_config;
  if (!GetProtoConfig(&comp_config)) {
    return false;
  }
  AINFO << "Radar Component Configs: " << comp_config.DebugString();

  // To load component configs
  tf_child_frame_id_ = comp_config.tf_child_frame_id();
  radar_forward_distance_ = comp_config.radar_forward_distance();
  preprocessor_method_ = comp_config.radar_preprocessor_method();
  perception_method_ = comp_config.radar_perception_method();
  pipeline_name_ = comp_config.radar_pipeline_name();
  odometry_channel_name_ = comp_config.odometry_channel_name();

  if (!common::SensorManager::Instance()->GetSensorInfo(
      comp_config.radar_name(), &radar_info_)) {
    AERROR << "Failed to get sensor info, sensor name: "
           << comp_config.radar_name();
    return false;
  }

  writer_ = node_->CreateWriter<SensorFrameMessage>(
      comp_config.output_channel_name());

  // Init algorithm plugin
  CHECK(InitAlgorithmPlugin() == true) << "Failed to init algorithm plugin.";
  radar2world_trans_.Init(tf_child_frame_id_);
  radar2novatel_trans_.Init(tf_child_frame_id_);
  localization_subscriber_.Init(
      odometry_channel_name_,
      odometry_channel_name_ + '_' + comp_config.radar_name());
  return true;
}

bool RadarDetectionComponent::Proc(const std::shared_ptr<ContiRadar>& message) {
  AINFO << "Enter radar preprocess, message timestamp: "
        << std::to_string(message->header().timestamp_sec())
        << " current timestamp " << lib::TimeUtil::GetCurrentTime();
  std::shared_ptr<SensorFrameMessage> out_message(new (std::nothrow)
                                                      SensorFrameMessage);
  int status = InternalProc(message, out_message);
  if (status) {
    writer_->Write(out_message);
    AINFO << "Send radar processing output message.";
  }
  return status;
}

bool RadarDetectionComponent::InitAlgorithmPlugin() {
  AINFO << "onboard radar_preprocessor: " << preprocessor_method_;
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_ = map::HDMapInput::Instance();
    CHECK(hdmap_input_->Init()) << "Failed to init hdmap input.";
  }
  radar::BasePreprocessor* preprocessor =
      radar::BasePreprocessorRegisterer::GetInstanceByName(
          preprocessor_method_);
  CHECK_NOTNULL(preprocessor);
  radar_preprocessor_.reset(preprocessor);
  CHECK(radar_preprocessor_->Init()) << "Failed to init radar preprocessor.";
  radar::BaseRadarObstaclePerception* radar_perception =
      radar::BaseRadarObstaclePerceptionRegisterer::GetInstanceByName(
          perception_method_);
  CHECK(radar_perception != nullptr)
      << "No radar obstacle perception named: " << perception_method_;
  radar_perception_.reset(radar_perception);
  CHECK(radar_perception_->Init(pipeline_name_))
      << "Failed to init radar perception.";
  AINFO << "Init algorithm plugin successfully.";
  return true;
}

bool RadarDetectionComponent::InternalProc(
    const std::shared_ptr<ContiRadar>& in_message,
    std::shared_ptr<SensorFrameMessage> out_message) {
  PERCEPTION_PERF_FUNCTION_WITH_INDICATOR(radar_info_.name);
  ContiRadar raw_obstacles = *in_message;
  {
    std::unique_lock<std::mutex> lock(_mutex);
    ++seq_num_;
  }
  double timestamp = in_message->header().timestamp_sec();
  const double cur_time = lib::TimeUtil::GetCurrentTime();
  const double start_latency = (cur_time - timestamp) * 1e3;
  AINFO << "FRAME_STATISTICS:Radar:Start:msg_time[" << std::to_string(timestamp)
        << "]:cur_time[" << std::to_string(cur_time) << "]:cur_latency["
        << start_latency << "]";
  PERCEPTION_PERF_BLOCK_START();
  // Init preprocessor_options
  radar::PreprocessorOptions preprocessor_options;
  ContiRadar corrected_obstacles;
  radar_preprocessor_->Preprocess(raw_obstacles, preprocessor_options,
                                  &corrected_obstacles);
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_preprocessor");
  timestamp = corrected_obstacles.header().timestamp_sec();

  out_message->timestamp_ = timestamp;
  out_message->seq_num_ = seq_num_;
  out_message->process_stage_ = ProcessStage::LONG_RANGE_RADAR_DETECTION;
  out_message->sensor_id_ = radar_info_.name;

  // Init radar perception options
  radar::RadarPerceptionOptions options;
  options.sensor_name = radar_info_.name;
  // Init detector_options
  Eigen::Affine3d radar_trans;
  if (!radar2world_trans_.GetSensor2worldTrans(timestamp, &radar_trans)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get pose at time: " << timestamp;
    return true;
  }
  Eigen::Affine3d radar2novatel_trans;
  if (!radar2novatel_trans_.GetTrans(timestamp, &radar2novatel_trans, "novatel",
                                     tf_child_frame_id_)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get radar2novatel trans at time: " << timestamp;
    return true;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetSensor2worldTrans");
  Eigen::Matrix4d radar2world_pose = radar_trans.matrix();
  options.detector_options.radar2world_pose = &radar2world_pose;
  Eigen::Matrix4d radar2novatel_trans_m = radar2novatel_trans.matrix();
  options.detector_options.radar2novatel_trans = &radar2novatel_trans_m;
  if (!GetCarLocalizationSpeed(
          timestamp, &(options.detector_options.car_linear_speed),
          &(options.detector_options.car_angular_speed))) {
    AERROR << "Failed to call get_car_speed. [timestamp: "
           << std::to_string(timestamp);
    // return false;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name, "GetCarSpeed");
  // Init roi_filter_options
  base::PointD position;
  position.x = radar_trans(0, 3);
  position.y = radar_trans(1, 3);
  position.z = radar_trans(2, 3);
  options.roi_filter_options.roi.reset(new base::HdmapStruct());
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_->GetRoiHDMapStruct(position, radar_forward_distance_,
                                    options.roi_filter_options.roi);
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetRoiHDMapStruct");
  // Init object_filter_options
  // Init track_options
  // Init object_builder_options
  std::vector<base::ObjectPtr> radar_objects;
  if (!radar_perception_->Perceive(corrected_obstacles, options,
                                  &radar_objects)) {
    out_message->error_code_ =
        apollo::common::ErrorCode::PERCEPTION_ERROR_PROCESS;
    AERROR << "RadarDetector Proc failed.";
    return true;
  }
  out_message->frame_.reset(new base::Frame());
  out_message->frame_->sensor_info = radar_info_;
  out_message->frame_->timestamp = timestamp;
  out_message->frame_->sensor2world_pose = radar_trans;
  out_message->frame_->objects = radar_objects;

  const double end_timestamp = lib::TimeUtil::GetCurrentTime();
  const double end_latency =
      (end_timestamp - in_message->header().timestamp_sec()) * 1e3;
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_perception");
  AINFO << "FRAME_STATISTICS:Radar:End:msg_time["
        << std::to_string(in_message->header().timestamp_sec()) << "]:cur_time["
        << std::to_string(end_timestamp) << "]:cur_latency[" << end_latency
        << "]";

  return true;
}

bool RadarDetectionComponent::GetCarLocalizationSpeed(
    double timestamp, Eigen::Vector3f* car_linear_speed,
    Eigen::Vector3f* car_angular_speed) {
  CHECK_NOTNULL(car_linear_speed);
  (*car_linear_speed) = Eigen::Vector3f::Zero();
  CHECK_NOTNULL(car_angular_speed);
  (*car_angular_speed) = Eigen::Vector3f::Zero();
  std::shared_ptr<LocalizationEstimate const> loct_ptr;
  if (!localization_subscriber_.LookupNearest(timestamp, &loct_ptr)) {
    AERROR << "Cannot get car speed.";
    return false;
  }
  (*car_linear_speed)[0] =
      static_cast<float>(loct_ptr->pose().linear_velocity().x());
  (*car_linear_speed)[1] =
      static_cast<float>(loct_ptr->pose().linear_velocity().y());
  (*car_linear_speed)[2] =
      static_cast<float>(loct_ptr->pose().linear_velocity().z());
  (*car_angular_speed)[0] =
      static_cast<float>(loct_ptr->pose().angular_velocity().x());
  (*car_angular_speed)[1] =
      static_cast<float>(loct_ptr->pose().angular_velocity().y());
  (*car_angular_speed)[2] =
      static_cast<float>(loct_ptr->pose().angular_velocity().z());

  return true;
}

}  // namespace onboard
}  // namespace perception
}  // namespace apollo
<|endoftext|>