<commit_before>/**
 * Implementation of Monotone Chain for convex hull
 * computation of a set of points in the 2d space.
 */

#ifndef monotone_chain_h
#define monotone_chain_h

#include "angle.hpp"
#include "point_concept.hpp"
#include "static_assert.hpp"

#include <algorithm>
#include <tuple>

namespace hull::algorithms::details::monotone {
    /**
     * Sort the points of P by x-coordinate (in case of a tie, sort by y-coordinate).
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     */
    template <typename RandomIt>
    void sort(RandomIt first, RandomIt last) {
        std::sort(first, last, [](const auto& p1, const auto& p2) {
            return (x(p1) < x(p2) || (hull::equals(x(p1), x(p2)) && y(p1) < y(p2)));
        });
    }

    /**
     * Build a lambda function which tells whether a given point
     * (the one at index i with respect to first iterator) is on the
     * left (that is, not counter-clockwise) of the vector made of
     * the last 2 points on the result convex hull.
     * @param k - the index of the last point on the convex hull.
     * @param first - iterator to the first point in the input container of points.
     * @param first2 - iterator to the first point in the resulting convex hull.
     * @return - a lambda function which takes an index i and tells whether
     *           the point at first+i is on the left of vector first2+(k-2) first2+(k-1).
     */
    template <typename RandomIt1, typename RandomIt2>
    auto no_counter_clockwise(std::size_t& k, RandomIt1 first, RandomIt2 first2) {
        return [&k, first, first2](auto i) {
            return cross(*(first2 + (k - 2)), *(first2 + (k - 1)), *(first + i)) <= 0;
        };
    };

    /**
     * Build a lambda function which copies the input point at
     * index i into the resulting convex hull at index k (and it
     * increment k, the number of points in the convex hull).
     * @param k - the number of points in the resulting convex hull.
     * @param first - iterator to the first point in the input container of points.
     * @param first2 - iterator to the first point in the resulting convex hull.
     * @return - a lambda function which copies first+i to first2+k.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto copy(std::size_t& k, RandomIt1 first, RandomIt2 first2) {
        return [&k, first, first2](auto i) {
            *(first2 + k) = *(first + i);
            k++;
        };
    }

    /**
     * Get all the dependencies of the lower_hull and upper_hull algorithms.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the convex hull.
     * @return - a tuple containing all the dependencies of the lower and upper hull algorithms.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto get_dependencies(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        return std::make_tuple(no_counter_clockwise(k, first, first2),
                               copy(k, first, first2),
                               std::distance(first, last));
    }

    /**
     * Compute the lower hull of the convex hull.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the lower hull.
     */
    template <typename RandomIt1, typename RandomIt2>
    void lower_hull(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        auto [no_counter_clockwise, copy, N] = get_dependencies(first, last, first2, k);

        for (int i{}; i < N; i++) {
            while (k >= 2 && no_counter_clockwise(i)) {
                k--;
            }
            copy(i);
        }
    }

    /**
     * Compute the upper hull of the convex hull.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the upper hull.
     */
    template <typename RandomIt1, typename RandomIt2>
    void upper_hull(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        auto [no_counter_clockwise, copy, N] = get_dependencies(first, last, first2, k);

        auto t = k + 1;
        for (int i{static_cast<int>(N - 2)}; i >= 0; i--) {
            while (k >= t && no_counter_clockwise(i)) {
                k--;
            }
            copy(i);
        }
    }
}

namespace hull::algorithms::details {
    /**
     * Compute the convex hull of a container of points following
     * the Monotone Chain algorithm. This algorithm does not work in-place, but
     * it still modifies the input points (it sorts them by x-coordinates).
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * Reference: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 monotone_chain_impl(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        monotone::sort(first, last);

        std::size_t k{};
        monotone::lower_hull(first, last, first2, k);
        monotone::upper_hull(first, last, first2, k);

        return first2 + (k - 1);
    }
}

namespace hull::algorithms {
    /**
     * Compute the convex hull of a container of points following
     * the Monotone Chain algorithm. This algorithm does not work in-place, but
     * it still modifies the input points (it sorts them by x-coordinates).
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * Reference: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 monotone_chain(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        static_assert_is_random_access_iterator_to_point<RandomIt1>();
        static_assert_is_random_access_iterator_to_point<RandomIt2>();

        const auto N = std::distance(first, last);
        if (N <= 1) {
            return std::copy(first, last, first2);
        }

        return details::monotone_chain_impl(first, last, first2);
    }
}

namespace hull {
    /**
     * Compile-time enumeration to choose the
     * algorithm thanks to a policy approach.
     * @param monotone_chain_t - Monotone Chain algorithm.
     */
    struct monotone_chain_t {};

    /**
     * Algorithms policies to choose an overload.
     * @param monotone_chain - Monotone Chain algorithm.
     */
    namespace choice {
        static constexpr const monotone_chain_t monotone_chain{};
    }

    /**
     * Overload of iterator-based convex hull computation for Monotone Chain.
     * Note that the input is modified.
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * It is unfortunately not possible to use a std::back_insert_iterator.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           destination container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto compute_convex_hull(monotone_chain_t policy, RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        using value_type = typename std::iterator_traits<RandomIt2>::value_type;
        std::fill_n(first2, 2 * std::distance(first, last), value_type{});

        return algorithms::monotone_chain(first, last, first2);
    }

    namespace convex {
        /**
         * Overload of container-based convex hull computation for Monotone Chain.
         * Average time complexity: O(N * log(N)) where N is the number of
         * points.
         * Average space complexity: O(4 * N).
         * @param c1 - the input container.
         * @param c2 - the destination container.
         */
        template <typename TContainer1, typename TContainer2>
        void compute(monotone_chain_t policy, TContainer1 c1, TContainer2& c2) {
            c2.resize(2 * c1.size());

            std::fill(std::begin(c2), std::end(c2), typename TContainer2::value_type{});
            auto last = hull::algorithms::monotone_chain(std::begin(c1), std::end(c1), std::begin(c2));

            c2.erase(last, std::end(c2));
        }
    }
}

#endif
<commit_msg>Adding const qualifier.<commit_after>/**
 * Implementation of Monotone Chain for convex hull
 * computation of a set of points in the 2d space.
 */

#ifndef monotone_chain_h
#define monotone_chain_h

#include "angle.hpp"
#include "point_concept.hpp"
#include "static_assert.hpp"

#include <algorithm>
#include <tuple>

namespace hull::algorithms::details::monotone {
    /**
     * Sort the points of P by x-coordinate (in case of a tie, sort by y-coordinate).
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     */
    template <typename RandomIt>
    void sort(RandomIt first, RandomIt last) {
        std::sort(first, last, [](const auto& p1, const auto& p2) {
            return (x(p1) < x(p2) || (hull::equals(x(p1), x(p2)) && y(p1) < y(p2)));
        });
    }

    /**
     * Build a lambda function which tells whether a given point
     * (the one at index i with respect to first iterator) is on the
     * left (that is, not counter-clockwise) of the vector made of
     * the last 2 points on the result convex hull.
     * @param k - the index of the last point on the convex hull.
     * @param first - iterator to the first point in the input container of points.
     * @param first2 - iterator to the first point in the resulting convex hull.
     * @return - a lambda function which takes an index i and tells whether
     *           the point at first+i is on the left of vector first2+(k-2) first2+(k-1).
     */
    template <typename RandomIt1, typename RandomIt2>
    auto no_counter_clockwise(std::size_t& k, RandomIt1 first, RandomIt2 first2) {
        return [&k, first, first2](auto i) {
            return cross(*(first2 + (k - 2)), *(first2 + (k - 1)), *(first + i)) <= 0;
        };
    };

    /**
     * Build a lambda function which copies the input point at
     * index i into the resulting convex hull at index k (and it
     * increment k, the number of points in the convex hull).
     * @param k - the number of points in the resulting convex hull.
     * @param first - iterator to the first point in the input container of points.
     * @param first2 - iterator to the first point in the resulting convex hull.
     * @return - a lambda function which copies first+i to first2+k.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto copy(std::size_t& k, RandomIt1 first, RandomIt2 first2) {
        return [&k, first, first2](auto i) {
            *(first2 + k) = *(first + i);
            k++;
        };
    }

    /**
     * Get all the dependencies of the lower_hull and upper_hull algorithms.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the convex hull.
     * @return - a tuple containing all the dependencies of the lower and upper hull algorithms.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto get_dependencies(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        return std::make_tuple(no_counter_clockwise(k, first, first2),
                               copy(k, first, first2),
                               std::distance(first, last));
    }

    /**
     * Compute the lower hull of the convex hull.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the lower hull.
     */
    template <typename RandomIt1, typename RandomIt2>
    void lower_hull(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        const auto [no_counter_clockwise, copy, N] = get_dependencies(first, last, first2, k);

        for (int i{}; i < N; i++) {
            while (k >= 2 && no_counter_clockwise(i)) {
                k--;
            }
            copy(i);
        }
    }

