<commit_before>/*
 *  Copyright 2008-2010 NVIDIA Corporation
 *
 *  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 <thrust/copy.h>
#include <thrust/gather.h>
#include <thrust/sequence.h>
#include <thrust/iterator/iterator_traits.h>

#include <thrust/detail/raw_buffer.h>
#include <thrust/detail/type_traits.h>
#include <thrust/detail/util/align.h>

#include <thrust/detail/device/cuda/detail/b40c/radixsort_api.h>

namespace thrust
{
namespace detail
{
namespace device
{
namespace cuda
{
namespace detail
{

template<typename RandomAccessIterator>
void stable_radix_sort(RandomAccessIterator first,
                       RandomAccessIterator last)
{
    typedef typename thrust::iterator_value<RandomAccessIterator>::type K;

    unsigned int num_elements = last - first;

    // ensure data is properly aligned
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first), 2*sizeof(K)))
    {
        thrust::detail::raw_cuda_device_buffer<K> aligned_keys(first, last);
        stable_radix_sort(aligned_keys.begin(), aligned_keys.end());
        thrust::copy(aligned_keys.begin(), aligned_keys.end(), first);
        return;
    }

    b40c::RadixSortingEnactor<K> sorter(num_elements);
    b40c::RadixSortStorage<K>    storage;

    // allocate temporary buffers
    thrust::detail::raw_cuda_device_buffer<K>            temp_keys(num_elements);
    thrust::detail::raw_cuda_device_buffer<unsigned int> temp_spine(sorter.SpineElements());
    thrust::detail::raw_cuda_device_buffer<bool>         temp_from_alt(2);

    // define storage
    storage.d_keys             = thrust::raw_pointer_cast(&*first);
    storage.d_alt_keys         = thrust::raw_pointer_cast(&temp_keys[0]);
    storage.d_spine            = thrust::raw_pointer_cast(&temp_spine[0]);
    storage.d_from_alt_storage = thrust::raw_pointer_cast(&temp_from_alt[0]);

    // perform the sort
    sorter.EnactSort(storage);

    // radix sort sometimes leaves results in the alternate buffers
    if (storage.using_alternate_storage)
    {
        thrust::copy(temp_keys.begin(), temp_keys.end(), first);
    }

    // temporary storage automatically freed
}

///////////////////////
// Key-Value Sorting //
///////////////////////

// sort values directly
template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              thrust::detail::true_type)
{
    typedef typename thrust::iterator_value<RandomAccessIterator1>::type K;
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    unsigned int num_elements = last1 - first1;

    // ensure data is properly aligned
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first1), 2*sizeof(K)))
    {
        thrust::detail::raw_cuda_device_buffer<K> aligned_keys(first1, last1);
        stable_radix_sort_by_key(aligned_keys.begin(), aligned_keys.end(), first2);
        thrust::copy(aligned_keys.begin(), aligned_keys.end(), first1);
        return;
    }
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first2), 2*sizeof(V)))
    {
        thrust::detail::raw_cuda_device_buffer<V> aligned_values(first2, first2 + num_elements);
        stable_radix_sort_by_key(first1, last1, aligned_values.begin());
        thrust::copy(aligned_values.begin(), aligned_values.end(), first2);
        return;
    }

    b40c::RadixSortingEnactor<K,V> sorter(num_elements);
    b40c::RadixSortStorage<K,V>    storage;

    // allocate temporary buffers
    thrust::detail::raw_cuda_device_buffer<K>            temp_keys(num_elements);
    thrust::detail::raw_cuda_device_buffer<V>            temp_values(num_elements);
    thrust::detail::raw_cuda_device_buffer<unsigned int> temp_spine(sorter.SpineElements());
    thrust::detail::raw_cuda_device_buffer<bool>         temp_from_alt(2);

    // define storage
    storage.d_keys             = thrust::raw_pointer_cast(&*first1);
    storage.d_values           = thrust::raw_pointer_cast(&*first2);
    storage.d_alt_keys         = thrust::raw_pointer_cast(&temp_keys[0]);
    storage.d_alt_values       = thrust::raw_pointer_cast(&temp_values[0]);
    storage.d_spine            = thrust::raw_pointer_cast(&temp_spine[0]);
    storage.d_from_alt_storage = thrust::raw_pointer_cast(&temp_from_alt[0]);

    // perform the sort
    sorter.EnactSort(storage);

    // radix sort sometimes leaves results in the alternate buffers
    if (storage.using_alternate_storage)
    {
        thrust::copy(  temp_keys.begin(),   temp_keys.end(), first1);
        thrust::copy(temp_values.begin(), temp_values.end(), first2);
    }

    // temporary storage automatically freed
}

// sort values indirectly
template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              thrust::detail::false_type)
{
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    unsigned int num_elements = last1 - first1;

    // sort with integer values and then permute the real values accordingly
    thrust::detail::raw_cuda_device_buffer<unsigned int> permutation(num_elements);
    thrust::sequence(permutation.begin(), permutation.end());

    stable_radix_sort_by_key(first1, last1, permutation.begin());

    // copy values into temp vector and then permute
    thrust::detail::raw_cuda_device_buffer<V> temp_values(first2, first2 + num_elements);

    // permute values
    thrust::gather(permutation.begin(), permutation.end(),
                   temp_values.begin(),
                   first2);
}

template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2)
{
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    // decide how to handle values
    static const bool sort_values_directly = thrust::detail::is_trivial_iterator<RandomAccessIterator2>::value &&
                                             thrust::detail::is_arithmetic<V>::value &&
                                             sizeof(V) <= 8;    // TODO profile this

    // XXX WAR nvcc 3.0 unused variable warning
    (void) sort_values_directly;

    stable_radix_sort_by_key(first1, last1, first2,
                             thrust::detail::integral_constant<bool, sort_values_directly>());
}

} // end namespace detail
} // end namespace cuda
} // end namespace device
} // end namespace detail
} // end namespace thrust

<commit_msg>access b40c namespace via full path<commit_after>/*
 *  Copyright 2008-2010 NVIDIA Corporation
 *
 *  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 <thrust/copy.h>
#include <thrust/gather.h>
#include <thrust/sequence.h>
#include <thrust/iterator/iterator_traits.h>

#include <thrust/detail/raw_buffer.h>
#include <thrust/detail/type_traits.h>
#include <thrust/detail/util/align.h>

#include <thrust/detail/device/cuda/detail/b40c/radixsort_api.h>

namespace thrust
{
namespace detail
{
namespace device
{
namespace cuda
{
namespace detail
{

template<typename RandomAccessIterator>
void stable_radix_sort(RandomAccessIterator first,
                       RandomAccessIterator last)
{
    typedef typename thrust::iterator_value<RandomAccessIterator>::type K;

    unsigned int num_elements = last - first;

    // ensure data is properly aligned
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first), 2*sizeof(K)))
    {
        thrust::detail::raw_cuda_device_buffer<K> aligned_keys(first, last);
        stable_radix_sort(aligned_keys.begin(), aligned_keys.end());
        thrust::copy(aligned_keys.begin(), aligned_keys.end(), first);
        return;
    }

    thrust::detail::device::cuda::detail::b40c::RadixSortingEnactor<K> sorter(num_elements);
    thrust::detail::device::cuda::detail::b40c::RadixSortStorage<K>    storage;

    // allocate temporary buffers
    thrust::detail::raw_cuda_device_buffer<K>            temp_keys(num_elements);
    thrust::detail::raw_cuda_device_buffer<unsigned int> temp_spine(sorter.SpineElements());
    thrust::detail::raw_cuda_device_buffer<bool>         temp_from_alt(2);

    // define storage
    storage.d_keys             = thrust::raw_pointer_cast(&*first);
    storage.d_alt_keys         = thrust::raw_pointer_cast(&temp_keys[0]);
    storage.d_spine            = thrust::raw_pointer_cast(&temp_spine[0]);
    storage.d_from_alt_storage = thrust::raw_pointer_cast(&temp_from_alt[0]);

    // perform the sort
    sorter.EnactSort(storage);

    // radix sort sometimes leaves results in the alternate buffers
    if (storage.using_alternate_storage)
    {
        thrust::copy(temp_keys.begin(), temp_keys.end(), first);
    }

    // temporary storage automatically freed
}

///////////////////////
// Key-Value Sorting //
///////////////////////

// sort values directly
template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              thrust::detail::true_type)
{
    typedef typename thrust::iterator_value<RandomAccessIterator1>::type K;
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    unsigned int num_elements = last1 - first1;

    // ensure data is properly aligned
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first1), 2*sizeof(K)))
    {
        thrust::detail::raw_cuda_device_buffer<K> aligned_keys(first1, last1);
        stable_radix_sort_by_key(aligned_keys.begin(), aligned_keys.end(), first2);
        thrust::copy(aligned_keys.begin(), aligned_keys.end(), first1);
        return;
    }
    if (!thrust::detail::util::is_aligned(thrust::raw_pointer_cast(&*first2), 2*sizeof(V)))
    {
        thrust::detail::raw_cuda_device_buffer<V> aligned_values(first2, first2 + num_elements);
        stable_radix_sort_by_key(first1, last1, aligned_values.begin());
        thrust::copy(aligned_values.begin(), aligned_values.end(), first2);
        return;
    }

    thrust::detail::device::cuda::detail::b40c::RadixSortingEnactor<K,V> sorter(num_elements);
    thrust::detail::device::cuda::detail::b40c::RadixSortStorage<K,V>    storage;

    // allocate temporary buffers
    thrust::detail::raw_cuda_device_buffer<K>            temp_keys(num_elements);
    thrust::detail::raw_cuda_device_buffer<V>            temp_values(num_elements);
    thrust::detail::raw_cuda_device_buffer<unsigned int> temp_spine(sorter.SpineElements());
    thrust::detail::raw_cuda_device_buffer<bool>         temp_from_alt(2);

    // define storage
    storage.d_keys             = thrust::raw_pointer_cast(&*first1);
    storage.d_values           = thrust::raw_pointer_cast(&*first2);
    storage.d_alt_keys         = thrust::raw_pointer_cast(&temp_keys[0]);
    storage.d_alt_values       = thrust::raw_pointer_cast(&temp_values[0]);
    storage.d_spine            = thrust::raw_pointer_cast(&temp_spine[0]);
    storage.d_from_alt_storage = thrust::raw_pointer_cast(&temp_from_alt[0]);

    // perform the sort
    sorter.EnactSort(storage);

    // radix sort sometimes leaves results in the alternate buffers
    if (storage.using_alternate_storage)
    {
        thrust::copy(  temp_keys.begin(),   temp_keys.end(), first1);
        thrust::copy(temp_values.begin(), temp_values.end(), first2);
    }

    // temporary storage automatically freed
}

// sort values indirectly
template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              thrust::detail::false_type)
{
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    unsigned int num_elements = last1 - first1;

    // sort with integer values and then permute the real values accordingly
    thrust::detail::raw_cuda_device_buffer<unsigned int> permutation(num_elements);
    thrust::sequence(permutation.begin(), permutation.end());

    stable_radix_sort_by_key(first1, last1, permutation.begin());

    // copy values into temp vector and then permute
    thrust::detail::raw_cuda_device_buffer<V> temp_values(first2, first2 + num_elements);

    // permute values
    thrust::gather(permutation.begin(), permutation.end(),
                   temp_values.begin(),
                   first2);
}

template<typename RandomAccessIterator1,
         typename RandomAccessIterator2>
void stable_radix_sort_by_key(RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2)
{
    typedef typename thrust::iterator_value<RandomAccessIterator2>::type V;

    // decide how to handle values
    static const bool sort_values_directly = thrust::detail::is_trivial_iterator<RandomAccessIterator2>::value &&
                                             thrust::detail::is_arithmetic<V>::value &&
                                             sizeof(V) <= 8;    // TODO profile this

    // XXX WAR nvcc 3.0 unused variable warning
    (void) sort_values_directly;

    stable_radix_sort_by_key(first1, last1, first2,
                             thrust::detail::integral_constant<bool, sort_values_directly>());
}

} // end namespace detail
} // end namespace cuda
} // end namespace device
} // end namespace detail
} // end namespace thrust

<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_QUAD_FORM_SYM_HPP
#define STAN_MATH_REV_FUN_QUAD_FORM_SYM_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/rev/fun/quad_form.hpp>
#include <type_traits>

namespace stan {
namespace math {

/**
 * Return the quadratic form \f$ B^T A B \f$ of a symmetric matrix.
 *
 * Symmetry of the resulting matrix is guaranteed.
 *
 * @tparam EigMat1 type of the first (symmetric) matrix
 * @tparam EigMat2 type of the second matrix
 *
 * @param A symmetric matrix
 * @param B second matrix
 * @return The quadratic form, which is a symmetric matrix of size Cb.
 * If \c B is a column vector returns a scalar.
 * @throws std::invalid_argument if A is not symmetric, or if A cannot be
 * multiplied by B
 */