    /**
     * Compute the upper hull of the convex hull.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @param k - this will be the number of points on the upper hull.
     */
    template <typename RandomIt1, typename RandomIt2>
    void upper_hull(RandomIt1 first, RandomIt1 last, RandomIt2 first2, std::size_t& k) {
        const auto [no_counter_clockwise, copy, N] = get_dependencies(first, last, first2, k);

        auto t = k + 1;
        for (int i{static_cast<int>(N - 2)}; i >= 0; i--) {
            while (k >= t && no_counter_clockwise(i)) {
                k--;
            }
            copy(i);
        }
    }
}

namespace hull::algorithms::details {
    /**
     * Compute the convex hull of a container of points following
     * the Monotone Chain algorithm. This algorithm does not work in-place, but
     * it still modifies the input points (it sorts them by x-coordinates).
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * Reference: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 monotone_chain_impl(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        monotone::sort(first, last);

        std::size_t k{};
        monotone::lower_hull(first, last, first2, k);
        monotone::upper_hull(first, last, first2, k);

        return first2 + (k - 1);
    }
}

namespace hull::algorithms {
    /**
     * Compute the convex hull of a container of points following
     * the Monotone Chain algorithm. This algorithm does not work in-place, but
     * it still modifies the input points (it sorts them by x-coordinates).
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * Reference: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 monotone_chain(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        static_assert_is_random_access_iterator_to_point<RandomIt1>();
        static_assert_is_random_access_iterator_to_point<RandomIt2>();

        const auto N = std::distance(first, last);
        if (N <= 1) {
            return std::copy(first, last, first2);
        }

        return details::monotone_chain_impl(first, last, first2);
    }
}

namespace hull {
    /**
     * Compile-time enumeration to choose the
     * algorithm thanks to a policy approach.
     * @param monotone_chain_t - Monotone Chain algorithm.
     */
    struct monotone_chain_t {};

    /**
     * Algorithms policies to choose an overload.
     * @param monotone_chain - Monotone Chain algorithm.
     */
    namespace choice {
        static constexpr const monotone_chain_t monotone_chain{};
    }

    /**
     * Overload of iterator-based convex hull computation for Monotone Chain.
     * Note that the input is modified.
     * Average time complexity: O(N * log(N)) where N is the number of
     * points.
     * Average space complexity: O(3 * N).
     * It is unfortunately not possible to use a std::back_insert_iterator.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           destination container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto compute_convex_hull(monotone_chain_t policy, RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        using value_type = typename std::iterator_traits<RandomIt2>::value_type;
        std::fill_n(first2, 2 * std::distance(first, last), value_type{});

        return algorithms::monotone_chain(first, last, first2);
    }

    namespace convex {
        /**
         * Overload of container-based convex hull computation for Monotone Chain.
         * Average time complexity: O(N * log(N)) where N is the number of
         * points.
         * Average space complexity: O(4 * N).
         * @param c1 - the input container.
         * @param c2 - the destination container.
         */
        template <typename TContainer1, typename TContainer2>
        void compute(monotone_chain_t policy, TContainer1 c1, TContainer2& c2) {
            c2.resize(2 * c1.size());

            std::fill(std::begin(c2), std::end(c2), typename TContainer2::value_type{});
            auto last = hull::algorithms::monotone_chain(std::begin(c1), std::end(c1), std::begin(c2));

            c2.erase(last, std::end(c2));
        }
    }
}

#endif
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

#ifndef rtkWaterPrecorrectionImageFilter_hxx
#define rtkWaterPrecorrectionImageFilter_hxx

#include <itkImageRegionConstIterator.h>
#include <itkImageRegionIterator.h>

#include "rtkWaterPrecorrectionImageFilter.h"

namespace rtk
{
template <class TInputImage, class  TOutputImage>
WaterPrecorrectionImageFilter<TInputImage, TOutputImage>
::WaterPrecorrectionImageFilter()
{
  m_Coefficients.push_back(0.0);  // No correction by default
  m_Coefficients.push_back(1.0);
}

template <class TInputImage, class  TOutputImage>
void WaterPrecorrectionImageFilter<TInputImage,TOutputImage>
::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType itkNotUsed(threadId) )
{
  const int csize = m_Coefficients.size();

  typename itk::ImageRegionConstIterator< TInputImage > itIn(this->GetInput(), outputRegionForThread);
  typename itk::ImageRegionIterator< TOutputImage >     itOut(this->GetOutput(), outputRegionForThread);

  if ( csize >= 3 )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();

    while ( !itIn.IsAtEnd() )
      {
      float v = itIn.Get();
      float out = m_Coefficients[0] + m_Coefficients[1] * v;
      float bpow = v * v;

      for ( int i = 2; i < csize; i++ )
        {
        out += m_Coefficients[i] * bpow;
        bpow = bpow * v;
        }
      itOut.Set(out);

      ++itIn;
      ++itOut;
      }
    }
  else if ( ( csize == 2 ) && ( ( m_Coefficients[0] != 0 ) || ( m_Coefficients[1] != 1 ) ) )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();
    while ( !itIn.IsAtEnd() )
      {
      itOut.Set( m_Coefficients[0] + m_Coefficients[1] * itIn.Get() );
      ++itIn;
      ++itOut;
      }
    }
  else if ( ( csize == 1 ) && ( m_Coefficients[0] != 0 ) )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();
    while ( !itIn.IsAtEnd() )
      {
      itOut.Set( m_Coefficients[0] + itIn.Get() );
      ++itIn;
      ++itOut;
      }
    }
}
} // end namespace rtk

#endif // rtkWaterPrecorrectionImageFilter_hxx
<commit_msg>FIX: order 0 water pre-correction seemed wrong<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

#ifndef rtkWaterPrecorrectionImageFilter_hxx
#define rtkWaterPrecorrectionImageFilter_hxx

#include <itkImageRegionConstIterator.h>
#include <itkImageRegionIterator.h>

#include "rtkWaterPrecorrectionImageFilter.h"

namespace rtk
{
template <class TInputImage, class  TOutputImage>
WaterPrecorrectionImageFilter<TInputImage, TOutputImage>
::WaterPrecorrectionImageFilter()
{
  m_Coefficients.push_back(0.0);  // No correction by default
  m_Coefficients.push_back(1.0);
}

template <class TInputImage, class  TOutputImage>
void WaterPrecorrectionImageFilter<TInputImage,TOutputImage>
::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType itkNotUsed(threadId) )
{
  const int csize = m_Coefficients.size();

  typename itk::ImageRegionConstIterator< TInputImage > itIn(this->GetInput(), outputRegionForThread);
  typename itk::ImageRegionIterator< TOutputImage >     itOut(this->GetOutput(), outputRegionForThread);

  if ( csize >= 3 )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();

    while ( !itIn.IsAtEnd() )
      {
      float v = itIn.Get();
      float out = m_Coefficients[0] + m_Coefficients[1] * v;
      float bpow = v * v;

      for ( int i = 2; i < csize; i++ )
        {
        out += m_Coefficients[i] * bpow;
        bpow = bpow * v;
        }
      itOut.Set(out);

      ++itIn;
      ++itOut;
      }
    }
  else if ( ( csize == 2 ) && ( ( m_Coefficients[0] != 0 ) || ( m_Coefficients[1] != 1 ) ) )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();
    while ( !itIn.IsAtEnd() )
      {
      itOut.Set( m_Coefficients[0] + m_Coefficients[1] * itIn.Get() );
      ++itIn;
      ++itOut;
      }
    }
  else if ( ( csize == 1 ) && ( m_Coefficients[0] != 0 ) )
    {
    itIn.GoToBegin();
    itOut.GoToBegin();
    while ( !itIn.IsAtEnd() )
      {
      itOut.Set( m_Coefficients[0]);
      ++itIn;
      ++itOut;
      }
    }
}
} // end namespace rtk

#endif // rtkWaterPrecorrectionImageFilter_hxx
<|endoftext|>


<commit_before><commit_msg>`Text3DStruct`: remove unused variable `text_string_char`.<commit_after><|endoftext|>


<commit_before>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_STRING_HPP
#define TOML11_STRING_HPP
#include <string>
#include <cstdint>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif
#endif

namespace toml
{

enum class string_t : std::uint8_t
{
    basic   = 0,
    literal = 1,
};

struct string
{
    string()  = default;
    ~string() = default;
    string(const string& s) = default;
    string(string&& s)      = default;
    string& operator=(const string& s) = default;
    string& operator=(string&& s)      = default;

    string(const std::string& s): kind(string_t::basic), str(s){}
    string(const std::string& s, string_t k):   kind(k), str(s){}
    string(const char* s):        kind(string_t::basic), str(s){}
    string(const char* s,        string_t k):   kind(k), str(s){}

    string(std::string&& s): kind(string_t::basic), str(std::move(s)){}
    string(std::string&& s, string_t k):   kind(k), str(std::move(s)){}

    string& operator=(const std::string& s)
    {kind = string_t::basic; str = s; return *this;}
    string& operator=(std::string&& s)
    {kind = string_t::basic; str = std::move(s); return *this;}

    operator std::string&       () &      noexcept {return str;}
    operator std::string const& () const& noexcept {return str;}
    operator std::string&&      () &&     noexcept {return std::move(str);}

#if __cplusplus >= 201703L
    explicit string(std::string_view s): kind(string_t::basic), str(s){}
    string(std::string_view s, string_t k): kind(k), str(s){}

    string& operator=(std::string_view s)
    {kind = string_t::basic; str = s; return *this;}

    explicit operator std::string_view() const noexcept
    {return std::string_view(str);}
#endif

    string_t    kind;
    std::string str;
};

inline bool operator==(const string& lhs, const string& rhs)
{
    return lhs.kind == rhs.kind && lhs.str == rhs.str;
}
inline bool operator!=(const string& lhs, const string& rhs)
{
    return !(lhs == rhs);
}
inline bool operator<(const string& lhs, const string& rhs)
{
    return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind);
}
inline bool operator>(const string& lhs, const string& rhs)
{
    return rhs < lhs;
}
inline bool operator<=(const string& lhs, const string& rhs)
{
    return !(rhs < lhs);
}
inline bool operator>=(const string& lhs, const string& rhs)
{
    return !(lhs < rhs);
}

inline bool
operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;}
inline bool
operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;}
inline bool
operator< (const string& lhs, const std::string& rhs) {return lhs.str <  rhs;}
inline bool
operator> (const string& lhs, const std::string& rhs) {return lhs.str >  rhs;}
inline bool
operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;}
inline bool
operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;}

inline bool
operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;}
inline bool
operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;}
inline bool
operator< (const std::string& lhs, const string& rhs) {return lhs <  rhs.str;}
inline bool
operator> (const std::string& lhs, const string& rhs) {return lhs >  rhs.str;}
inline bool
operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;}
inline bool
operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;}

inline bool
operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);}
inline bool
operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);}
inline bool
operator< (const string& lhs, const char* rhs) {return lhs.str <  std::string(rhs);}
inline bool
operator> (const string& lhs, const char* rhs) {return lhs.str >  std::string(rhs);}
inline bool
operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);}
inline bool
operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);}

inline bool
operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;}
inline bool
operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;}
inline bool
operator< (const char* lhs, const string& rhs) {return std::string(lhs) <  rhs.str;}
inline bool
operator> (const char* lhs, const string& rhs) {return std::string(lhs) >  rhs.str;}
inline bool
operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;}
inline bool
operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;}

template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const string& s)
{
    if(s.kind == string_t::basic)
    {
        if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
        {
            // it contains newline. make it multiline string.
            os << "\"\"\"\n";
            for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
            {
                switch(*i)
                {
                    case '\\': {os << "\\\\"; break;}
                    case '\"': {os << "\\\""; break;}
                    case '\b': {os << "\\b";  break;}
                    case '\t': {os << "\\t";  break;}
                    case '\f': {os << "\\f";  break;}
                    case '\n': {os << '\n';   break;}
                    case '\r':
                    {
                        // since it is a multiline string,
                        // CRLF is not needed to be escaped.
                        if(std::next(i) != e && *std::next(i) == '\n')
                        {
                            os << "\r\n";
                            ++i;
                        }
                        else
                        {
                            os << "\\r";
                        }
                        break;
                    }
                    default: {os << *i; break;}
                }
            }
            os << "\\\n\"\"\"";
            return os;
        }
        // no newline. make it inline.
        os << "\"";
        for(const auto c : s.str)
        {
            switch(c)
            {
                case '\\': {os << "\\\\"; break;}
                case '\"': {os << "\\\""; break;}
                case '\b': {os << "\\b";  break;}
                case '\t': {os << "\\t";  break;}
                case '\f': {os << "\\f";  break;}
                case '\n': {os << "\\n";  break;}
                case '\r': {os << "\\r";  break;}
                default  : {os << c;      break;}
            }
        }
        os << "\"";
        return os;
    }
    // the string `s` is literal-string.
    if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
       std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
    {
        // contains newline or single quote. make it multiline.
        os << "'''\n" << s.str << "'''";
        return os;
    }
    // normal literal string
    os << '\'' << s.str << '\'';
    return os;
}

} // toml
#endif// TOML11_STRING_H
<commit_msg>feat: add operator+= to toml::string<commit_after>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_STRING_HPP
#define TOML11_STRING_HPP
#include <algorithm>
#include <string>
#include <cstdint>
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif
#endif

namespace toml
{

enum class string_t : std::uint8_t
{
    basic   = 0,
    literal = 1,
};

struct string
{
    string()  = default;
    ~string() = default;
    string(const string& s) = default;
    string(string&& s)      = default;
    string& operator=(const string& s) = default;
    string& operator=(string&& s)      = default;

    string(const std::string& s): kind(string_t::basic), str(s){}
    string(const std::string& s, string_t k):   kind(k), str(s){}
    string(const char* s):        kind(string_t::basic), str(s){}
    string(const char* s,        string_t k):   kind(k), str(s){}

    string(std::string&& s): kind(string_t::basic), str(std::move(s)){}
    string(std::string&& s, string_t k):   kind(k), str(std::move(s)){}

    string& operator=(const std::string& s)
    {kind = string_t::basic; str = s; return *this;}
    string& operator=(std::string&& s)
    {kind = string_t::basic; str = std::move(s); return *this;}

    operator std::string&       () &      noexcept {return str;}
    operator std::string const& () const& noexcept {return str;}
    operator std::string&&      () &&     noexcept {return std::move(str);}

    string& operator+=(const char*        rhs) {str += rhs; return *this;}
    string& operator+=(const char         rhs) {str += rhs; return *this;}
    string& operator+=(const std::string& rhs) {str += rhs; return *this;}
    string& operator+=(const string&      rhs) {str += rhs.str; return *this;}

#if __cplusplus >= 201703L
    explicit string(std::string_view s): kind(string_t::basic), str(s){}
    string(std::string_view s, string_t k): kind(k), str(s){}

    string& operator=(std::string_view s)
    {kind = string_t::basic; str = s; return *this;}

    explicit operator std::string_view() const noexcept
    {return std::string_view(str);}

    string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
#endif

    string_t    kind;
    std::string str;
};

inline bool operator==(const string& lhs, const string& rhs)
{
    return lhs.kind == rhs.kind && lhs.str == rhs.str;
}
inline bool operator!=(const string& lhs, const string& rhs)
{
    return !(lhs == rhs);
}
inline bool operator<(const string& lhs, const string& rhs)
{
    return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind);
}
inline bool operator>(const string& lhs, const string& rhs)
{
    return rhs < lhs;
}
inline bool operator<=(const string& lhs, const string& rhs)
{
    return !(rhs < lhs);
}
inline bool operator>=(const string& lhs, const string& rhs)
{
    return !(lhs < rhs);
}

inline bool
operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;}
inline bool
operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;}
inline bool
operator< (const string& lhs, const std::string& rhs) {return lhs.str <  rhs;}
inline bool
operator> (const string& lhs, const std::string& rhs) {return lhs.str >  rhs;}
inline bool
operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;}
inline bool
operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;}

inline bool
operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;}
inline bool
operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;}
inline bool
operator< (const std::string& lhs, const string& rhs) {return lhs <  rhs.str;}
inline bool
operator> (const std::string& lhs, const string& rhs) {return lhs >  rhs.str;}
inline bool
operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;}
inline bool
operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;}

inline bool
operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);}
inline bool
operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);}
inline bool
operator< (const string& lhs, const char* rhs) {return lhs.str <  std::string(rhs);}
inline bool
operator> (const string& lhs, const char* rhs) {return lhs.str >  std::string(rhs);}
inline bool
operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);}
inline bool
operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);}

inline bool
operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;}
inline bool
operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;}
inline bool
operator< (const char* lhs, const string& rhs) {return std::string(lhs) <  rhs.str;}
inline bool
operator> (const char* lhs, const string& rhs) {return std::string(lhs) >  rhs.str;}
inline bool
operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;}
inline bool
operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;}