template <typename EigMat1, typename EigMat2,
          require_all_eigen_t<EigMat1, EigMat2>* = nullptr,
          require_any_vt_var<EigMat1, EigMat2>* = nullptr>
inline auto quad_form_sym(const EigMat1& A, const EigMat2& B) {
  check_multiplicable("quad_form_sym", "A", A, "B", B);
  const auto& A_ref = to_ref(A);
  check_symmetric("quad_form_sym", "A", A_ref);
  return quad_form(A_ref, B);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>fixes #2095; using the symmetric version of quad_form<commit_after>#ifndef STAN_MATH_REV_FUN_QUAD_FORM_SYM_HPP
#define STAN_MATH_REV_FUN_QUAD_FORM_SYM_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/rev/fun/quad_form.hpp>
#include <type_traits>

namespace stan {
namespace math {

/**
 * Return the quadratic form \f$ B^T A B \f$ of a symmetric matrix.
 *
 * Symmetry of the resulting matrix is guaranteed.
 *
 * @tparam EigMat1 type of the first (symmetric) matrix
 * @tparam EigMat2 type of the second matrix
 *
 * @param A symmetric matrix
 * @param B second matrix
 * @return The quadratic form, which is a symmetric matrix of size Cb.
 * If \c B is a column vector returns a scalar.
 * @throws std::invalid_argument if A is not symmetric, or if A cannot be
 * multiplied by B
 */
template <typename EigMat1, typename EigMat2,
          require_all_eigen_t<EigMat1, EigMat2>* = nullptr,
          require_any_vt_var<EigMat1, EigMat2>* = nullptr>
inline auto quad_form_sym(const EigMat1& A, const EigMat2& B) {
  check_multiplicable("quad_form_sym", "A", A, "B", B);
  const auto& A_ref = to_ref(A);
  check_symmetric("quad_form_sym", "A", A_ref);
  return quad_form(A_ref, B, true);
}

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


<commit_before>/*
    matrix.cpp

    Purpose: A Matrix implementation to ease future problems that
    could more efficiently be solved with Matrix abstraction.

    @author c650
    @version 0.1 1/10/16

    The MIT License (MIT)

    Copyright (c) 2016 c650

*/
#include <iostream>
#include <vector>
#include <cstdlib>

/*
    Begin the Matrix class:
*/
template <typename T> class Matrix {
    /*
        `elements` is a 2D array that is
         a vector of the rows of the matrix.
    */
    std::vector< std::vector<T> > elements;

public:
    /*
        Constructors:
    */
    /*
        Makes a new instance of Matrix

        @param elem a 2D vector that represents what a
        Matrix actually is.

        @return a new instance of Matrix
    */
    Matrix(std::vector< std::vector<T> > elem) : elements(elem) {}
    /*
        Makes a new instance of Matrix

        @param m another instance of Matrix to copy
        using func get_all_elements()

        @return a new instance of Matrix
    */
    Matrix(Matrix &m) : elements(m.elements) {}
    /*
        Makes a new, empty instance of Matrix

        @param rows the number of rows desired
        @param cols the number of columns desired

        @return a new instance of Matrix
    */
    Matrix(const int &rows, const int &cols) {
        std::vector< std::vector<T> > _elem(rows, std::vector<T>(cols));
        elements = _elem;
    }

    /*
        REMEMBER THE DESTRUCTOR
    */
    ~Matrix();

    /*
        Column and Row Size Getters:
    */
    /*
        Returns the number of columns in an instance
        of Matrix

        @return the number of columns
    */
    int num_cols() {
        return elements[0].size();
    }
    /*
        Returns the number of rows for an instance of
        Matrix

        @return the number of columns
    */
    int num_rows() {
        return elements.size();
    }

    /*
        Returns a vector representing a row in the Matrix

    */
    std::vector<T> operator[](const int &rhs) {
        if (abs(rhs) > num_rows()) {
            throw "operator[] in Matrix out of bounds";
        }

        if (rhs >= 0) {
            return elements[rhs];
        } else {
            return elements[num_rows() + rhs];
        }

    }
    /*
        Element Getter and Setter:
    */
    /*
        Changes the value of a given position in
        the Matrix.

        @param row the row that holds the value to change
        @param col the column of the value to change
        @param val the value to set
    */
    void set(const int &row, const int &col, T const &val) {
        if (this->num_cols() > col && this->num_rows() > row)
            elements[row][col] = val;
    }
    /*
        Gets the value held at a certain position in
        the Matrix.

        @param row the row to read from
        @param col the column to read from

        @return the value of type T held at the positon
        row,col in the Matrix
    */
    T get(const int &row, const int &col) {
        if (this->num_cols() > col && this->num_rows() > row)
            return elements[row][col];
        else
            return 0;
    }
    /*
        Matrix Arithmetic Methods
    */
    /*
        ADDITION:

        Binary operator to add two matrices together.
        Does not modify either matrix.

        @param other the Matrix on the right side of +

        @return a Matrix, whose elements are the sums of
        the corresponding elements of `this` and `other`
    */
    Matrix<T> operator+(Matrix<T> &other) {
        // Matrices must be same dimensions to
        // be addable
        if (this->num_rows() != other.num_rows() || this->num_cols() != other.num_cols())
            return *this;

        // make matrix based on `this`
        Matrix<T> resultant(*this);

        for (int i = 0, n = this->num_rows(); i < n; i++) {
            for (int j = 0, o = this->num_cols(); j < o; j++) {
                // set each value in the resultant equal
                // to the sum of the corresponding values
                // in `this` and `other`
                resultant.set(i, j, this->get(i, j) + other.get(i, j));
            }
        }

        return resultant;
    }
    /*
        SUBTRACTION:

        Binary operator to subtract two matrices.
        Does not modify either matrix.

        @param other the Matrix on the right side of -

        @return a Matrix, whose elements are the differences of
        the corresponding elements of `this` and `other`
    */
    Matrix<T> operator-(Matrix<T> &other) {
        return (*this) + (other * -1);
    }
    /*
        MATRIX*MATRIX MULTIPLICATION

        Binary operator to multiple two matrices.
        Does not modify either matrix.

        @param other the Matrix on the right side of *

        @return a Matrix, whose elements are the products of
        the corresponding elements of `this` and `other`, following
        the accepted way of multiplying matrices.
    */
    Matrix<T> operator*(Matrix<T> &other) {
        Matrix<T> resultant(this->num_rows(), other.num_cols());

        if (this->num_cols() != other.num_rows())
            return *this;

        // go through all rows of the left Matrix
        for (int i = 0, n = this->num_rows(); i < n; i++) {

            // go through all columns of right Matrix for each row
            // of the left Matrix

            for (int j = 0, o = other.num_cols(); j < o; j++) {

                T tmp = 0;

                int x = 0;
                while (x < n) {
                    tmp += (this->get(i, x) * other.get(x, j));
                    x++;
                }

                resultant.set(i, j, tmp); // put the tmp into the resultant
            }
        }
        return resultant;
    }
    /*
        MATRIX*SCALAR MULTIPLICATION

        Multiplies a Matrix by a scalar value.

        @param other the scalar value

        @return the result of scaling `this` by `other`
    */
    Matrix<T> operator*(T &other) {
        Matrix<T> resultant(*this);

        for (int i = 0, n = this->num_rows(); i < n; i++) {
            for (int j = 0, o = this->num_cols(); j < o; j++) {
                resultant.elements[i][j] *= other;
            }
        }

        return resultant;
    }
    /*
        Matrix Power Method
        Powers >= 1 only!

        @param p an unsigned integer >= 1 to which the Matrix will
        be raised.

        @return the Matrix raised to the `p` power
    */
    Matrix power(const unsigned int &p) {
        if (p == 1)
            return *this;
        else if (p <= 0) // set for now to keep it safe
            return *this;

        Matrix m(*this);

        m = m.power(p / 2);
        m = m * m;

        if (p % 2 == 1)
            m = m * (*this);
        return m;
    }
    /*
        Matrix Printer
        Formats the Matrix for STDOUT
    */
    std::ostream& operator<<(std::ostream& out) {
        for (int i = 0, n = this.num_rows(); i < n; i++) {
            out << "| ";
            for (int j = 0, o = this.num_cols(); j < o; j++) {
                out << this.elements[i][j] << " ";
            }
            out << "|" << std::endl;
        }

        return out;
    }
};

int main() {
    return 0;
}<commit_msg>fixing throw erros<commit_after>/*
    matrix.cpp

    Purpose: A Matrix implementation to ease future problems that
    could more efficiently be solved with Matrix abstraction.

    @author c650
    @version 0.1 1/10/16

    The MIT License (MIT)

    Copyright (c) 2016 c650

*/
#include <iostream>
#include <vector>
#include <cstdlib>

/*
    Begin the Matrix class:
*/
template <typename T> class Matrix {
    /*
        `elements` is a 2D array that is
         a vector of the rows of the matrix.
    */
    std::vector< std::vector<T> > elements;

public:
    /*
        Constructors:
    */
    /*
        Makes a new instance of Matrix

        @param elem a 2D vector that represents what a
        Matrix actually is.

        @return a new instance of Matrix
    */
    Matrix(std::vector< std::vector<T> > elem) : elements(elem) {}
    /*
        Makes a new instance of Matrix

        @param m another instance of Matrix to copy
        using func get_all_elements()

        @return a new instance of Matrix
    */
    Matrix(Matrix &m) : elements(m.elements) {}
    /*
        Makes a new, empty instance of Matrix

        @param rows the number of rows desired
        @param cols the number of columns desired

        @return a new instance of Matrix
    */
    Matrix(const int &rows, const int &cols) {
        std::vector< std::vector<T> > _elem(rows, std::vector<T>(cols));
        elements = _elem;
    }

    /*
        REMEMBER THE DESTRUCTOR
    */
    ~Matrix();

    /*
        Column and Row Size Getters:
    */
    /*
        Returns the number of columns in an instance
        of Matrix

        @return the number of columns
    */
    int num_cols() {
        return elements[0].size();
    }
    /*
        Returns the number of rows for an instance of
        Matrix

        @return the number of columns
    */
    int num_rows() {
        return elements.size();
    }

    /*
        Returns a vector representing a row in the Matrix

    */
    std::vector<T> operator[](const int &rhs) {
        if (abs(rhs) > num_rows()) {
            throw std::invalid_argument("operator[] in Matrix out of bounds");
        }

        if (rhs >= 0) {
            return elements[rhs];
        } else {
            return elements[num_rows() + rhs];
        }

    }
    /*
        Element Getter and Setter:
    */
    /*
        Changes the value of a given position in
        the Matrix.

        @param row the row that holds the value to change
        @param col the column of the value to change
        @param val the value to set
    */
    void set(const int &row, const int &col, T const &val) {
        if (this->num_cols() > col && this->num_rows() > row)
            elements[row][col] = val;
    }
    /*
        Gets the value held at a certain position in
        the Matrix.

        @param row the row to read from
        @param col the column to read from

        @return the value of type T held at the positon
        row,col in the Matrix
    */
    T get(const int &row, const int &col) {
        if (this->num_cols() > col && this->num_rows() > row)
            return elements[row][col];
        else
            return 0;
    }
    /*
        Matrix Arithmetic Methods
    */
    /*
        ADDITION:

        Binary operator to add two matrices together.
        Does not modify either matrix.

        @param other the Matrix on the right side of +

        @return a Matrix, whose elements are the sums of
        the corresponding elements of `this` and `other`
    */
    Matrix<T> operator+(Matrix<T> &other) {
        // Matrices must be same dimensions to
        // be addable
        if (this->num_rows() != other.num_rows() || this->num_cols() != other.num_cols())
            throw std::invalid_argument("these Matrices cannot be added/subtracted");

        // make matrix based on `this`
        Matrix<T> resultant(*this);

        for (int i = 0, n = this->num_rows(); i < n; i++) {
            for (int j = 0, o = this->num_cols(); j < o; j++) {
                // set each value in the resultant equal
                // to the sum of the corresponding values
                // in `this` and `other`
                resultant.set(i, j, this->get(i, j) + other.get(i, j));
            }
        }

        return resultant;
    }
    /*
        SUBTRACTION:

        Binary operator to subtract two matrices.
        Does not modify either matrix.

        @param other the Matrix on the right side of -

        @return a Matrix, whose elements are the differences of
        the corresponding elements of `this` and `other`
    */
    Matrix<T> operator-(Matrix<T> &other) {
        return (*this) + (other * -1);
    }
    /*
        MATRIX*MATRIX MULTIPLICATION

        Binary operator to multiple two matrices.
        Does not modify either matrix.

        @param other the Matrix on the right side of *

        @return a Matrix, whose elements are the products of
        the corresponding elements of `this` and `other`, following
        the accepted way of multiplying matrices.
    */
    Matrix<T> operator*(Matrix<T> &other) {
        Matrix<T> resultant(this->num_rows(), other.num_cols());

        if (this->num_cols() != other.num_rows())
            throw std::invalid_argument("these Matrices cannot be multiplied");

        // go through all rows of the left Matrix
        for (int i = 0, n = this->num_rows(); i < n; i++) {

            // go through all columns of right Matrix for each row
            // of the left Matrix

            for (int j = 0, o = other.num_cols(); j < o; j++) {

                T tmp = 0;

                int x = 0;
                while (x < n) {
                    tmp += (this->get(i, x) * other.get(x, j));
                    x++;
                }

                resultant.set(i, j, tmp); // put the tmp into the resultant
            }
        }
        return resultant;
    }
    /*
        MATRIX*SCALAR MULTIPLICATION

        Multiplies a Matrix by a scalar value.

        @param other the scalar value

        @return the result of scaling `this` by `other`
    */
    Matrix<T> operator*(T &other) {
        Matrix<T> resultant(*this);

        for (int i = 0, n = this->num_rows(); i < n; i++) {
            for (int j = 0, o = this->num_cols(); j < o; j++) {
                resultant.elements[i][j] *= other;
            }
        }

        return resultant;
    }
    /*
        Matrix Power Method
        Powers >= 1 only!

        @param p an unsigned integer >= 1 to which the Matrix will
        be raised.

        @return the Matrix raised to the `p` power
    */
    Matrix power(const unsigned int &p) {
        if (p == 1)
            return *this;
        else if (p <= 0) // set for now to keep it safe
            return *this;

        Matrix m(*this);

        m = m.power(p / 2);
        m = m * m;

        if (p % 2 == 1)
            m = m * (*this);
        return m;
    }
    /*
        Matrix Printer
        Formats the Matrix for STDOUT
    */
    std::ostream& operator<<(std::ostream& out) {
        for (int i = 0, n = this.num_rows(); i < n; i++) {
            out << "| ";
            for (int j = 0, o = this.num_cols(); j < o; j++) {
                out << this.elements[i][j] << " ";
            }
            out << "|" << std::endl;
        }

        return out;
    }
};

int main() {
    return 0;
}<|endoftext|>


<commit_before>#include "MechanicsFwd.hpp"
#include "NewtonEulerDS.hpp"
#include "RigidBody2dDS.hpp"
#include "SiconosContactor.hpp"
RigidBody2dDS::RigidBody2dDS(SP::SiconosVector position,
                             SP::SiconosVector velocity,
                             SP::SiconosMatrix  mass)
  : LagrangianLinearTIDS(position, velocity, mass)
  , _contactors(std::make_shared<SiconosContactorSet>())
  , _useContactorInertia(true)
  , _allowSelfCollide(true)
{
  // Check size of positions, velocities and mass matrix
  _scalarMass = mass->getValue(0,0);
}

RigidBody2dDS::RigidBody2dDS(SP::SiconosVector position,
                             SP::SiconosVector velocity,
                             double mass,
                             double inertia)
  : LagrangianLinearTIDS(position, velocity, SP::SimpleMatrix(new SimpleMatrix(3,3)))
  ,_scalarMass(mass)
  , _contactors(std::make_shared<SiconosContactorSet>())
  , _useContactorInertia(true)
  , _allowSelfCollide(true)
{
  _mass->setValue(0,0,mass);
  _mass->setValue(1,1,mass);
  _mass->setValue(2,2,inertia);

  // Check size of positions, velocities and mass matrix
}

RigidBody2dDS::~RigidBody2dDS()
{
}
<commit_msg>[mechanics] check size of position and velocity<commit_after>#include "MechanicsFwd.hpp"
#include "NewtonEulerDS.hpp"
#include "RigidBody2dDS.hpp"
#include "SiconosContactor.hpp"
RigidBody2dDS::RigidBody2dDS(SP::SiconosVector position,
                             SP::SiconosVector velocity,
                             SP::SiconosMatrix  mass)
  : LagrangianLinearTIDS(position, velocity, mass)
  , _contactors(std::make_shared<SiconosContactorSet>())
  , _useContactorInertia(true)
  , _allowSelfCollide(true)
{
  // Check size of positions, velocities and mass matrix
  if((position->size() !=3) or (velocity->size() !=3))
  {
    THROW_EXCEPTION("RigidBody2dDS::RigidBody2dDS(...). The size of position and velocity must of size 3");
  }

  _scalarMass = mass->getValue(0,0);
}

RigidBody2dDS::RigidBody2dDS(SP::SiconosVector position,
                             SP::SiconosVector velocity,
                             double mass,
                             double inertia)
  : LagrangianLinearTIDS(position, velocity, SP::SimpleMatrix(new SimpleMatrix(3,3)))
  ,_scalarMass(mass)
  , _contactors(std::make_shared<SiconosContactorSet>())
  , _useContactorInertia(true)
  , _allowSelfCollide(true)
{
  _mass->setValue(0,0,mass);
  _mass->setValue(1,1,mass);
  _mass->setValue(2,2,inertia);

  // Check size of positions, velocities and mass matrix
    if((position->size() !=3) or (velocity->size() !=3))
  {
    THROW_EXCEPTION("RigidBody2dDS::RigidBody2dDS(...). The size of position and velocity must of size 3");
  }

}

RigidBody2dDS::~RigidBody2dDS()
{
}
<|endoftext|>


<commit_before>//
//  HttpRequestSystem.cpp
//  Chilli Source
//  Created by Scott Downie on 23/05/2011.
//
//  The MIT License (MIT)
//
//  Copyright (c) 2011 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#ifdef CS_TARGETPLATFORM_WINDOWS

#include <CSBackend/Platform/Windows/Networking/Http/HttpRequestSystem.h>

#include <CSBackend/Platform/Windows/Core/String/WindowsStringUtils.h>
#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Threading/TaskScheduler.h>

#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp")

namespace CSBackend
{
	namespace Windows
	{
		namespace
		{
			//--------------------------------------------------------------------------------------------------
			/// Setup the request to use SSL level 3
			///
			/// @author S Downie
			///
			/// @param Request handle
			///
			/// @return Success or failure
			//--------------------------------------------------------------------------------------------------
			bool ApplySSLSettings(HINTERNET in_requestHandle)
			{
				DWORD requestOptions = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
				if (!WinHttpSetOption(in_requestHandle, WINHTTP_OPTION_SECURITY_FLAGS, &requestOptions, sizeof(DWORD)))
				{
					CS_LOG_ERROR("Failed to set HTTP SSL security flag options");
					return false;
				}

				return true;
			}
			//--------------------------------------------------------------------------------------------------
			/// Convert param dictionary to header format required by WinHTTP
			///
			/// @author S Downie
			///
			/// @param Header dictionary
			///
			/// @return Header blob
			//--------------------------------------------------------------------------------------------------
			std::wstring ConvertHeaders(const ChilliSource::ParamDictionary& in_headers)
			{
				//The headers must be passed as a single string with each header except the last
				//terminated by a carraige return/line feed
				std::string headerBlob;
				for (auto it = in_headers.begin(); it != in_headers.end(); ++it)
				{
					headerBlob += it->first;
					headerBlob += ": ";
					headerBlob += it->second;
					headerBlob += '\r';
					headerBlob += '\n';
				}

				CS_ASSERT(headerBlob.length() > 2, "Http: Cannot convert empty headers");

				std::wstring headerBlobWide(headerBlob.length() - 2, L' ');
				std::copy(headerBlob.begin(), headerBlob.end()-2, headerBlobWide.begin());
				return headerBlobWide;
			}
		}

		CS_DEFINE_NAMEDTYPE(HttpRequestSystem);

		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnInit()
		{
			m_sessionHandle = ::WinHttpOpen(L"CSWinHttpClient", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
			CS_ASSERT(m_sessionHandle != nullptr, "Failed to open WinHTTP session");
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		bool HttpRequestSystem::IsA(ChilliSource::InterfaceIDType in_interfaceId) const
		{
			return in_interfaceId == ChilliSource::HttpRequestSystem::InterfaceID || in_interfaceId == HttpRequestSystem::InterfaceID;
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeGetRequest(const std::string& in_url, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_get, in_url, "", ChilliSource::ParamDictionary(), in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeGetRequest(const std::string& in_url, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_get, in_url, "", in_headers, in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakePostRequest(const std::string& in_url, const std::string& in_body, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_post, in_url, in_body, ChilliSource::ParamDictionary(), in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakePostRequest(const std::string& in_url, const std::string& in_body, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_post, in_url, in_body, in_headers, in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeRequest(HttpRequest::Type in_type, const std::string& in_url, const std::string& in_body, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			CS_ASSERT(ChilliSource::Application::Get()->GetTaskScheduler()->IsMainThread() == true, "Http requests can currently only be made on the main thread");
			CS_ASSERT(in_delegate != nullptr, "Cannot make an http request with a null delegate");
			CS_ASSERT(in_url.empty() == false, "Cannot make an http request to a blank url");

			URL_COMPONENTS urlComps;

			//Initialize the URL_COMPONENTS structure.
			ZeroMemory(&urlComps, sizeof(URL_COMPONENTS));
			urlComps.dwStructSize = sizeof(URL_COMPONENTS);

			//Set required component lengths to non-zero so that they are cracked.
			urlComps.dwSchemeLength    = (DWORD)-1;
			urlComps.dwHostNameLength  = (DWORD)-1;
			urlComps.dwUrlPathLength   = (DWORD)-1;
			urlComps.dwExtraInfoLength = (DWORD)-1;

			//Change the URL to wide string
			std::wstring url(WindowsStringUtils::UTF8ToUTF16(in_url));

			//Crack the URL.
			if (!WinHttpCrackUrl(url.c_str(), (DWORD)url.length(), 0, &urlComps))
			{
				CS_LOG_FATAL("Cannot crack URL: " + in_url);
				return nullptr;
			}

			//Weirdly the cracked URL struct only gives you the ability to crack your own URL
			std::wstring hostName = urlComps.lpszHostName;
			hostName = hostName.substr(0, urlComps.dwHostNameLength);
			HINTERNET connectionHandle = ::WinHttpConnect(m_sessionHandle, hostName.c_str(), INTERNET_DEFAULT_PORT, 0);

			if (!connectionHandle)
			{
				CS_LOG_ERROR("Failed to connect to server: " + in_url);
				return nullptr;
			}

			//Set up the request based on whether it is POST or GET and whether it is SSL
			LPCWSTR type = (in_type == ChilliSource::HttpRequest::Type::k_get ? L"GET" : L"POST");
			HINTERNET requestHandle = 0;

			std::wstring urlPath = urlComps.lpszUrlPath;
			urlPath = urlPath.substr(0, urlComps.dwUrlPathLength);

			if (urlComps.nScheme == INTERNET_SCHEME_HTTPS)
			{
				requestHandle = ::WinHttpOpenRequest(connectionHandle, type, urlPath.c_str(), L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
				if (requestHandle == nullptr || ApplySSLSettings(requestHandle) == false)
				{
					CS_LOG_ERROR("Failed to open request: " + in_url);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}
			else
			{
				requestHandle = ::WinHttpOpenRequest(connectionHandle, type, urlPath.c_str(), L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
				if (requestHandle == nullptr)
				{
					CS_LOG_ERROR("Failed to open request: " + in_url);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}

			if (in_headers.empty() == false)
			{
				std::wstring headerBlob = ConvertHeaders(in_headers);

				if (WinHttpAddRequestHeaders(requestHandle, headerBlob.c_str(), DWORD(headerBlob.length()), WINHTTP_ADDREQ_FLAG_ADD) == false)
				{
					CS_LOG_ERROR("Failed to add http headers: " + in_url);
					WinHttpCloseHandle(requestHandle);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}

			HttpRequest* httpRequest = new HttpRequest(in_type, in_url, in_body, in_headers, in_timeoutSecs, requestHandle, connectionHandle, GetMaxBufferSize(), in_delegate);
			m_requests.push_back(httpRequest);
			return httpRequest;
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::CancelAllRequests()
		{
			CS_ASSERT(ChilliSource::Application::Get()->GetTaskScheduler()->IsMainThread() == true, "Http requests can currently only be made on the main thread");

			for(u32 nRequest=0; nRequest<m_requests.size(); ++nRequest)
			{
				m_requests[nRequest]->Cancel();
			}
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::CheckReachability(const ReachabilityResultDelegate& in_reachabilityDelegate) const
		{
			//TODO: Implement this functionality
            CS_ASSERT(in_reachabilityDelegate, "The reachability delegate should not be null.");
			in_reachabilityDelegate(true);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnUpdate(f32 in_timeSinceLastUpdate)
		{
			//We should do this in two loops incase anyone tries to insert into the requests from the completion callback
			for (u32 i=0; i<m_requests.size(); ++i)
			{
				m_requests[i]->Update(in_timeSinceLastUpdate);
			}

			for (auto it = m_requests.begin(); it != m_requests.end(); /*No increment*/)
			{
				if((*it)->HasCompleted())
				{
					//...and remove the completed request
					CS_SAFEDELETE(*it);
					it = m_requests.erase(it);
				}
				else
				{
					++it;
				}
			}
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnDestroy()
		{
			CancelAllRequests();

			HttpRequest::Shutdown();

			for (auto it = m_requests.begin(); it != m_requests.end(); ++it)
			{
				CS_SAFEDELETE(*it);
			}

			m_requests.clear();
			m_requests.shrink_to_fit();

			WinHttpCloseHandle(m_sessionHandle);
		}
	}
}

#endif
<commit_msg>Network reachability for Windows.<commit_after>//
//  HttpRequestSystem.cpp
//  Chilli Source
//  Created by Scott Downie on 23/05/2011.
//
//  The MIT License (MIT)
//
//  Copyright (c) 2011 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#ifdef CS_TARGETPLATFORM_WINDOWS

#include <CSBackend/Platform/Windows/Networking/Http/HttpRequestSystem.h>

#include <CSBackend/Platform/Windows/Core/String/WindowsStringUtils.h>
#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Threading/TaskScheduler.h>

#include <Windows.h>

// Have to wrap WinInet's include in a namespace, because MS violates ODR with WinInet and WinHTTP.
namespace WinInet
{
#include <WinInet.h>
}

// A couple of undefs required too.
#undef BOOLAPI
#undef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
#undef SECURITY_FLAG_IGNORE_CERT_CN_INVALID

#include <winhttp.h>

#pragma comment(lib, "winhttp")
#pragma comment(lib, "wininet")

namespace CSBackend
{
	namespace Windows
	{
		namespace
		{
			//--------------------------------------------------------------------------------------------------
			/// Setup the request to use SSL level 3
			///
			/// @author S Downie
			///
			/// @param Request handle
			///
			/// @return Success or failure
			//--------------------------------------------------------------------------------------------------
			bool ApplySSLSettings(HINTERNET in_requestHandle)
			{
				DWORD requestOptions = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
				if (!WinHttpSetOption(in_requestHandle, WINHTTP_OPTION_SECURITY_FLAGS, &requestOptions, sizeof(DWORD)))
				{
					CS_LOG_ERROR("Failed to set HTTP SSL security flag options");
					return false;
				}

				return true;
			}
			//--------------------------------------------------------------------------------------------------
			/// Convert param dictionary to header format required by WinHTTP
			///
			/// @author S Downie
			///
			/// @param Header dictionary
			///
			/// @return Header blob
			//--------------------------------------------------------------------------------------------------
			std::wstring ConvertHeaders(const ChilliSource::ParamDictionary& in_headers)
			{
				//The headers must be passed as a single string with each header except the last
				//terminated by a carraige return/line feed
				std::string headerBlob;
				for (auto it = in_headers.begin(); it != in_headers.end(); ++it)
				{
					headerBlob += it->first;
					headerBlob += ": ";
					headerBlob += it->second;
					headerBlob += '\r';
					headerBlob += '\n';
				}

				CS_ASSERT(headerBlob.length() > 2, "Http: Cannot convert empty headers");

				std::wstring headerBlobWide(headerBlob.length() - 2, L' ');
				std::copy(headerBlob.begin(), headerBlob.end()-2, headerBlobWide.begin());
				return headerBlobWide;
			}
		}

		CS_DEFINE_NAMEDTYPE(HttpRequestSystem);

		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnInit()
		{
			m_sessionHandle = ::WinHttpOpen(L"CSWinHttpClient", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
			CS_ASSERT(m_sessionHandle != nullptr, "Failed to open WinHTTP session");
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		bool HttpRequestSystem::IsA(ChilliSource::InterfaceIDType in_interfaceId) const
		{
			return in_interfaceId == ChilliSource::HttpRequestSystem::InterfaceID || in_interfaceId == HttpRequestSystem::InterfaceID;
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeGetRequest(const std::string& in_url, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_get, in_url, "", ChilliSource::ParamDictionary(), in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeGetRequest(const std::string& in_url, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_get, in_url, "", in_headers, in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakePostRequest(const std::string& in_url, const std::string& in_body, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_post, in_url, in_body, ChilliSource::ParamDictionary(), in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakePostRequest(const std::string& in_url, const std::string& in_body, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			return MakeRequest(HttpRequest::Type::k_post, in_url, in_body, in_headers, in_delegate, in_timeoutSecs);
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		HttpRequest* HttpRequestSystem::MakeRequest(HttpRequest::Type in_type, const std::string& in_url, const std::string& in_body, const ChilliSource::ParamDictionary& in_headers, const HttpRequest::Delegate& in_delegate, u32 in_timeoutSecs)
		{
			CS_ASSERT(ChilliSource::Application::Get()->GetTaskScheduler()->IsMainThread() == true, "Http requests can currently only be made on the main thread");
			CS_ASSERT(in_delegate != nullptr, "Cannot make an http request with a null delegate");
			CS_ASSERT(in_url.empty() == false, "Cannot make an http request to a blank url");

			URL_COMPONENTS urlComps;

			//Initialize the URL_COMPONENTS structure.
			ZeroMemory(&urlComps, sizeof(URL_COMPONENTS));
			urlComps.dwStructSize = sizeof(URL_COMPONENTS);

			//Set required component lengths to non-zero so that they are cracked.
			urlComps.dwSchemeLength    = (DWORD)-1;
			urlComps.dwHostNameLength  = (DWORD)-1;
			urlComps.dwUrlPathLength   = (DWORD)-1;
			urlComps.dwExtraInfoLength = (DWORD)-1;

			//Change the URL to wide string
			std::wstring url(WindowsStringUtils::UTF8ToUTF16(in_url));

			//Crack the URL.
			if (!WinHttpCrackUrl(url.c_str(), (DWORD)url.length(), 0, &urlComps))
			{
				CS_LOG_FATAL("Cannot crack URL: " + in_url);
				return nullptr;
			}

			//Weirdly the cracked URL struct only gives you the ability to crack your own URL
			std::wstring hostName = urlComps.lpszHostName;
			hostName = hostName.substr(0, urlComps.dwHostNameLength);
			HINTERNET connectionHandle = ::WinHttpConnect(m_sessionHandle, hostName.c_str(), INTERNET_DEFAULT_PORT, 0);

			if (!connectionHandle)
			{
				CS_LOG_ERROR("Failed to connect to server: " + in_url);
				return nullptr;
			}

			//Set up the request based on whether it is POST or GET and whether it is SSL
			LPCWSTR type = (in_type == ChilliSource::HttpRequest::Type::k_get ? L"GET" : L"POST");
			HINTERNET requestHandle = 0;

			std::wstring urlPath = urlComps.lpszUrlPath;
			urlPath = urlPath.substr(0, urlComps.dwUrlPathLength);

			if (urlComps.nScheme == INTERNET_SCHEME_HTTPS)
			{
				requestHandle = ::WinHttpOpenRequest(connectionHandle, type, urlPath.c_str(), L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
				if (requestHandle == nullptr || ApplySSLSettings(requestHandle) == false)
				{
					CS_LOG_ERROR("Failed to open request: " + in_url);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}
			else
			{
				requestHandle = ::WinHttpOpenRequest(connectionHandle, type, urlPath.c_str(), L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
				if (requestHandle == nullptr)
				{
					CS_LOG_ERROR("Failed to open request: " + in_url);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}

			if (in_headers.empty() == false)
			{
				std::wstring headerBlob = ConvertHeaders(in_headers);

				if (WinHttpAddRequestHeaders(requestHandle, headerBlob.c_str(), DWORD(headerBlob.length()), WINHTTP_ADDREQ_FLAG_ADD) == false)
				{
					CS_LOG_ERROR("Failed to add http headers: " + in_url);
					WinHttpCloseHandle(requestHandle);
					WinHttpCloseHandle(connectionHandle);
					return nullptr;
				}
			}

			HttpRequest* httpRequest = new HttpRequest(in_type, in_url, in_body, in_headers, in_timeoutSecs, requestHandle, connectionHandle, GetMaxBufferSize(), in_delegate);
			m_requests.push_back(httpRequest);
			return httpRequest;
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::CancelAllRequests()
		{
			CS_ASSERT(ChilliSource::Application::Get()->GetTaskScheduler()->IsMainThread() == true, "Http requests can currently only be made on the main thread");

			for(u32 nRequest=0; nRequest<m_requests.size(); ++nRequest)
			{
				m_requests[nRequest]->Cancel();
			}
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::CheckReachability(const ReachabilityResultDelegate& in_reachabilityDelegate) const
		{
			// Check internet connectivity/reachability, using WinINet.
			DWORD inetState = 0;
			BOOL hasConnection = WinInet::InternetGetConnectedState(&inetState, 0);

			// True is returned when the device has an active connection to the internet, or a correctly-configured proxy connection.
			// False is returned when the device has no connection to the internet, even if successfully connected to LAN.
			// More information about the connection can be obtained from the 'inetState' flag.

            CS_ASSERT(in_reachabilityDelegate, "The reachability delegate should not be null.");
			in_reachabilityDelegate(hasConnection ? true : false); //ternary operator used here because BOOL is a typedef'd int & conversion has perf issues
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnUpdate(f32 in_timeSinceLastUpdate)
		{
			//We should do this in two loops incase anyone tries to insert into the requests from the completion callback
			for (u32 i=0; i<m_requests.size(); ++i)
			{
				m_requests[i]->Update(in_timeSinceLastUpdate);
			}

			for (auto it = m_requests.begin(); it != m_requests.end(); /*No increment*/)
			{
				if((*it)->HasCompleted())
				{
					//...and remove the completed request
					CS_SAFEDELETE(*it);
					it = m_requests.erase(it);
				}
				else
				{
					++it;
				}
			}
		}
		//--------------------------------------------------------------------------------------------------
		//--------------------------------------------------------------------------------------------------
		void HttpRequestSystem::OnDestroy()
		{
			CancelAllRequests();

			HttpRequest::Shutdown();

			for (auto it = m_requests.begin(); it != m_requests.end(); ++it)
			{
				CS_SAFEDELETE(*it);
			}

			m_requests.clear();
			m_requests.shrink_to_fit();

			WinHttpCloseHandle(m_sessionHandle);
		}
	}
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"

#include <string.h>

#include <vector>

#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/widevine_cdm_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"

#include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.

using content::BrowserThread;
using content::PluginService;

namespace {

// TODO(xhwang): Move duplicate code among all component installer
// implementations to some common place.

#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

// CRX hash. The extension id is: pdkaonnflpjcgibpgaanildgengnihcm.
const uint8 kSha2Hash[] = { 0xf3, 0xa0, 0xed, 0xd5, 0xbf, 0x92, 0x68, 0x1f,
                            0x60, 0x0d, 0x8b, 0x36, 0x4d, 0x6d, 0x87, 0x2c,
                            0x86, 0x61, 0x12, 0x20, 0x21, 0xf8, 0x94, 0xdd,
                            0xe1, 0xb6, 0xb4, 0x55, 0x34, 0x8c, 0x2e, 0x20 };

// File name of the Widevine CDM component manifest on different platforms.
const char kWidevineCdmManifestName[] = "WidevineCdm";

// Name of the Widevine CDM OS in the component manifest.
const char kWidevineCdmOperatingSystem[] =
#if defined(OS_MACOSX)
    "mac";
#elif defined(OS_WIN)
    "win";
#else  // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android?
    "linux";
#endif

// Name of the Widevine CDM architecture in the component manifest.
const char kWidevineCdmArch[] =
#if defined(ARCH_CPU_X86)
    "ia32";
#elif defined(ARCH_CPU_X86_64)
    "x64";
#else  // TODO(viettrungluu): Support an ARM check?
    "???";
#endif

// If we don't have a Widevine CDM component, this is the version we claim.
const char kNullVersion[] = "0.0.0.0";

// The base directory on Windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\.
base::FilePath GetWidevineCdmBaseDirectory() {
  base::FilePath result;
  PathService::Get(chrome::DIR_COMPONENT_WIDEVINE_CDM, &result);
  return result;
}

// Widevine CDM has the version encoded in the path so we need to enumerate the
// directories to find the full path.
// On success, |latest_dir| returns something like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\10.3.44.555\.
// |latest_version| returns the corresponding version number. |older_dirs|
// returns directories of all older versions.
bool GetWidevineCdmDirectory(base::FilePath* latest_dir,
                             base::Version* latest_version,
                             std::vector<base::FilePath>* older_dirs) {
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  bool found = false;
  base::FileEnumerator file_enumerator(
      base_dir, false, base::FileEnumerator::DIRECTORIES);
  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
       path = file_enumerator.Next()) {
    base::Version version(path.BaseName().MaybeAsASCII());
    if (!version.IsValid())
      continue;
    if (found) {
      if (version.CompareTo(*latest_version) > 0) {
        older_dirs->push_back(*latest_dir);
        *latest_dir = path;
        *latest_version = version;
      } else {
        older_dirs->push_back(path);
      }
    } else {
      *latest_dir = path;
      *latest_version = version;
      found = true;
    }
  }
  return found;
}

bool MakeWidevineCdmPluginInfo(const base::FilePath& path,
                               const base::Version& version,
                               content::PepperPluginInfo* plugin_info) {
  if (!version.IsValid() ||
      version.components().size() !=
          static_cast<size_t>(kWidevineCdmVersionNumComponents)) {
    return false;
  }

  plugin_info->is_internal = false;
  // Widevine CDM must run out of process.
  plugin_info->is_out_of_process = true;
  plugin_info->path = path;
  plugin_info->name = kWidevineCdmDisplayName;
  plugin_info->description = kWidevineCdmDescription;
  plugin_info->version = version.GetString();
  webkit::WebPluginMimeType widevine_cdm_mime_type(
      kWidevineCdmPluginMimeType,
      kWidevineCdmPluginExtension,
      kWidevineCdmPluginMimeTypeDescription);
  plugin_info->mime_types.push_back(widevine_cdm_mime_type);
  plugin_info->permissions = kWidevineCdmPluginPermissions;

  return true;
}

void RegisterWidevineCdmWithChrome(const base::FilePath& path,
                                   const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::PepperPluginInfo plugin_info;
  if (!MakeWidevineCdmPluginInfo(path, version, &plugin_info))
    return;

  PluginService::GetInstance()->RegisterInternalPlugin(
      plugin_info.ToWebPluginInfo(), true);
  PluginService::GetInstance()->RefreshPlugins();
}

// Returns true if this browser is compatible with the given Widevine CDM
// manifest, with the version specified in the manifest in |version_out|.
bool CheckWidevineCdmManifest(const base::DictionaryValue& manifest,
                              base::Version* version_out) {
  std::string name;
  manifest.GetStringASCII("name", &name);

  if (name != kWidevineCdmManifestName)
    return false;

  std::string proposed_version;
  manifest.GetStringASCII("version", &proposed_version);
  base::Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;

  std::string os;
  manifest.GetStringASCII("x-widevine-cdm-os", &os);
  if (os != kWidevineCdmOperatingSystem)
    return false;

  std::string arch;
  manifest.GetStringASCII("x-widevine-cdm-arch", &arch);
  if (arch != kWidevineCdmArch)
    return false;

  *version_out = version;
  return true;
}

class WidevineCdmComponentInstaller : public ComponentInstaller {
 public:
  explicit WidevineCdmComponentInstaller(const base::Version& version);
  virtual ~WidevineCdmComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;
  virtual bool Install(const base::DictionaryValue& manifest,
                       const base::FilePath& unpack_path) OVERRIDE;

  virtual bool GetInstalledFile(const std::string& file,
                                base::FilePath* installed_file) OVERRIDE;

 private:
  base::Version current_version_;
};

WidevineCdmComponentInstaller::WidevineCdmComponentInstaller(
    const base::Version& version)
    : current_version_(version) {
  DCHECK(version.IsValid());
}

void WidevineCdmComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "Widevine CDM update error: " << error;
}

bool WidevineCdmComponentInstaller::Install(
    const base::DictionaryValue& manifest,
    const base::FilePath& unpack_path) {
  base::Version version;
  if (!CheckWidevineCdmManifest(manifest, &version))
    return false;
  if (current_version_.CompareTo(version) > 0)
    return false;

  if (!file_util::PathExists(unpack_path.AppendASCII(kWidevineCdmFileName)))
    return false;

  base::FilePath adapter_source_path;
  PathService::Get(chrome::FILE_WIDEVINE_CDM_ADAPTER, &adapter_source_path);
  if (!file_util::PathExists(adapter_source_path))
    return false;

  // Passed the basic tests. Time to install it.
  base::FilePath install_path =
      GetWidevineCdmBaseDirectory().AppendASCII(version.GetString());
  if (file_util::PathExists(install_path))
    return false;
  if (!file_util::Move(unpack_path, install_path))
    return false;

  base::FilePath adapter_install_path =
      install_path.AppendASCII(kWidevineCdmAdapterFileName);
  if (!file_util::CopyFile(adapter_source_path, adapter_install_path))
    return false;

  // Installation is done. Now register the Widevine CDM with chrome.
  current_version_ = version;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
      &RegisterWidevineCdmWithChrome, adapter_install_path, version));
  return true;
}

bool WidevineCdmComponentInstaller::GetInstalledFile(
    const std::string& file, base::FilePath* installed_file) {
  return false;
}

void FinishWidevineCdmUpdateRegistration(ComponentUpdateService* cus,
                                         const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  CrxComponent widevine_cdm;
  widevine_cdm.name = "WidevineCdm";
  widevine_cdm.installer = new WidevineCdmComponentInstaller(version);
  widevine_cdm.version = version;
  widevine_cdm.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
  if (cus->RegisterComponent(widevine_cdm) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Widevine CDM component registration failed.";
    return;
  }
}

void StartWidevineCdmUpdateRegistration(ComponentUpdateService* cus) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  if (!file_util::PathExists(base_dir) &&
      !file_util::CreateDirectory(base_dir)) {
    NOTREACHED() << "Could not create Widevine CDM directory.";
    return;
  }

  base::FilePath latest_dir;
  base::Version version(kNullVersion);
  std::vector<base::FilePath> older_dirs;

  if (GetWidevineCdmDirectory(&latest_dir, &version, &older_dirs)) {
    base::FilePath adapter_path =
        latest_dir.AppendASCII(kWidevineCdmAdapterFileName);
    base::FilePath cdm_path = latest_dir.AppendASCII(kWidevineCdmFileName);

    if (file_util::PathExists(adapter_path) &&
        file_util::PathExists(cdm_path)) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          base::Bind(&RegisterWidevineCdmWithChrome, adapter_path, version));
    } else {
      file_util::Delete(latest_dir, true);
      version = base::Version(kNullVersion);
    }
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishWidevineCdmUpdateRegistration, cus, version));

  // Remove older versions of Widevine CDM.
  for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
       iter != older_dirs.end(); ++iter) {
    file_util::Delete(*iter, true);
  }
}

#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

}  // namespace

void RegisterWidevineCdmComponent(ComponentUpdateService* cus) {
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                          base::Bind(&StartWidevineCdmUpdateRegistration, cus));
#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
}
<commit_msg>Implement GetInstalledFile() in WidevineCdmComponentInstaller.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"

#include <string.h>

#include <vector>

#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/widevine_cdm_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"

#include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.

using content::BrowserThread;
using content::PluginService;

namespace {

// TODO(xhwang): Move duplicate code among all component installer
// implementations to some common place.

#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

// CRX hash. The extension id is: pdkaonnflpjcgibpgaanildgengnihcm.
const uint8 kSha2Hash[] = { 0xf3, 0xa0, 0xed, 0xd5, 0xbf, 0x92, 0x68, 0x1f,
                            0x60, 0x0d, 0x8b, 0x36, 0x4d, 0x6d, 0x87, 0x2c,
                            0x86, 0x61, 0x12, 0x20, 0x21, 0xf8, 0x94, 0xdd,
                            0xe1, 0xb6, 0xb4, 0x55, 0x34, 0x8c, 0x2e, 0x20 };

// File name of the Widevine CDM component manifest on different platforms.
const char kWidevineCdmManifestName[] = "WidevineCdm";

// Name of the Widevine CDM OS in the component manifest.
const char kWidevineCdmOperatingSystem[] =
#if defined(OS_MACOSX)
    "mac";
#elif defined(OS_WIN)
    "win";
#else  // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android?
    "linux";
#endif

// Name of the Widevine CDM architecture in the component manifest.
const char kWidevineCdmArch[] =
#if defined(ARCH_CPU_X86)
    "ia32";
#elif defined(ARCH_CPU_X86_64)
    "x64";
#else  // TODO(viettrungluu): Support an ARM check?
    "???";
#endif

// If we don't have a Widevine CDM component, this is the version we claim.
const char kNullVersion[] = "0.0.0.0";

// The base directory on Windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\.
base::FilePath GetWidevineCdmBaseDirectory() {
  base::FilePath result;
  PathService::Get(chrome::DIR_COMPONENT_WIDEVINE_CDM, &result);
  return result;
}

// Widevine CDM has the version encoded in the path so we need to enumerate the
// directories to find the full path.
// On success, |latest_dir| returns something like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\10.3.44.555\.
// |latest_version| returns the corresponding version number. |older_dirs|
// returns directories of all older versions.
bool GetWidevineCdmDirectory(base::FilePath* latest_dir,
                             base::Version* latest_version,
                             std::vector<base::FilePath>* older_dirs) {
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  bool found = false;
  base::FileEnumerator file_enumerator(
      base_dir, false, base::FileEnumerator::DIRECTORIES);
  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
       path = file_enumerator.Next()) {
    base::Version version(path.BaseName().MaybeAsASCII());
    if (!version.IsValid())
      continue;
    if (found) {
      if (version.CompareTo(*latest_version) > 0) {
        older_dirs->push_back(*latest_dir);
        *latest_dir = path;
        *latest_version = version;
      } else {
        older_dirs->push_back(path);
      }
    } else {
      *latest_dir = path;
      *latest_version = version;
      found = true;
    }
  }
  return found;
}

bool MakeWidevineCdmPluginInfo(const base::FilePath& path,
                               const base::Version& version,
                               content::PepperPluginInfo* plugin_info) {
  if (!version.IsValid() ||
      version.components().size() !=
          static_cast<size_t>(kWidevineCdmVersionNumComponents)) {
    return false;
  }

  plugin_info->is_internal = false;
  // Widevine CDM must run out of process.
  plugin_info->is_out_of_process = true;
  plugin_info->path = path;
  plugin_info->name = kWidevineCdmDisplayName;
  plugin_info->description = kWidevineCdmDescription;
  plugin_info->version = version.GetString();
  webkit::WebPluginMimeType widevine_cdm_mime_type(
      kWidevineCdmPluginMimeType,
      kWidevineCdmPluginExtension,
      kWidevineCdmPluginMimeTypeDescription);
  plugin_info->mime_types.push_back(widevine_cdm_mime_type);
  plugin_info->permissions = kWidevineCdmPluginPermissions;

  return true;
}

void RegisterWidevineCdmWithChrome(const base::FilePath& path,
                                   const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::PepperPluginInfo plugin_info;
  if (!MakeWidevineCdmPluginInfo(path, version, &plugin_info))
    return;

  PluginService::GetInstance()->RegisterInternalPlugin(
      plugin_info.ToWebPluginInfo(), true);
  PluginService::GetInstance()->RefreshPlugins();
}

// Returns true if this browser is compatible with the given Widevine CDM
// manifest, with the version specified in the manifest in |version_out|.
bool CheckWidevineCdmManifest(const base::DictionaryValue& manifest,
                              base::Version* version_out) {
  std::string name;
  manifest.GetStringASCII("name", &name);

  if (name != kWidevineCdmManifestName)
    return false;

  std::string proposed_version;
  manifest.GetStringASCII("version", &proposed_version);
  base::Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;

  std::string os;
  manifest.GetStringASCII("x-widevine-cdm-os", &os);
  if (os != kWidevineCdmOperatingSystem)
    return false;

  std::string arch;
  manifest.GetStringASCII("x-widevine-cdm-arch", &arch);
  if (arch != kWidevineCdmArch)
    return false;

  *version_out = version;
  return true;
}

class WidevineCdmComponentInstaller : public ComponentInstaller {
 public:
  explicit WidevineCdmComponentInstaller(const base::Version& version);
  virtual ~WidevineCdmComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;
  virtual bool Install(const base::DictionaryValue& manifest,
                       const base::FilePath& unpack_path) OVERRIDE;

  virtual bool GetInstalledFile(const std::string& file,
                                base::FilePath* installed_file) OVERRIDE;

 private:
  base::Version current_version_;
};

WidevineCdmComponentInstaller::WidevineCdmComponentInstaller(
    const base::Version& version)
    : current_version_(version) {
  DCHECK(version.IsValid());
}

void WidevineCdmComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "Widevine CDM update error: " << error;
}

bool WidevineCdmComponentInstaller::Install(
    const base::DictionaryValue& manifest,
    const base::FilePath& unpack_path) {
  base::Version version;
  if (!CheckWidevineCdmManifest(manifest, &version))
    return false;
  if (current_version_.CompareTo(version) > 0)
    return false;

  if (!file_util::PathExists(unpack_path.AppendASCII(kWidevineCdmFileName)))
    return false;

  base::FilePath adapter_source_path;
  PathService::Get(chrome::FILE_WIDEVINE_CDM_ADAPTER, &adapter_source_path);
  if (!file_util::PathExists(adapter_source_path))
    return false;

  // Passed the basic tests. Time to install it.
  base::FilePath install_path =
      GetWidevineCdmBaseDirectory().AppendASCII(version.GetString());
  if (file_util::PathExists(install_path))
    return false;
  if (!file_util::Move(unpack_path, install_path))
    return false;

  base::FilePath adapter_install_path =
      install_path.AppendASCII(kWidevineCdmAdapterFileName);
  if (!file_util::CopyFile(adapter_source_path, adapter_install_path))
    return false;

  // Installation is done. Now register the Widevine CDM with chrome.
  current_version_ = version;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
      &RegisterWidevineCdmWithChrome, adapter_install_path, version));
  return true;
}

bool WidevineCdmComponentInstaller::GetInstalledFile(
    const std::string& file, base::FilePath* installed_file) {
  // Only the CDM is component-updated.
  if (file != kWidevineCdmFileName)
    return false;

  if (current_version_.Equals(base::Version(kNullVersion)))
    return false;  // No CDM has been installed yet.

  *installed_file =
      GetWidevineCdmBaseDirectory().AppendASCII(current_version_.GetString())
          .AppendASCII(kWidevineCdmFileName);
  return true;
}

void FinishWidevineCdmUpdateRegistration(ComponentUpdateService* cus,
                                         const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  CrxComponent widevine_cdm;
  widevine_cdm.name = "WidevineCdm";
  widevine_cdm.installer = new WidevineCdmComponentInstaller(version);
  widevine_cdm.version = version;
  widevine_cdm.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
  if (cus->RegisterComponent(widevine_cdm) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Widevine CDM component registration failed.";
    return;
  }
}

void StartWidevineCdmUpdateRegistration(ComponentUpdateService* cus) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  if (!file_util::PathExists(base_dir) &&
      !file_util::CreateDirectory(base_dir)) {
    NOTREACHED() << "Could not create Widevine CDM directory.";
    return;
  }

  base::FilePath latest_dir;
  base::Version version(kNullVersion);
  std::vector<base::FilePath> older_dirs;

  if (GetWidevineCdmDirectory(&latest_dir, &version, &older_dirs)) {
    base::FilePath adapter_path =
        latest_dir.AppendASCII(kWidevineCdmAdapterFileName);
    base::FilePath cdm_path = latest_dir.AppendASCII(kWidevineCdmFileName);

    if (file_util::PathExists(adapter_path) &&
        file_util::PathExists(cdm_path)) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          base::Bind(&RegisterWidevineCdmWithChrome, adapter_path, version));
    } else {
      file_util::Delete(latest_dir, true);
      version = base::Version(kNullVersion);
    }
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishWidevineCdmUpdateRegistration, cus, version));

  // Remove older versions of Widevine CDM.
  for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
       iter != older_dirs.end(); ++iter) {
    file_util::Delete(*iter, true);
  }
}

#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

}  // namespace

void RegisterWidevineCdmComponent(ComponentUpdateService* cus) {
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                          base::Bind(&StartWidevineCdmUpdateRegistration, cus));
#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
}
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"

#include "ash/multi_profile_uma.h"
#include "ash/session_state_delegate.h"
#include "ash/shell.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
#include "grit/generated_resources.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"

namespace {

class MultiUserContextMenuChromeos : public ui::SimpleMenuModel,
                                     public ui::SimpleMenuModel::Delegate {
 public:
  explicit MultiUserContextMenuChromeos(aura::Window* window);
  virtual ~MultiUserContextMenuChromeos() {}

  // SimpleMenuModel::Delegate:
  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
    return false;
  }
  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
    return true;
  }
  virtual bool GetAcceleratorForCommandId(
      int command_id,
      ui::Accelerator* accelerator) OVERRIDE {
    return false;
  }
  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;

 private:
  // The window for which this menu is.
  aura::Window* window_;

  DISALLOW_COPY_AND_ASSIGN(MultiUserContextMenuChromeos);
};

MultiUserContextMenuChromeos::MultiUserContextMenuChromeos(aura::Window* window)
    : ui::SimpleMenuModel(this),
      window_(window) {
}

void MultiUserContextMenuChromeos::ExecuteCommand(int command_id,
                                                  int event_flags) {
  switch (command_id) {
    case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
    case IDC_VISIT_DESKTOP_OF_LRU_USER_3: {
        ash::MultiProfileUMA::RecordTeleportAction(
            ash::MultiProfileUMA::TELEPORT_WINDOW_CAPTION_MENU);
        // When running the multi user mode on Chrome OS, windows can "visit"
        // another user's desktop.
        const std::string& user_id =
            ash::Shell::GetInstance()->session_state_delegate()->GetUserID(
                IDC_VISIT_DESKTOP_OF_LRU_USER_2 == command_id ? 1 : 2);
        chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
            window_,
            user_id);
        return;
      }
    default:
      NOTREACHED();
  }
}

}  // namespace

scoped_ptr<ui::MenuModel> CreateMultiUserContextMenu(
    aura::Window* window) {
  scoped_ptr<ui::MenuModel> model;
  ash::SessionStateDelegate* delegate =
      ash::Shell::GetInstance()->session_state_delegate();
  int logged_in_users = delegate->NumberOfLoggedInUsers();
  if (delegate && logged_in_users > 1) {
    // If this window is not owned, we don't show the menu addition.
    chrome::MultiUserWindowManager* manager =
        chrome::MultiUserWindowManager::GetInstance();
    const std::string user_id = manager->GetWindowOwner(window);
    if (user_id.empty() || !window ||
        manager->GetWindowOwner(window).empty())
      return model.Pass();
    MultiUserContextMenuChromeos* menu =
        new MultiUserContextMenuChromeos(window);
    model.reset(menu);
    for (int user_index = 1; user_index < logged_in_users; ++user_index) {
      menu->AddItem(
          user_index == 1 ? IDC_VISIT_DESKTOP_OF_LRU_USER_2 :
                            IDC_VISIT_DESKTOP_OF_LRU_USER_3,
          l10n_util::GetStringFUTF16(
              IDS_VISIT_DESKTOP_OF_LRU_USER,
              delegate->GetUserDisplayName(user_index),
              base::ASCIIToUTF16(delegate->GetUserEmail(user_index))));
    }
  }
  return model.Pass();
}
<commit_msg>Move a null check before it's usage.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"

#include "ash/multi_profile_uma.h"
#include "ash/session_state_delegate.h"
#include "ash/shell.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
#include "grit/generated_resources.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"

namespace {

class MultiUserContextMenuChromeos : public ui::SimpleMenuModel,
                                     public ui::SimpleMenuModel::Delegate {
 public:
  explicit MultiUserContextMenuChromeos(aura::Window* window);
  virtual ~MultiUserContextMenuChromeos() {}

  // SimpleMenuModel::Delegate:
  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
    return false;
  }
  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
    return true;
  }
  virtual bool GetAcceleratorForCommandId(
      int command_id,
      ui::Accelerator* accelerator) OVERRIDE {
    return false;
  }
  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;

 private:
  // The window for which this menu is.
  aura::Window* window_;

  DISALLOW_COPY_AND_ASSIGN(MultiUserContextMenuChromeos);
};

MultiUserContextMenuChromeos::MultiUserContextMenuChromeos(aura::Window* window)
    : ui::SimpleMenuModel(this),
      window_(window) {
}

void MultiUserContextMenuChromeos::ExecuteCommand(int command_id,
                                                  int event_flags) {
  switch (command_id) {
    case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
    case IDC_VISIT_DESKTOP_OF_LRU_USER_3: {
        ash::MultiProfileUMA::RecordTeleportAction(
            ash::MultiProfileUMA::TELEPORT_WINDOW_CAPTION_MENU);
        // When running the multi user mode on Chrome OS, windows can "visit"
        // another user's desktop.
        const std::string& user_id =
            ash::Shell::GetInstance()->session_state_delegate()->GetUserID(
                IDC_VISIT_DESKTOP_OF_LRU_USER_2 == command_id ? 1 : 2);
        chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
            window_,
            user_id);
        return;
      }
    default:
      NOTREACHED();
  }
}

}  // namespace

scoped_ptr<ui::MenuModel> CreateMultiUserContextMenu(
    aura::Window* window) {
  scoped_ptr<ui::MenuModel> model;
  ash::SessionStateDelegate* delegate =
      ash::Shell::GetInstance()->session_state_delegate();
  if (!delegate)
    return model.Pass();

  int logged_in_users = delegate->NumberOfLoggedInUsers();
  if (logged_in_users > 1) {
    // If this window is not owned, we don't show the menu addition.
    chrome::MultiUserWindowManager* manager =
        chrome::MultiUserWindowManager::GetInstance();
    const std::string user_id = manager->GetWindowOwner(window);
    if (user_id.empty() || !window ||
        manager->GetWindowOwner(window).empty())
      return model.Pass();
    MultiUserContextMenuChromeos* menu =
        new MultiUserContextMenuChromeos(window);
    model.reset(menu);
    for (int user_index = 1; user_index < logged_in_users; ++user_index) {
      menu->AddItem(
          user_index == 1 ? IDC_VISIT_DESKTOP_OF_LRU_USER_2 :
                            IDC_VISIT_DESKTOP_OF_LRU_USER_3,
          l10n_util::GetStringFUTF16(
              IDS_VISIT_DESKTOP_OF_LRU_USER,
              delegate->GetUserDisplayName(user_index),
              base::ASCIIToUTF16(delegate->GetUserEmail(user_index))));
    }
  }
  return model.Pass();
}
<|endoftext|>