template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const string& s)
{
    if(s.kind == string_t::basic)
    {
        if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
        {
            // it contains newline. make it multiline string.
            os << "\"\"\"\n";
            for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
            {
                switch(*i)
                {
                    case '\\': {os << "\\\\"; break;}
                    case '\"': {os << "\\\""; break;}
                    case '\b': {os << "\\b";  break;}
                    case '\t': {os << "\\t";  break;}
                    case '\f': {os << "\\f";  break;}
                    case '\n': {os << '\n';   break;}
                    case '\r':
                    {
                        // since it is a multiline string,
                        // CRLF is not needed to be escaped.
                        if(std::next(i) != e && *std::next(i) == '\n')
                        {
                            os << "\r\n";
                            ++i;
                        }
                        else
                        {
                            os << "\\r";
                        }
                        break;
                    }
                    default: {os << *i; break;}
                }
            }
            os << "\\\n\"\"\"";
            return os;
        }
        // no newline. make it inline.
        os << "\"";
        for(const auto c : s.str)
        {
            switch(c)
            {
                case '\\': {os << "\\\\"; break;}
                case '\"': {os << "\\\""; break;}
                case '\b': {os << "\\b";  break;}
                case '\t': {os << "\\t";  break;}
                case '\f': {os << "\\f";  break;}
                case '\n': {os << "\\n";  break;}
                case '\r': {os << "\\r";  break;}
                default  : {os << c;      break;}
            }
        }
        os << "\"";
        return os;
    }
    // the string `s` is literal-string.
    if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
       std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
    {
        // contains newline or single quote. make it multiline.
        os << "'''\n" << s.str << "'''";
        return os;
    }
    // normal literal string
    os << '\'' << s.str << '\'';
    return os;
}

} // toml
#endif// TOML11_STRING_H
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 <QApplication>

#include "pqOptions.h"
#include "pqPVApplicationCore.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"

#include "MainWindow.h"
#include "TomVizPythonConfig.h"

#include <clocale>

// We need to override the default options to enable streaming by default.
// Streaming needs to be enabled for the dax representations
class TomoOptions : public pqOptions
{
public:
  static TomoOptions* New();
  vtkTypeMacro(TomoOptions, pqOptions);
  virtual int GetEnableStreaming() { return 1; }

protected:
  TomoOptions(): pqOptions()
  { }
};
vtkStandardNewMacro(TomoOptions);

int main(int argc, char** argv)
{
  QCoreApplication::setApplicationName("TomViz");
  QCoreApplication::setApplicationVersion("0.1.0");
  QCoreApplication::setOrganizationName("Kitware");

  tomviz::InitializePythonEnvironment(argc, argv);

  QApplication app(argc, argv);
  setlocale(LC_NUMERIC, "C");
  vtkNew<TomoOptions> options;
  pqPVApplicationCore appCore(argc, argv, options.GetPointer());
  tomviz::MainWindow window;
  window.show();
  return app.exec();
}
<commit_msg>Clean up name, minor compiler warnings, include style<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 <QApplication>

#include <pqOptions.h>
#include <pqPVApplicationCore.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>

#include "MainWindow.h"
#include "TomVizPythonConfig.h"

#include <clocale>

// We need to override the default options to enable streaming by default.
// Streaming needs to be enabled for the dax representations
class TomvizOptions : public pqOptions
{
public:
  static TomvizOptions* New();
  vtkTypeMacro(TomvizOptions, pqOptions)
  virtual int GetEnableStreaming() { return 1; }

protected:
  TomvizOptions() : pqOptions() { ; }
};
vtkStandardNewMacro(TomvizOptions)

int main(int argc, char** argv)
{
  QCoreApplication::setApplicationName("tomviz");
  QCoreApplication::setApplicationVersion("0.1.0");
  QCoreApplication::setOrganizationName("Kitware");

  tomviz::InitializePythonEnvironment(argc, argv);

  QApplication app(argc, argv);
  setlocale(LC_NUMERIC, "C");
  vtkNew<TomvizOptions> options;
  pqPVApplicationCore appCore(argc, argv, options.Get());
  tomviz::MainWindow window;
  window.show();
  return app.exec();
}
<|endoftext|>


<commit_before>#include "thumbnailbox.hpp"

ThumbnailBox::ThumbnailBox(QWidget *parent)
            : QFrame(parent),
              updating_thumbnails(false),
              _index(-1),
              _size(.3),
              _showdirs(false),
              _isclickable(true),
              _pixmaxwh(200),
              _pixsource(0),
              thumbarea(0)
{
    QHBoxLayout *hbox;

    hbox = new QHBoxLayout;

    thumbcontainer = new QWidget;
    thumbcontainerlayout = new QHBoxLayout;
    thumbcontainerlayout->setContentsMargins(QMargins());
    thumbcontainerlayout->setSpacing(2);
    //This is where the thumbarea will be...
    thumbcontainer->setLayout(thumbcontainerlayout);
    hbox->addWidget(thumbcontainer);

    scrollbar = new QScrollBar(Qt::Vertical);
    scrollbar->setTracking(true);
    scrollbar->setMinimum(0);
    scrollbar->setMaximum(0);
    connect(scrollbar,
            SIGNAL(valueChanged(int)),
            SLOT(updateThumbnails(int)));

    hbox->addWidget(scrollbar);

    setLayout(hbox);

    connect(this, SIGNAL(resized()), SLOT(updateThumbnails()));

    connect(this, SIGNAL(itemSelected(int)), SLOT(ensureItemVisible(int)));

    connect(this,
            SIGNAL(rightClicked(int, const QPoint&)),
            SLOT(showMenu(int, const QPoint&)));

    updatetimer = new QTimer(this);
    updatetimer->setInterval(100);
    updatetimer->stop();
    connect(updatetimer, SIGNAL(timeout()), SLOT(updateThumbnails()));
}

void
ThumbnailBox::resizeEvent(QResizeEvent *event)
{
    if (event->oldSize().isValid())
    emit resized();
}

void
ThumbnailBox::wheelEvent(QWheelEvent *event)
{
    int degrees = event->delta() / 8;
    int steps = degrees / 15;

    if (event->orientation() != Qt::Vertical) return;
    if (!scrollbar->isEnabled()) return;

    scrollbar->setValue(scrollbar->value() - steps);

    event->accept();
}

void
ThumbnailBox::showMenu(int index, const QPoint &pos)
{
    if (!isMenuEnabled()) return;

    QString item = itemPath(index);
    if (item.isEmpty()) return;

    QString title = QFileInfo(item).fileName();

    QMenu menu;
    QAction *action = new QAction(title, &menu);
    QFont font = action->font();
    font.setBold(true);
    action->setFont(font);
    action->setEnabled(false);
    menu.addAction(action);
    foreach (QAction *action, _actions)
    {
        menu.addAction(action);
    }

    emit menuItemSelected(menu.exec(pos), item);
}

QPixmap
ThumbnailBox::getPixmap(QString file)
{
    int maxwh = _pixmaxwh; //Thumbs shouldn't be larger than this

    //Search cache

    if (_pixsource) return _pixsource(file);

    if (_pixcache.contains(file)) return _pixcache[file];

    //Load file

    if (!QFile::exists(file)) return QPixmap();

    QImage img(QImage(file).scaled(maxwh, maxwh, Qt::KeepAspectRatio));
    QPixmap pix(QPixmap::fromImage(img));

    if (!pix.isNull()) _pixcache[file] = pix;

    return pix;
}

void
ThumbnailBox::clearCache()
{
    _pixcache.clear();
}

int
ThumbnailBox::availableWidth()
{
    return thumbcontainer->width();
}

int
ThumbnailBox::availableHeight()
{
    return thumbcontainer->height();
}

int
ThumbnailBox::columnCount()
{
    int cols;
    int padding = 5;
    int availablewidth = availableWidth();
    int thumbsize = thumbWidth();
    int thumbwidth = thumbsize;
    cols = availablewidth / (thumbwidth + padding); //2.9 -> 2
    return cols;
}

int
ThumbnailBox::rowCount()
{
    int rows;
    int padding = 5;
    int availableheight = availableHeight();
    int thumbsize = thumbWidth();
    int thumbheight = thumbsize;
    rows = availableheight / (thumbheight + padding); //2.9 -> 2
    return rows;
}

int
ThumbnailBox::topRow()
{
    int scrollpos = scrollbar->value();
    return scrollpos;
}

int
ThumbnailBox::bottomRow()
{
    return topRow() + (rowCount() - 1);
}

QFileInfoList&
ThumbnailBox::items()
{
    QFileInfoList &list(_list);
    for (int i = list.size(); --i >= 0 && !directoriesVisible();)
    {
        if (list[i].isDir()) list.removeAt(i);
    }
    return list;
}

QStringList
ThumbnailBox::list()
{
    QStringList paths;
    foreach (QFileInfo inf, items()) paths << inf.absoluteFilePath();
    return paths;
}

int
ThumbnailBox::count()
{
    return items().size();
}

double
ThumbnailBox::thumbSize()
{
    return _size;
}

int
ThumbnailBox::thumbWidth()
{
    int availablewidth = availableWidth();
    int width = availablewidth;
    width *= thumbSize();
    if (width < 30) width = 30; //Should be a const

    return width;
}

bool
ThumbnailBox::isValidIndex(int index)
{
    return (index >= 0 && index < count());
}

int
ThumbnailBox::index()
{
    if (_index < 0) _index = -1;
    if (_index >= list().size()) _index = -1;
    return _index;
}

bool
ThumbnailBox::isSelected()
{
    return (index() != -1);
}

QFileInfo
ThumbnailBox::item(int index)
{
    QFileInfo inf;
    if (index == -1) index = this->index();
    if (isValidIndex(index)) inf = items().at(index);
    return inf;
}

QString
ThumbnailBox::itemPath(int index)
{
    return item(index).absoluteFilePath();
}

bool
ThumbnailBox::isFirst()
{
    return (index() == 0);
}

bool
ThumbnailBox::isLast()
{
    return (index() == count() - 1);
}

QString
ThumbnailBox::path()
{
    return _path;
}

bool
ThumbnailBox::directoriesVisible()
{
    return _showdirs;
}

bool
ThumbnailBox::itemsClickable()
{
    return _isclickable;
}

void
ThumbnailBox::addMenuItem(QAction *action)
{
    if (!action) return;
    if (!_actions.contains(action))
    {
        _actions << action;
    }
}

void
ThumbnailBox::removeMenuItem(QAction *action)
{
    if (action) _actions.removeAll(action);
    else _actions.clear();
}

bool
ThumbnailBox::isMenuEnabled()
{
    return _actions.size();
}

void
ThumbnailBox::scrollToRow(int row)
{
    scrollbar->setValue(row);
}

void
ThumbnailBox::updateThumbnails()
{
    int count = this->count(); //Total amount of files
    //int availablewidth = availableWidth();
    //int availableheight = availableHeight();
    int thumbwidth;
    int thumbheight;
    int padding = 5;
    int cols;
    int rows;
    int totalrows; //Row count (incl. hidden)
    int totalhiddenrows;
    int maxthumbs; //Maximum visible thumbs
    int visiblethumbs; //Visible thumbs needed
    int scrollpos;
    int hiddenrows; //Rows hidden ABOVE viewport
    int hiddenthumbs; //Thumbs hidden ABOVE viewport

    if (updating_thumbnails) return;
    updating_thumbnails = true;

    int thumbsize = thumbWidth();
    thumbwidth = thumbsize;
    if (thumbwidth < 30) thumbwidth = 30;
    thumbheight = thumbwidth;

    cols = columnCount(); //2.9 -> 2
    rows = rowCount(); //2.9 -> 2
    if (!cols) cols = 1;
    if (!rows) rows = 1;
    maxthumbs = cols * rows;
    visiblethumbs = count;
    if (visiblethumbs > maxthumbs) visiblethumbs = maxthumbs;
    totalrows = count / cols; if (count % cols) totalrows++; //2.1 -> 3
    totalhiddenrows = totalrows - rows;

    //Important:
    //Everytime an update is triggered,
    //the thumbnail area widget is recreated
    //and filled with the amount of visible thumbs.
    //This is important for large directories (> 1000 items),
    //because creating 1000 thumbs is inefficient/stupid/sigsegv.

    if (thumbarea) delete thumbarea;
    thumbarea = new QWidget();
    thumbcontainerlayout->insertWidget(0, thumbarea);
    thumbarea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    if (totalhiddenrows >= 0) scrollbar->setMaximum(totalhiddenrows);
    scrollbar->setPageStep(rows);

    scrollpos = scrollbar->value();
    hiddenrows = scrollpos;
    hiddenthumbs = hiddenrows * cols;

    QVBoxLayout *vbox_rows = new QVBoxLayout;
    thumbarea->setLayout(vbox_rows);

    for (int i = 0; i < rows; i++)
    {
        QHBoxLayout *hbox_row = new QHBoxLayout;
        hbox_row->setSpacing(padding);
        for (int j = 0; j < cols; j++)
        {
            int relindex = i * cols + j;
            int absindex = relindex + hiddenthumbs;
            if (absindex >= count) break;
            int index = this->index();

            QString title = item(absindex).fileName();
            Thumb *thumb = new Thumb;
            thumb->setEnabled(itemsClickable());
            connect(thumb,
                    SIGNAL(clicked(int)),
                    SLOT(select(int)));
            thumb->setIndex(absindex);
            thumb->setFixedSize(QSize(thumbwidth, thumbheight));
            thumb->setFrameStyle(QFrame::Panel | QFrame::Raised);
            if (absindex == index) thumb->setFrameShadow(QFrame::Sunken);
            thumb->setLineWidth(2);
            thumb->setToolTip(title);
            hbox_row->addWidget(thumb);
            QVBoxLayout *vbox = new QVBoxLayout;
            QLabel *lbl = new QLabel();
            lbl->setPixmap(getPixmap(itemPath(absindex)));
            lbl->setScaledContents(true);
            vbox->addWidget(lbl);
            lbl = new QLabel(title);
            lbl->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
            vbox->addWidget(lbl);
            thumb->setLayout(vbox);
            connect(thumb,
                    SIGNAL(clicked(int)),
                    SIGNAL(clicked(int)));
            connect(thumb,
                    SIGNAL(clicked(int, const QPoint&)),
                    SIGNAL(clicked(int, const QPoint&)));
            connect(thumb,
                    SIGNAL(rightClicked(int)),
                    SIGNAL(rightClicked(int)));
            connect(thumb,
                    SIGNAL(rightClicked(int, const QPoint&)),
                    SIGNAL(rightClicked(int, const QPoint&)));
            connect(thumb,
                    SIGNAL(contextMenuRequested(const QPoint&)),
                    SIGNAL(contextMenuRequested(const QPoint&)));
            connect(thumb,
                    SIGNAL(middleClicked(int)),
                    SIGNAL(middleClicked(int)));
            connect(thumb,
                    SIGNAL(middleClicked(int, const QPoint&)),
                    SIGNAL(middleClicked(int, const QPoint&)));
        }
        hbox_row->addStretch(1);
        vbox_rows->addLayout(hbox_row);
    }
    vbox_rows->addStretch(1);

    emit updated();

    updating_thumbnails = false;
}

void
ThumbnailBox::updateThumbnails(int unused)
{
    updateThumbnails();
}

void
ThumbnailBox::scheduleUpdateThumbnails()
{
    updatetimer->setSingleShot(true);
    updatetimer->start();
}

void
ThumbnailBox::setThumbSize(double percent)
{
    if (percent < 0) percent = 0;
    if (percent > 1) percent = 1;
    _size = percent;

    updateThumbnails();

    setMinimumHeight(thumbWidth() * 1.5);
}

void
ThumbnailBox::setThumbSize(int percent)
{
    setThumbSize((double)percent / 100);
}

void
ThumbnailBox::setThumbWidth(int width)
{
    double percent = 0;
    int availwidth = availableWidth();
    if (availwidth) percent = width / availwidth;
    setThumbSize(percent);
}

void
ThumbnailBox::select(int index)
{
    if (!isEnabled()) return;

    if (!isValidIndex(index)) index = -1;
    if (index == this->index()) return;
    _index = index;
    //updateThumbnails(); //Segfault for no apparent reason
    scheduleUpdateThumbnails();

    emit selectionChanged();
    if (index != -1)
    {
        emit itemSelected(index);
        emit itemSelected(itemPath(index));
    }
}

void
ThumbnailBox::unselect()
{
    select(-1);
}

void
ThumbnailBox::selectPrevious()
{
    if (!isFirst()) select(index() - 1);
}

void
ThumbnailBox::selectNext()
{
    if (!isLast()) select(index() + 1);
}

void
ThumbnailBox::ensureItemVisible(int index)
{
    //Scroll to item, if out of viewport

    if (index < 0 || index >= count()) return;
    int col_count = columnCount();
    int row_item = (double)index / (double)col_count;
    int row_top = topRow();
    int row_bottom = bottomRow();

    if (row_item < row_top) //Item above viewport
    {
        //Make item row 2nd from top?
        scrollToRow(row_item);
    }
    else if (row_item > row_bottom) //Item below viewport
    {
        //Make item row 2nd from bottom?
        scrollToRow(row_item);
    }
}

void
ThumbnailBox::setNameFilter(QStringList filter)
{
    _filter = filter;

    reload();
}

void
ThumbnailBox::reload()
{
    QString path = this->path();
    _path.clear();
    navigateTo(path);
}

bool
ThumbnailBox::setList(const QStringList &paths, int selected)
{
    clearCache();

    _path.clear();
    _index = -1;
    _index = selected;

    QFileInfoList &list = _list;
    list.clear();

    foreach (QString path, paths)
    {
        QFileInfo inf(path);
        if (!inf.isFile() &&
            !inf.isDir()) continue; //Invalid entry
        list << inf;
    }

    updateThumbnails();

    emit selectionChanged();

    return true;
}

bool
ThumbnailBox::setList(const QStringList &paths, const QString &selected)
{
    return setList(paths, paths.indexOf(selected));
}

bool
ThumbnailBox::navigateTo(const QString &path, const QString &selected)
{
    QDir dir(path);
    if (!dir.exists()) return false;
    if (path == this->path()) return true;
    _path = path;

    clearCache();

    _index = -1;

    QFileInfoList &list = _list;
    QDir::Filters filter = QDir::AllEntries | QDir::Hidden | QDir::System;
    QDir::SortFlags flags = QDir::Name | QDir::DirsFirst;

    if (_filter.size()) list = dir.entryInfoList(_filter, filter, flags);
    else list = dir.entryInfoList(filter, flags);

    if (!selected.isEmpty()) _index = this->list().indexOf(selected);

    updateThumbnails();

    emit selectionChanged();

    return true;
}

bool
ThumbnailBox::navigate2(QString path, QString selected)
{
    return navigateTo(path);
}

void
ThumbnailBox::setDirectoriesVisible(bool enable)
{
    _showdirs = enable;

    updateThumbnails();
}

void
ThumbnailBox::setItemsClickable(bool enable)
{
    _isclickable = enable;

    updateThumbnails();
}

void
ThumbnailBox::setPixMaxWH(int wh)
{
    if (wh < 0) wh = 0; //Even 0 is nonsense
    _pixmaxwh = wh;
}

void
ThumbnailBox::setPixmapSource(QPixmap(*pixsource)(QString))
{
    _pixsource = pixsource;
}

void
ThumbnailBox::setPixmapSource()
{
    _pixsource = 0;
}

//---

Thumb::Thumb(QWidget *parent)
     : QFrame(parent),
       index(0)
{
}

void
Thumb::setIndex(int index)
{
    this->index = index;
}

void
Thumb::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        emit clicked(index);
        emit clicked(index, event->globalPos());
    }
    else if (event->button() == Qt::RightButton)
    {
        emit rightClicked(index);
        emit rightClicked(index, event->globalPos());
        emit contextMenuRequested(event->globalPos());
    }
    else if (event->button() == Qt::MidButton)
    {
        emit middleClicked(index);
        emit middleClicked(index, event->globalPos());
    }
}

<commit_msg>Fix scrollbar bug<commit_after>#include "thumbnailbox.hpp"

ThumbnailBox::ThumbnailBox(QWidget *parent)
            : QFrame(parent),
              updating_thumbnails(false),
              _index(-1),
              _size(.3),
              _showdirs(false),
              _isclickable(true),
              _pixmaxwh(200),
              _pixsource(0),
              thumbarea(0)
{
    QHBoxLayout *hbox;

    hbox = new QHBoxLayout;

    thumbcontainer = new QWidget;
    thumbcontainerlayout = new QHBoxLayout;
    thumbcontainerlayout->setContentsMargins(QMargins());
    thumbcontainerlayout->setSpacing(2);
    //This is where the thumbarea will be...
    thumbcontainer->setLayout(thumbcontainerlayout);
    hbox->addWidget(thumbcontainer);

    scrollbar = new QScrollBar(Qt::Vertical);
    scrollbar->setTracking(true);
    scrollbar->setMinimum(0);
    scrollbar->setMaximum(0);
    connect(scrollbar,
            SIGNAL(valueChanged(int)),
            SLOT(updateThumbnails(int)));

    hbox->addWidget(scrollbar);

    setLayout(hbox);

    connect(this, SIGNAL(resized()), SLOT(updateThumbnails()));

    connect(this, SIGNAL(itemSelected(int)), SLOT(ensureItemVisible(int)));

    connect(this,
            SIGNAL(rightClicked(int, const QPoint&)),
            SLOT(showMenu(int, const QPoint&)));

    updatetimer = new QTimer(this);
    updatetimer->setInterval(100);
    updatetimer->stop();
    connect(updatetimer, SIGNAL(timeout()), SLOT(updateThumbnails()));
}

void
ThumbnailBox::resizeEvent(QResizeEvent *event)
{
    if (event->oldSize().isValid())
    emit resized();
}

void
ThumbnailBox::wheelEvent(QWheelEvent *event)
{
    int degrees = event->delta() / 8;
    int steps = degrees / 15;

    if (event->orientation() != Qt::Vertical) return;
    if (!scrollbar->isEnabled()) return;

    scrollbar->setValue(scrollbar->value() - steps);

    event->accept();
}

void
ThumbnailBox::showMenu(int index, const QPoint &pos)
{
    if (!isMenuEnabled()) return;

    QString item = itemPath(index);
    if (item.isEmpty()) return;

    QString title = QFileInfo(item).fileName();

    QMenu menu;
    QAction *action = new QAction(title, &menu);
    QFont font = action->font();
    font.setBold(true);
    action->setFont(font);
    action->setEnabled(false);
    menu.addAction(action);
    foreach (QAction *action, _actions)
    {
        menu.addAction(action);
    }

    emit menuItemSelected(menu.exec(pos), item);
}

QPixmap
ThumbnailBox::getPixmap(QString file)
{
    int maxwh = _pixmaxwh; //Thumbs shouldn't be larger than this

    //Search cache

    if (_pixsource) return _pixsource(file);

    if (_pixcache.contains(file)) return _pixcache[file];

    //Load file

    if (!QFile::exists(file)) return QPixmap();

    QImage img(QImage(file).scaled(maxwh, maxwh, Qt::KeepAspectRatio));
    QPixmap pix(QPixmap::fromImage(img));

    if (!pix.isNull()) _pixcache[file] = pix;

    return pix;
}

void
ThumbnailBox::clearCache()
{
    _pixcache.clear();
}

int
ThumbnailBox::availableWidth()
{
    return thumbcontainer->width();
}

int
ThumbnailBox::availableHeight()
{
    return thumbcontainer->height();
}

int
ThumbnailBox::columnCount()
{
    int cols;
    int padding = 5;
    int availablewidth = availableWidth();
    int thumbsize = thumbWidth();
    int thumbwidth = thumbsize;
    cols = availablewidth / (thumbwidth + padding); //2.9 -> 2
    return cols;
}

int
ThumbnailBox::rowCount()
{
    int rows;
    int padding = 5;
    int availableheight = availableHeight();
    int thumbsize = thumbWidth();
    int thumbheight = thumbsize;
    rows = availableheight / (thumbheight + padding); //2.9 -> 2
    return rows;
}

int
ThumbnailBox::topRow()
{
    int scrollpos = scrollbar->value();
    return scrollpos;
}

int
ThumbnailBox::bottomRow()
{
    return topRow() + (rowCount() - 1);
}

QFileInfoList&
ThumbnailBox::items()
{
    QFileInfoList &list(_list);
    for (int i = list.size(); --i >= 0 && !directoriesVisible();)
    {
        if (list[i].isDir()) list.removeAt(i);
    }
    return list;
}

QStringList
ThumbnailBox::list()
{
    QStringList paths;
    foreach (QFileInfo inf, items()) paths << inf.absoluteFilePath();
    return paths;
}

int
ThumbnailBox::count()
{
    return items().size();
}

double
ThumbnailBox::thumbSize()
{
    return _size;
}

int
ThumbnailBox::thumbWidth()
{
    int availablewidth = availableWidth();
    int width = availablewidth;
    width *= thumbSize();
    if (width < 30) width = 30; //Should be a const

    return width;
}

bool
ThumbnailBox::isValidIndex(int index)
{
    return (index >= 0 && index < count());
}

int
ThumbnailBox::index()
{
    if (_index < 0) _index = -1;
    if (_index >= list().size()) _index = -1;
    return _index;
}

bool
ThumbnailBox::isSelected()
{
    return (index() != -1);
}

QFileInfo
ThumbnailBox::item(int index)
{
    QFileInfo inf;
    if (index == -1) index = this->index();
    if (isValidIndex(index)) inf = items().at(index);
    return inf;
}

QString
ThumbnailBox::itemPath(int index)
{
    return item(index).absoluteFilePath();
}

bool
ThumbnailBox::isFirst()
{
    return (index() == 0);
}

bool
ThumbnailBox::isLast()
{
    return (index() == count() - 1);
}

QString
ThumbnailBox::path()
{
    return _path;
}

bool
ThumbnailBox::directoriesVisible()
{
    return _showdirs;
}

bool
ThumbnailBox::itemsClickable()
{
    return _isclickable;
}

void
ThumbnailBox::addMenuItem(QAction *action)
{
    if (!action) return;
    if (!_actions.contains(action))
    {
        _actions << action;
    }
}

void
ThumbnailBox::removeMenuItem(QAction *action)
{
    if (action) _actions.removeAll(action);
    else _actions.clear();
}

bool
ThumbnailBox::isMenuEnabled()
{
    return _actions.size();
}

void
ThumbnailBox::scrollToRow(int row)
{
    scrollbar->setValue(row);
}

void
ThumbnailBox::updateThumbnails()
{
    int count = this->count(); //Total amount of files
    //int availablewidth = availableWidth();
    //int availableheight = availableHeight();
    int thumbwidth;
    int thumbheight;
    int padding = 5;
    int cols;
    int rows;
    int totalrows; //Row count (incl. hidden)
    int totalhiddenrows;
    int maxthumbs; //Maximum visible thumbs
    int visiblethumbs; //Visible thumbs needed
    int scrollpos;
    int hiddenrows; //Rows hidden ABOVE viewport
    int hiddenthumbs; //Thumbs hidden ABOVE viewport

    if (updating_thumbnails) return;
    updating_thumbnails = true;

    int thumbsize = thumbWidth();
    thumbwidth = thumbsize;
    if (thumbwidth < 30) thumbwidth = 30;
    thumbheight = thumbwidth;

    cols = columnCount(); //2.9 -> 2
    rows = rowCount(); //2.9 -> 2
    if (!cols) cols = 1;
    if (!rows) rows = 1;
    maxthumbs = cols * rows;
    visiblethumbs = count;
    if (visiblethumbs > maxthumbs) visiblethumbs = maxthumbs;
    totalrows = count / cols; if (count % cols) totalrows++; //2.1 -> 3
    totalhiddenrows = totalrows - rows;
    if (totalhiddenrows < 0) totalhiddenrows = 0;

    //Important:
    //Everytime an update is triggered,
    //the thumbnail area widget is recreated
    //and filled with the amount of visible thumbs.
    //This is important for large directories (> 1000 items),
    //because creating 1000 thumbs is inefficient/stupid/sigsegv.

    if (thumbarea) delete thumbarea;
    thumbarea = new QWidget();
    thumbcontainerlayout->insertWidget(0, thumbarea);
    thumbarea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    if (totalhiddenrows >= 0) scrollbar->setMaximum(totalhiddenrows);
    scrollbar->setPageStep(rows);

    scrollpos = scrollbar->value();
    hiddenrows = scrollpos;
    hiddenthumbs = hiddenrows * cols;

    QVBoxLayout *vbox_rows = new QVBoxLayout;
    thumbarea->setLayout(vbox_rows);

    for (int i = 0; i < rows; i++)
    {
        QHBoxLayout *hbox_row = new QHBoxLayout;
        hbox_row->setSpacing(padding);
        for (int j = 0; j < cols; j++)
        {
            int relindex = i * cols + j;
            int absindex = relindex + hiddenthumbs;
            if (absindex >= count) break;
            int index = this->index();

            QString title = item(absindex).fileName();
            Thumb *thumb = new Thumb;
            thumb->setEnabled(itemsClickable());
            connect(thumb,
                    SIGNAL(clicked(int)),
                    SLOT(select(int)));
            thumb->setIndex(absindex);
            thumb->setFixedSize(QSize(thumbwidth, thumbheight));
            thumb->setFrameStyle(QFrame::Panel | QFrame::Raised);
            if (absindex == index) thumb->setFrameShadow(QFrame::Sunken);
            thumb->setLineWidth(2);
            thumb->setToolTip(title);
            hbox_row->addWidget(thumb);
            QVBoxLayout *vbox = new QVBoxLayout;
            QLabel *lbl = new QLabel();
            lbl->setPixmap(getPixmap(itemPath(absindex)));
            lbl->setScaledContents(true);
            vbox->addWidget(lbl);
            lbl = new QLabel(title);
            lbl->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
            vbox->addWidget(lbl);
            thumb->setLayout(vbox);
            connect(thumb,
                    SIGNAL(clicked(int)),
                    SIGNAL(clicked(int)));
            connect(thumb,
                    SIGNAL(clicked(int, const QPoint&)),
                    SIGNAL(clicked(int, const QPoint&)));
            connect(thumb,
                    SIGNAL(rightClicked(int)),
                    SIGNAL(rightClicked(int)));
            connect(thumb,
                    SIGNAL(rightClicked(int, const QPoint&)),
                    SIGNAL(rightClicked(int, const QPoint&)));
            connect(thumb,
                    SIGNAL(contextMenuRequested(const QPoint&)),
                    SIGNAL(contextMenuRequested(const QPoint&)));
            connect(thumb,
                    SIGNAL(middleClicked(int)),
                    SIGNAL(middleClicked(int)));
            connect(thumb,
                    SIGNAL(middleClicked(int, const QPoint&)),
                    SIGNAL(middleClicked(int, const QPoint&)));
        }
        hbox_row->addStretch(1);
        vbox_rows->addLayout(hbox_row);
    }
    vbox_rows->addStretch(1);

    emit updated();

    updating_thumbnails = false;
}

void
ThumbnailBox::updateThumbnails(int unused)
{
    updateThumbnails();
}

void
ThumbnailBox::scheduleUpdateThumbnails()
{
    updatetimer->setSingleShot(true);
    updatetimer->start();
}

void
ThumbnailBox::setThumbSize(double percent)
{
    if (percent < 0) percent = 0;
    if (percent > 1) percent = 1;
    _size = percent;

    updateThumbnails();

    setMinimumHeight(thumbWidth() * 1.5);
}

void
ThumbnailBox::setThumbSize(int percent)
{
    setThumbSize((double)percent / 100);
}

void
ThumbnailBox::setThumbWidth(int width)
{
    double percent = 0;
    int availwidth = availableWidth();
    if (availwidth) percent = width / availwidth;
    setThumbSize(percent);
}

void
ThumbnailBox::select(int index)
{
    if (!isEnabled()) return;

    if (!isValidIndex(index)) index = -1;
    if (index == this->index()) return;
    _index = index;
    //updateThumbnails(); //Segfault for no apparent reason
    scheduleUpdateThumbnails();

    emit selectionChanged();
    if (index != -1)
    {
        emit itemSelected(index);
        emit itemSelected(itemPath(index));
    }
}

void
ThumbnailBox::unselect()
{
    select(-1);
}

void
ThumbnailBox::selectPrevious()
{
    if (!isFirst()) select(index() - 1);
}

void
ThumbnailBox::selectNext()
{
    if (!isLast()) select(index() + 1);
}

void
ThumbnailBox::ensureItemVisible(int index)
{
    //Scroll to item, if out of viewport

    if (index < 0 || index >= count()) return;
    int col_count = columnCount();
    int row_item = (double)index / (double)col_count;
    int row_top = topRow();
    int row_bottom = bottomRow();

    if (row_item < row_top) //Item above viewport
    {
        //Make item row 2nd from top?
        scrollToRow(row_item);
    }
    else if (row_item > row_bottom) //Item below viewport
    {
        //Make item row 2nd from bottom?
        scrollToRow(row_item);
    }
}

void
ThumbnailBox::setNameFilter(QStringList filter)
{
    _filter = filter;

    reload();
}

void
ThumbnailBox::reload()
{
    QString path = this->path();
    _path.clear();
    navigateTo(path);
}

bool
ThumbnailBox::setList(const QStringList &paths, int selected)
{
    clearCache();

    _path.clear();
    _index = -1;
    _index = selected;

    QFileInfoList &list = _list;
    list.clear();

    foreach (QString path, paths)
    {
        QFileInfo inf(path);
        if (!inf.isFile() &&
            !inf.isDir()) continue; //Invalid entry
        list << inf;
    }

    updateThumbnails();

    emit selectionChanged();

    return true;
}

bool
ThumbnailBox::setList(const QStringList &paths, const QString &selected)
{
    return setList(paths, paths.indexOf(selected));
}

bool
ThumbnailBox::navigateTo(const QString &path, const QString &selected)
{
    QDir dir(path);
    if (!dir.exists()) return false;
    if (path == this->path()) return true;
    _path = path;

    clearCache();

    _index = -1;

    QFileInfoList &list = _list;
    QDir::Filters filter = QDir::AllEntries | QDir::Hidden | QDir::System;
    QDir::SortFlags flags = QDir::Name | QDir::DirsFirst;

    if (_filter.size()) list = dir.entryInfoList(_filter, filter, flags);
    else list = dir.entryInfoList(filter, flags);

    if (!selected.isEmpty()) _index = this->list().indexOf(selected);

    updateThumbnails();

    emit selectionChanged();

    return true;
}

bool
ThumbnailBox::navigate2(QString path, QString selected)
{
    return navigateTo(path);
}

void
ThumbnailBox::setDirectoriesVisible(bool enable)
{
    _showdirs = enable;

    updateThumbnails();
}

void
ThumbnailBox::setItemsClickable(bool enable)
{
    _isclickable = enable;

    updateThumbnails();
}

void
ThumbnailBox::setPixMaxWH(int wh)
{
    if (wh < 0) wh = 0; //Even 0 is nonsense
    _pixmaxwh = wh;
}

void
ThumbnailBox::setPixmapSource(QPixmap(*pixsource)(QString))
{
    _pixsource = pixsource;
}

void
ThumbnailBox::setPixmapSource()
{
    _pixsource = 0;
}

//---

Thumb::Thumb(QWidget *parent)
     : QFrame(parent),
       index(0)
{
}

void
Thumb::setIndex(int index)
{
    this->index = index;
}

void
Thumb::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        emit clicked(index);
        emit clicked(index, event->globalPos());
    }
    else if (event->button() == Qt::RightButton)
    {
        emit rightClicked(index);
        emit rightClicked(index, event->globalPos());
        emit contextMenuRequested(event->globalPos());
    }
    else if (event->button() == Qt::MidButton)
    {
        emit middleClicked(index);
        emit middleClicked(index, event->globalPos());
    }
}

<|endoftext|>


<commit_before>/*
* Finished Message
* (C) 2004-2006,2012 Jack Lloyd
*
* Released under the terms of the Botan license
*/

#include <botan/internal/tls_messages.h>
#include <botan/prf_tls.h>
#include <botan/hmac.h>
#include <botan/sha2_32.h>
#include <memory>

#include <stdio.h>

namespace Botan {

namespace {

KDF* choose_tls_prf(Version_Code version)
   {
   if(version == TLS_V10 || version == TLS_V11)
      return new TLS_PRF;
   else if(version == TLS_V12)
      return new TLS_12_PRF(new HMAC(new SHA_256)); // might depend on ciphersuite
   else
      throw TLS_Exception(PROTOCOL_VERSION,
                          "Unknown version for PRF");
   }

/*
* Compute the verify_data
*/
MemoryVector<byte> finished_compute_verify(TLS_Handshake_State* state,
                                           Connection_Side side)
   {
   if(state->version == SSL_V3)
      {
      const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 };
      const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 };

      MemoryVector<byte> ssl3_finished;

      if(side == CLIENT)
         state->hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL));
      else
         state->hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL));

      return state->hash.final_ssl3(state->keys.master_secret());
      }
   else
      {
      const byte TLS_CLIENT_LABEL[] = {
         0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69,
         0x73, 0x68, 0x65, 0x64 };

      const byte TLS_SERVER_LABEL[] = {
         0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69,
         0x73, 0x68, 0x65, 0x64 };

      std::auto_ptr<KDF> prf(choose_tls_prf(state->version));

      MemoryVector<byte> input;
      if(side == CLIENT)
         input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
      else
         input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));

      input += state->hash.final(state->version);

      return prf->derive_key(12, state->keys.master_secret(), input);
      }
   }

}

/*
* Create a new Finished message
*/
Finished::Finished(Record_Writer& writer,
                   TLS_Handshake_State* state,
                   Connection_Side side)
   {
   verification_data = finished_compute_verify(state, side);
   send(writer, state->hash);
   }

/*
* Serialize a Finished message
*/
MemoryVector<byte> Finished::serialize() const
   {
   return verification_data;
   }

/*
* Deserialize a Finished message
*/
Finished::Finished(const MemoryRegion<byte>& buf)
   {
   verification_data = buf;
   }

/*
* Verify a Finished message
*/
bool Finished::verify(TLS_Handshake_State* state,
                      Connection_Side side)
   {
   return (verification_data == finished_compute_verify(state, side));
   }

}
<commit_msg>A change to Finished in 687c3c7dccdd2f5e4825bdb60155c7bfba22339f broke SSLv3 handshakes: we need to copy the handshake state when we computed the finished data in the SSLv3 case because we need to add a little bit of data onto the end, but we don't want to include that data with the next computation. This meant that the finished message a client sent us was fine, but the one we sent out had a bad finished value and was rejected.<commit_after>/*
* Finished Message
* (C) 2004-2006,2012 Jack Lloyd
*
* Released under the terms of the Botan license
*/

#include <botan/internal/tls_messages.h>
#include <botan/prf_tls.h>
#include <botan/hmac.h>
#include <botan/sha2_32.h>
#include <memory>

#include <stdio.h>

namespace Botan {

namespace {

KDF* choose_tls_prf(Version_Code version)
   {
   if(version == TLS_V10 || version == TLS_V11)
      return new TLS_PRF;
   else if(version == TLS_V12)
      return new TLS_12_PRF(new HMAC(new SHA_256)); // might depend on ciphersuite
   else
      throw TLS_Exception(PROTOCOL_VERSION,
                          "Unknown version for PRF");
   }

/*
* Compute the verify_data
*/
MemoryVector<byte> finished_compute_verify(TLS_Handshake_State* state,
                                           Connection_Side side)
   {
   if(state->version == SSL_V3)
      {
      const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 };
      const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 };

      TLS_Handshake_Hash hash = state->hash; // don't modify state

      MemoryVector<byte> ssl3_finished;

      if(side == CLIENT)
         hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL));
      else
         hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL));

      return hash.final_ssl3(state->keys.master_secret());
      }
   else
      {
      const byte TLS_CLIENT_LABEL[] = {
         0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69,
         0x73, 0x68, 0x65, 0x64 };

      const byte TLS_SERVER_LABEL[] = {
         0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69,
         0x73, 0x68, 0x65, 0x64 };

      std::auto_ptr<KDF> prf(choose_tls_prf(state->version));

      MemoryVector<byte> input;
      if(side == CLIENT)
         input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
      else
         input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));

      input += state->hash.final(state->version);

      return prf->derive_key(12, state->keys.master_secret(), input);
      }
   }

}

/*
* Create a new Finished message
*/
Finished::Finished(Record_Writer& writer,
                   TLS_Handshake_State* state,
                   Connection_Side side)
   {
   verification_data = finished_compute_verify(state, side);
   send(writer, state->hash);
   }

/*
* Serialize a Finished message
*/
MemoryVector<byte> Finished::serialize() const
   {
   return verification_data;
   }

/*
* Deserialize a Finished message
*/
Finished::Finished(const MemoryRegion<byte>& buf)
   {
   verification_data = buf;
   }

/*
* Verify a Finished message
*/
bool Finished::verify(TLS_Handshake_State* state,
                      Connection_Side side)
   {
   return (verification_data == finished_compute_verify(state, side));
   }

}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include <rm.hpp>

#include <cmdline.hpp>
#include <kdb.hpp>

#include <iostream>

using namespace std;
using namespace kdb;

RemoveCommand::RemoveCommand ()
{
}

int RemoveCommand::execute (Cmdline const & cl)
{
	if (cl.arguments.size () != 1) throw invalid_argument ("1 argument required");

	KeySet conf;
	Key x = cl.createKey (0);

	kdb.get (conf, x);

	KeySet savedKeys;

	if (cl.withoutElektra)
	{
		Key systemElektra ("system/elektra", KEY_END);
		savedKeys = conf.cut (systemElektra);
	}

	if (!cl.recursive)
	{
		Key f = conf.lookup (x, KDB_O_POP);

		if (!f)
		{
			cerr << "Did not find the key" << endl;
			return cl.force ? 0 : 1;
		}
	}
	else
	{
		// do recursive removing
		KeySet ks = conf.cut (x);

		if (ks.size () == 0)
		{
			cerr << "Did not find any key" << endl;
			return cl.force ? 0 : 1;
		}
	}

	conf.append(savedKeys);

	kdb.set (conf, x);

	return 0;
}

RemoveCommand::~RemoveCommand ()
{
}
<commit_msg>reformat-source<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include <rm.hpp>

#include <cmdline.hpp>
#include <kdb.hpp>

#include <iostream>

using namespace std;
using namespace kdb;

RemoveCommand::RemoveCommand ()
{
}

int RemoveCommand::execute (Cmdline const & cl)
{
	if (cl.arguments.size () != 1) throw invalid_argument ("1 argument required");

	KeySet conf;
	Key x = cl.createKey (0);

	kdb.get (conf, x);

	KeySet savedKeys;

	if (cl.withoutElektra)
	{
		Key systemElektra ("system/elektra", KEY_END);
		savedKeys = conf.cut (systemElektra);
	}

	if (!cl.recursive)
	{
		Key f = conf.lookup (x, KDB_O_POP);

		if (!f)
		{
			cerr << "Did not find the key" << endl;
			return cl.force ? 0 : 1;
		}
	}
	else
	{
		// do recursive removing
		KeySet ks = conf.cut (x);

		if (ks.size () == 0)
		{
			cerr << "Did not find any key" << endl;
			return cl.force ? 0 : 1;
		}
	}

	conf.append (savedKeys);

	kdb.set (conf, x);

	return 0;
}

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