<commit_before>// 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.

#ifndef __STOUT_DURATION_HPP__
#define __STOUT_DURATION_HPP__

#include <ctype.h> // For 'isdigit'.

// For 'timeval'.
#ifndef __WINDOWS__
#include <sys/time.h>
#endif // __WINDOWS__

#include <iomanip>
#include <iostream>
#include <limits>
#include <string>

#include "error.hpp"
#include "numify.hpp"
#include "try.hpp"

class Duration
{
public:
  static Try<Duration> parse(const std::string& s)
  {
    // TODO(benh): Support negative durations (i.e., starts with '-').
    size_t index = 0;
    while (index < s.size()) {
      if (isdigit(s[index]) || s[index] == '.') {
        index++;
        continue;
      }

      Try<double> value = numify<double>(s.substr(0, index));

      if (value.isError()) {
        return Error(value.error());
      }

      const std::string unit = s.substr(index);

      if (unit == "ns") {
        return Duration(value.get(), NANOSECONDS);
      } else if (unit == "us") {
        return Duration(value.get(), MICROSECONDS);
      } else if (unit == "ms") {
        return Duration(value.get(), MILLISECONDS);
      } else if (unit == "secs") {
        return Duration(value.get(), SECONDS);
      } else if (unit == "mins") {
        return Duration(value.get(), MINUTES);
      } else if (unit == "hrs") {
        return Duration(value.get(), HOURS);
      } else if (unit == "days") {
        return Duration(value.get(), DAYS);
      } else if (unit == "weeks") {
        return Duration(value.get(), WEEKS);
      } else {
        return Error(
            "Unknown duration unit '" + unit + "'; supported units are"
            " 'ns', 'us', 'ms', 'secs', 'mins', 'hrs', 'days', and 'weeks'");
      }
    }
    return Error("Invalid duration '" + s + "'");
  }

  static Try<Duration> create(double seconds);

  constexpr Duration() : nanos(0) {}

  explicit Duration(const timeval& t)
  {
    nanos = t.tv_sec * SECONDS + t.tv_usec * MICROSECONDS;
  }

  int64_t ns() const   { return nanos; }
  double us() const    { return static_cast<double>(nanos) / MICROSECONDS; }
  double ms() const    { return static_cast<double>(nanos) / MILLISECONDS; }
  double secs() const  { return static_cast<double>(nanos) / SECONDS; }
  double mins() const  { return static_cast<double>(nanos) / MINUTES; }
  double hrs() const   { return static_cast<double>(nanos) / HOURS; }
  double days() const  { return static_cast<double>(nanos) / DAYS; }
  double weeks() const { return static_cast<double>(nanos) / WEEKS; }

  struct timeval timeval() const
  {
    struct timeval t;
    t.tv_sec = secs();
    t.tv_usec = us() - (t.tv_sec * MILLISECONDS);
    return t;
  }

  bool operator<(const Duration& d) const { return nanos < d.nanos; }
  bool operator<=(const Duration& d) const { return nanos <= d.nanos; }
  bool operator>(const Duration& d) const { return nanos > d.nanos; }
  bool operator>=(const Duration& d) const { return nanos >= d.nanos; }
  bool operator==(const Duration& d) const { return nanos == d.nanos; }
  bool operator!=(const Duration& d) const { return nanos != d.nanos; }

  Duration& operator+=(const Duration& that)
  {
    nanos += that.nanos;
    return *this;
  }

  Duration& operator-=(const Duration& that)
  {
    nanos -= that.nanos;
    return *this;
  }

  Duration& operator*=(double multiplier)
  {
    nanos = static_cast<int64_t>(nanos * multiplier);
    return *this;
  }

  Duration& operator/=(double divisor)
  {
    nanos = static_cast<int64_t>(nanos / divisor);
    return *this;
  }

  Duration operator+(const Duration& that) const
  {
    Duration sum = *this;
    sum += that;
    return sum;
  }

  Duration operator-(const Duration& that) const
  {
    Duration diff = *this;
    diff -= that;
    return diff;
  }

  Duration operator*(double multiplier) const
  {
    Duration product = *this;
    product *= multiplier;
    return product;
  }

  Duration operator/(double divisor) const
  {
    Duration quotient = *this;
    quotient /= divisor;
    return quotient;
  }

  // A constant holding the maximum value a Duration can have.
  static constexpr Duration max();
  // A constant holding the minimum (negative) value a Duration can
  // have.
  static constexpr Duration min();
  // A constant holding a Duration of a "zero" value.
  static constexpr Duration zero() { return Duration(); }

protected:
  static constexpr int64_t NANOSECONDS  = 1;
  static constexpr int64_t MICROSECONDS = 1000 * NANOSECONDS;
  static constexpr int64_t MILLISECONDS = 1000 * MICROSECONDS;
  static constexpr int64_t SECONDS      = 1000 * MILLISECONDS;
  static constexpr int64_t MINUTES      = 60 * SECONDS;
  static constexpr int64_t HOURS        = 60 * MINUTES;
  static constexpr int64_t DAYS         = 24 * HOURS;
  static constexpr int64_t WEEKS        = 7 * DAYS;

  // Construct from a (value, unit) pair.
  constexpr Duration(int64_t value, int64_t unit)
    : nanos(value * unit) {}

private:
  // Used only by "parse".
  constexpr Duration(double value, int64_t unit)
    : nanos(static_cast<int64_t>(value * unit)) {}

  int64_t nanos;

  friend std::ostream& operator<<(
    std::ostream& stream,
    const Duration& duration);
};

class Nanoseconds : public Duration
{
public:
  explicit constexpr Nanoseconds(int64_t nanoseconds)
    : Duration(nanoseconds, NANOSECONDS) {}

  constexpr Nanoseconds(const Duration& d) : Duration(d) {}

  double value() const { return static_cast<double>(this->ns()); }

  static std::string units() { return "ns"; }
};

class Microseconds : public Duration
{
public:
  explicit constexpr Microseconds(int64_t microseconds)
    : Duration(microseconds, MICROSECONDS) {}

  constexpr Microseconds(const Duration& d) : Duration(d) {}

  double value() const { return this->us(); }

  static std::string units() { return "us"; }
};

class Milliseconds : public Duration
{
public:
  explicit constexpr Milliseconds(int64_t milliseconds)
    : Duration(milliseconds, MILLISECONDS) {}

  constexpr Milliseconds(const Duration& d) : Duration(d) {}

  double value() const { return this->ms(); }

  static std::string units() { return "ms"; }
};

class Seconds : public Duration
{
public:
  explicit constexpr Seconds(int64_t seconds)
    : Duration(seconds, SECONDS) {}

  constexpr Seconds(const Duration& d) : Duration(d) {}

  double value() const { return this->secs(); }

  static std::string units() { return "secs"; }
};

class Minutes : public Duration
{
public:
  explicit constexpr Minutes(int64_t minutes)
    : Duration(minutes, MINUTES) {}

  constexpr Minutes(const Duration& d) : Duration(d) {}

  double value() const { return this->mins(); }

  static std::string units() { return "mins"; }
};

class Hours : public Duration
{
public:
  explicit constexpr Hours(int64_t hours)
    : Duration(hours, HOURS) {}

  constexpr Hours(const Duration& d) : Duration(d) {}

  double value() const { return this->hrs(); }

  static std::string units() { return "hrs"; }
};

class Days : public Duration
{
public:
  explicit Days(int64_t days)
    : Duration(days, DAYS) {}

  Days(const Duration& d) : Duration(d) {}

  double value() const { return this->days(); }

  static std::string units() { return "days"; }
};

class Weeks : public Duration
{
public:
  explicit constexpr Weeks(int64_t value) : Duration(value, WEEKS) {}

  constexpr Weeks(const Duration& d) : Duration(d) {}

  double value() const { return this->weeks(); }

  static std::string units() { return "weeks"; }
};

inline std::ostream& operator<<(std::ostream& stream, const Duration& duration_)
{
  long precision = stream.precision();

  // Output the duration in full double precision.
  stream.precision(std::numeric_limits<double>::digits10);

  // Parse the duration as the sign and the absolute value.
  Duration duration = duration_;
  if (duration_ < Duration::zero()) {
    stream << "-";

    // Duration::min() may not be representable as a positive Duration.
    if (duration_ == Duration::min()) {
      duration = Duration::max();
    } else {
      duration = duration_ * -1;
    }
  }

  // First determine which bucket of time unit the duration falls into
  // then check whether the duration can be represented as a whole
  // number with this time unit or a smaller one.
  // e.g. 1.42857142857143weeks falls into the 'Weeks' bucket but
  // reads better with a smaller unit: '10days'. So we use 'days'
  // instead of 'weeks' to output the duration.
  int64_t nanoseconds = duration.ns();
  if (duration < Microseconds(1)) {
    stream << duration.ns() << Nanoseconds::units();
  } else if (duration < Milliseconds(1)) {
    if (nanoseconds % Duration::MICROSECONDS != 0) {
      // We can't get a whole number using this unit but we can at
      // one level down.
      stream << duration.ns() << Nanoseconds::units();
    } else {
      stream << duration.us() << Microseconds::units();
    }
  } else if (duration < Seconds(1)) {
    if (nanoseconds % Duration::MILLISECONDS != 0 &&
        nanoseconds % Duration::MICROSECONDS == 0) {
      stream << duration.us() << Microseconds::units();
    } else {
      stream << duration.ms() << Milliseconds::units();
    }
  } else if (duration < Minutes(1)) {
    if (nanoseconds % Duration::SECONDS != 0 &&
        nanoseconds % Duration::MILLISECONDS == 0) {
      stream << duration.ms() << Milliseconds::units();
    } else {
      stream << duration.secs() << Seconds::units();
    }
  } else if (duration < Hours(1)) {
    if (nanoseconds % Duration::MINUTES != 0 &&
        nanoseconds % Duration::SECONDS == 0) {
      stream << duration.secs() << Seconds::units();
    } else {
      stream << duration.mins() << Minutes::units();
    }
  } else if (duration < Days(1)) {
    if (nanoseconds % Duration::HOURS != 0 &&
        nanoseconds % Duration::MINUTES == 0) {
      stream << duration.mins() << Minutes::units();
    } else {
      stream << duration.hrs() << Hours::units();
    }
  } else if (duration < Weeks(1)) {
    if (nanoseconds % Duration::DAYS != 0 &&
        nanoseconds % Duration::HOURS == 0) {
      stream << duration.hrs() << Hours::units();
    } else {
      stream << duration.days() << Days::units();
    }
  } else {
    if (nanoseconds % Duration::WEEKS != 0 &&
        nanoseconds % Duration::DAYS == 0) {
      stream << duration.days() << Days::units();
    } else {
      stream << duration.weeks() << Weeks::units();
    }
  }

  // Return the stream to original formatting state.
  stream.precision(precision);

  return stream;
}

inline Try<Duration> Duration::create(double seconds)
{
  if (seconds * SECONDS > std::numeric_limits<int64_t>::max() ||
      seconds * SECONDS < std::numeric_limits<int64_t>::min()) {
    return Error("Argument out of the range that a Duration can represent due "
                 "to int64_t's size limit");
  }

  return Nanoseconds(static_cast<int64_t>(seconds * SECONDS));
}

inline constexpr Duration Duration::max()
{
  return Nanoseconds(std::numeric_limits<int64_t>::max());
}

inline constexpr Duration Duration::min()
{
  return Nanoseconds(std::numeric_limits<int64_t>::min());
}

#endif // __STOUT_DURATION_HPP__
<commit_msg>Removed an unnecessary call to stream.precision() in Duration.<commit_after>// 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.

#ifndef __STOUT_DURATION_HPP__
#define __STOUT_DURATION_HPP__

#include <ctype.h> // For 'isdigit'.

// For 'timeval'.
#ifndef __WINDOWS__
#include <sys/time.h>
#endif // __WINDOWS__

#include <iomanip>
#include <iostream>
#include <limits>
#include <string>

#include "error.hpp"
#include "numify.hpp"
#include "try.hpp"

class Duration
{
public:
  static Try<Duration> parse(const std::string& s)
  {
    // TODO(benh): Support negative durations (i.e., starts with '-').
    size_t index = 0;
    while (index < s.size()) {
      if (isdigit(s[index]) || s[index] == '.') {
        index++;
        continue;
      }

      Try<double> value = numify<double>(s.substr(0, index));

      if (value.isError()) {
        return Error(value.error());
      }

      const std::string unit = s.substr(index);

      if (unit == "ns") {
        return Duration(value.get(), NANOSECONDS);
      } else if (unit == "us") {
        return Duration(value.get(), MICROSECONDS);
      } else if (unit == "ms") {
        return Duration(value.get(), MILLISECONDS);
      } else if (unit == "secs") {
        return Duration(value.get(), SECONDS);
      } else if (unit == "mins") {
        return Duration(value.get(), MINUTES);
      } else if (unit == "hrs") {
        return Duration(value.get(), HOURS);
      } else if (unit == "days") {
        return Duration(value.get(), DAYS);
      } else if (unit == "weeks") {
        return Duration(value.get(), WEEKS);
      } else {
        return Error(
            "Unknown duration unit '" + unit + "'; supported units are"
            " 'ns', 'us', 'ms', 'secs', 'mins', 'hrs', 'days', and 'weeks'");
      }
    }
    return Error("Invalid duration '" + s + "'");
  }

  static Try<Duration> create(double seconds);

  constexpr Duration() : nanos(0) {}

  explicit Duration(const timeval& t)
  {
    nanos = t.tv_sec * SECONDS + t.tv_usec * MICROSECONDS;
  }

  int64_t ns() const   { return nanos; }
  double us() const    { return static_cast<double>(nanos) / MICROSECONDS; }
  double ms() const    { return static_cast<double>(nanos) / MILLISECONDS; }
  double secs() const  { return static_cast<double>(nanos) / SECONDS; }
  double mins() const  { return static_cast<double>(nanos) / MINUTES; }
  double hrs() const   { return static_cast<double>(nanos) / HOURS; }
  double days() const  { return static_cast<double>(nanos) / DAYS; }
  double weeks() const { return static_cast<double>(nanos) / WEEKS; }

  struct timeval timeval() const
  {
    struct timeval t;
    t.tv_sec = secs();
    t.tv_usec = us() - (t.tv_sec * MILLISECONDS);
    return t;
  }

  bool operator<(const Duration& d) const { return nanos < d.nanos; }
  bool operator<=(const Duration& d) const { return nanos <= d.nanos; }
  bool operator>(const Duration& d) const { return nanos > d.nanos; }
  bool operator>=(const Duration& d) const { return nanos >= d.nanos; }
  bool operator==(const Duration& d) const { return nanos == d.nanos; }
  bool operator!=(const Duration& d) const { return nanos != d.nanos; }

  Duration& operator+=(const Duration& that)
  {
    nanos += that.nanos;
    return *this;
  }

  Duration& operator-=(const Duration& that)
  {
    nanos -= that.nanos;
    return *this;
  }

  Duration& operator*=(double multiplier)
  {
    nanos = static_cast<int64_t>(nanos * multiplier);
    return *this;
  }

  Duration& operator/=(double divisor)
  {
    nanos = static_cast<int64_t>(nanos / divisor);
    return *this;
  }

  Duration operator+(const Duration& that) const
  {
    Duration sum = *this;
    sum += that;
    return sum;
  }

  Duration operator-(const Duration& that) const
  {
    Duration diff = *this;
    diff -= that;
    return diff;
  }

  Duration operator*(double multiplier) const
  {
    Duration product = *this;
    product *= multiplier;
    return product;
  }

  Duration operator/(double divisor) const
  {
    Duration quotient = *this;
    quotient /= divisor;
    return quotient;
  }

  // A constant holding the maximum value a Duration can have.
  static constexpr Duration max();
  // A constant holding the minimum (negative) value a Duration can
  // have.
  static constexpr Duration min();
  // A constant holding a Duration of a "zero" value.
  static constexpr Duration zero() { return Duration(); }

protected:
  static constexpr int64_t NANOSECONDS  = 1;
  static constexpr int64_t MICROSECONDS = 1000 * NANOSECONDS;
  static constexpr int64_t MILLISECONDS = 1000 * MICROSECONDS;
  static constexpr int64_t SECONDS      = 1000 * MILLISECONDS;
  static constexpr int64_t MINUTES      = 60 * SECONDS;
  static constexpr int64_t HOURS        = 60 * MINUTES;
  static constexpr int64_t DAYS         = 24 * HOURS;
  static constexpr int64_t WEEKS        = 7 * DAYS;

  // Construct from a (value, unit) pair.
  constexpr Duration(int64_t value, int64_t unit)
    : nanos(value * unit) {}

private:
  // Used only by "parse".
  constexpr Duration(double value, int64_t unit)
    : nanos(static_cast<int64_t>(value * unit)) {}

  int64_t nanos;

  friend std::ostream& operator<<(
    std::ostream& stream,
    const Duration& duration);
};

class Nanoseconds : public Duration
{
public:
  explicit constexpr Nanoseconds(int64_t nanoseconds)
    : Duration(nanoseconds, NANOSECONDS) {}

  constexpr Nanoseconds(const Duration& d) : Duration(d) {}

  double value() const { return static_cast<double>(this->ns()); }

  static std::string units() { return "ns"; }
};

class Microseconds : public Duration
{
public:
  explicit constexpr Microseconds(int64_t microseconds)
    : Duration(microseconds, MICROSECONDS) {}

  constexpr Microseconds(const Duration& d) : Duration(d) {}

  double value() const { return this->us(); }

  static std::string units() { return "us"; }
};

class Milliseconds : public Duration
{
public:
  explicit constexpr Milliseconds(int64_t milliseconds)
    : Duration(milliseconds, MILLISECONDS) {}

  constexpr Milliseconds(const Duration& d) : Duration(d) {}

  double value() const { return this->ms(); }

  static std::string units() { return "ms"; }
};

class Seconds : public Duration
{
public:
  explicit constexpr Seconds(int64_t seconds)
    : Duration(seconds, SECONDS) {}

  constexpr Seconds(const Duration& d) : Duration(d) {}

  double value() const { return this->secs(); }

  static std::string units() { return "secs"; }
};

class Minutes : public Duration
{
public:
  explicit constexpr Minutes(int64_t minutes)
    : Duration(minutes, MINUTES) {}

  constexpr Minutes(const Duration& d) : Duration(d) {}

  double value() const { return this->mins(); }

  static std::string units() { return "mins"; }
};

class Hours : public Duration
{
public:
  explicit constexpr Hours(int64_t hours)
    : Duration(hours, HOURS) {}

  constexpr Hours(const Duration& d) : Duration(d) {}

  double value() const { return this->hrs(); }

  static std::string units() { return "hrs"; }
};

class Days : public Duration
{
public:
  explicit Days(int64_t days)
    : Duration(days, DAYS) {}

  Days(const Duration& d) : Duration(d) {}

  double value() const { return this->days(); }

  static std::string units() { return "days"; }
};

class Weeks : public Duration
{
public:
  explicit constexpr Weeks(int64_t value) : Duration(value, WEEKS) {}

  constexpr Weeks(const Duration& d) : Duration(d) {}

  double value() const { return this->weeks(); }

  static std::string units() { return "weeks"; }
};

inline std::ostream& operator<<(std::ostream& stream, const Duration& duration_)
{
  // Output the duration in full double precision and save the old precision.
  long precision = stream.precision(std::numeric_limits<double>::digits10);

  // Parse the duration as the sign and the absolute value.
  Duration duration = duration_;
  if (duration_ < Duration::zero()) {
    stream << "-";

    // Duration::min() may not be representable as a positive Duration.
    if (duration_ == Duration::min()) {
      duration = Duration::max();
    } else {
      duration = duration_ * -1;
    }
  }

  // First determine which bucket of time unit the duration falls into
  // then check whether the duration can be represented as a whole
  // number with this time unit or a smaller one.
  // e.g. 1.42857142857143weeks falls into the 'Weeks' bucket but
  // reads better with a smaller unit: '10days'. So we use 'days'
  // instead of 'weeks' to output the duration.
  int64_t nanoseconds = duration.ns();
  if (duration < Microseconds(1)) {
    stream << duration.ns() << Nanoseconds::units();
  } else if (duration < Milliseconds(1)) {
    if (nanoseconds % Duration::MICROSECONDS != 0) {
      // We can't get a whole number using this unit but we can at
      // one level down.
      stream << duration.ns() << Nanoseconds::units();
    } else {
      stream << duration.us() << Microseconds::units();
    }
  } else if (duration < Seconds(1)) {
    if (nanoseconds % Duration::MILLISECONDS != 0 &&
        nanoseconds % Duration::MICROSECONDS == 0) {
      stream << duration.us() << Microseconds::units();
    } else {
      stream << duration.ms() << Milliseconds::units();
    }
  } else if (duration < Minutes(1)) {
    if (nanoseconds % Duration::SECONDS != 0 &&
        nanoseconds % Duration::MILLISECONDS == 0) {
      stream << duration.ms() << Milliseconds::units();
    } else {
      stream << duration.secs() << Seconds::units();
    }
  } else if (duration < Hours(1)) {
    if (nanoseconds % Duration::MINUTES != 0 &&
        nanoseconds % Duration::SECONDS == 0) {
      stream << duration.secs() << Seconds::units();
    } else {
      stream << duration.mins() << Minutes::units();
    }
  } else if (duration < Days(1)) {
    if (nanoseconds % Duration::HOURS != 0 &&
        nanoseconds % Duration::MINUTES == 0) {
      stream << duration.mins() << Minutes::units();
    } else {
      stream << duration.hrs() << Hours::units();
    }
  } else if (duration < Weeks(1)) {
    if (nanoseconds % Duration::DAYS != 0 &&
        nanoseconds % Duration::HOURS == 0) {
      stream << duration.hrs() << Hours::units();
    } else {
      stream << duration.days() << Days::units();
    }
  } else {
    if (nanoseconds % Duration::WEEKS != 0 &&
        nanoseconds % Duration::DAYS == 0) {
      stream << duration.days() << Days::units();
    } else {
      stream << duration.weeks() << Weeks::units();
    }
  }

  // Return the stream to original formatting state.
  stream.precision(precision);

  return stream;
}

inline Try<Duration> Duration::create(double seconds)
{
  if (seconds * SECONDS > std::numeric_limits<int64_t>::max() ||
      seconds * SECONDS < std::numeric_limits<int64_t>::min()) {
    return Error("Argument out of the range that a Duration can represent due "
                 "to int64_t's size limit");
  }

  return Nanoseconds(static_cast<int64_t>(seconds * SECONDS));
}

inline constexpr Duration Duration::max()
{
  return Nanoseconds(std::numeric_limits<int64_t>::max());
}

inline constexpr Duration Duration::min()
{
  return Nanoseconds(std::numeric_limits<int64_t>::min());
}

#endif // __STOUT_DURATION_HPP__
<|endoftext|>


<commit_before>/* OpenSceneGraph example, osgdepthpartion.
*
*  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 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.
*/

#include "DistanceAccumulator.h"
#include <osg/Geode>
#include <osg/Transform>
#include <osg/Projection>
#include <algorithm>
#include <math.h>

/** Function that sees whether one DistancePair should come before another in
    an sorted list. Used to sort the vector of DistancePairs. */
bool precedes(const DistanceAccumulator::DistancePair &a,
              const DistanceAccumulator::DistancePair &b)
{
    // This results in sorting in order of descending far distances
    if(a.second > b.second) return true;
    else return false;
}

/** Computes distance betwen a point and the viewpoint of a matrix */
double distance(const osg::Vec3 &coord, const osg::Matrix& matrix)
{
    return -( coord[0]*matrix(0,2) + coord[1]*matrix(1,2) +
              coord[2]*matrix(2,2) + matrix(3,2) );
}

#define CURRENT_CLASS DistanceAccumulator
CURRENT_CLASS::CURRENT_CLASS()
    : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
      _nearFarRatio(0.0005), _maxDepth(UINT_MAX)
{
    setMatrices(osg::Matrix::identity(), osg::Matrix::identity());
    reset();
}

CURRENT_CLASS::~CURRENT_CLASS() {}

void CURRENT_CLASS::pushLocalFrustum()
{
    osg::Matrix& currMatrix = _viewMatrices.back();

        // Compute the frustum in local space
        osg::Polytope localFrustum;
        localFrustum.setToUnitFrustum(false, false);
        localFrustum.transformProvidingInverse(currMatrix*_projectionMatrices.back());
        _localFrusta.push_back(localFrustum);

        // Compute new bounding box corners
        bbCornerPair corner;
        corner.second = (currMatrix(0,2)<=0?1:0) |
                        (currMatrix(1,2)<=0?2:0) |
                        (currMatrix(2,2)<=0?4:0);
        corner.first = (~corner.second)&7;
        _bbCorners.push_back(corner);
}

void CURRENT_CLASS::pushDistancePair(double zNear, double zFar)
{
    if(zFar > 0.0) // Make sure some of drawable is visible
    {
      // Make sure near plane is in front of viewpoint.
      if(zNear <= 0.0)
      {
        zNear = zFar*_nearFarRatio;
        if(zNear >= 1.0) zNear = 1.0; // 1.0 limit chosen arbitrarily!
      }

      // Add distance pair for current drawable
      _distancePairs.push_back(DistancePair(zNear, zFar));

      // Override the current nearest/farthest planes if necessary
      if(zNear < _limits.first) _limits.first = zNear;
      if(zFar > _limits.second) _limits.second = zFar;
    }
}

/** Return true if the node should be traversed, and false if the bounding sphere
    of the node is small enough to be rendered by one Camera. If the latter
    is true, then store the node's near & far plane distances. */
bool CURRENT_CLASS::shouldContinueTraversal(osg::Node &node)
{
    // Allow traversal to continue if we haven't reached maximum depth.
    bool keepTraversing = (_currentDepth < _maxDepth);

    const osg::BoundingSphere &bs = node.getBound();
    double zNear = 0.0, zFar = 0.0;

    // Make sure bounding sphere is valid and within viewing volume
    if(bs.valid())
    {
      if(!_localFrusta.back().contains(bs)) keepTraversing = false;
      else
      {
        // Compute near and far planes for this node
        zNear = distance(bs._center, _viewMatrices.back());
        zFar = zNear + bs._radius;
        zNear -= bs._radius;

        // If near/far ratio is big enough, then we don't need to keep
        // traversing children of this node.
        if(zNear >= zFar*_nearFarRatio) keepTraversing = false;
      }
    }

    // If traversal should stop, then store this node's (near,far) pair
    if(!keepTraversing) pushDistancePair(zNear, zFar);

    return keepTraversing;
}

void CURRENT_CLASS::apply(osg::Node &node)
{
    if(shouldContinueTraversal(node))
    {
      // Traverse this node
      _currentDepth++;
      traverse(node);
      _currentDepth--;
    }
}

void CURRENT_CLASS::apply(osg::Projection &proj)
{
    if(shouldContinueTraversal(proj))
    {
      // Push the new projection matrix view frustum
      _projectionMatrices.push_back(proj.getMatrix());
      pushLocalFrustum();

      // Traverse the group
      _currentDepth++;
      traverse(proj);
      _currentDepth--;

      // Reload original matrix and frustum
      _localFrusta.pop_back();
      _bbCorners.pop_back();
      _projectionMatrices.pop_back();
    }
}

void CURRENT_CLASS::apply(osg::Transform &transform)
{
    if(shouldContinueTraversal(transform))
    {
      // Compute transform for current node
      osg::Matrix currMatrix = _viewMatrices.back();
      bool pushMatrix = transform.computeLocalToWorldMatrix(currMatrix, this);

      if(pushMatrix)
      {
        // Store the new modelview matrix and view frustum
        _viewMatrices.push_back(currMatrix);
        pushLocalFrustum();
      }

      _currentDepth++;
      traverse(transform);
      _currentDepth--;

      if(pushMatrix)
      {
        // Restore the old modelview matrix and view frustum
        _localFrusta.pop_back();
        _bbCorners.pop_back();
        _viewMatrices.pop_back();
      }
    }
}

void CURRENT_CLASS::apply(osg::Geode &geode)
{
    // Contained drawables will only be individually considered if we are
    // allowed to continue traversing.
    if(shouldContinueTraversal(geode))
    {
      osg::Drawable *drawable;
      double zNear, zFar;

      // Handle each drawable in this geode
      for(unsigned int i = 0; i < geode.getNumDrawables(); i++)
      {
        drawable = geode.getDrawable(i);

        const osg::BoundingBox &bb = drawable->getBound();
        if(bb.valid())
        {
          // Make sure drawable will be visible in the scene
          if(!_localFrusta.back().contains(bb)) continue;

          // Compute near/far distances for current drawable
          zNear = distance(bb.corner(_bbCorners.back().first),
                               _viewMatrices.back());
          zFar = distance(bb.corner(_bbCorners.back().second),
                          _viewMatrices.back());
          if(zNear > zFar) std::swap(zNear, zFar);
          pushDistancePair(zNear, zFar);
        }
      }
    }
}

void CURRENT_CLASS::setMatrices(const osg::Matrix &modelview,
                                const osg::Matrix &projection)
{
    _modelview = modelview;
    _projection = projection;
}

void CURRENT_CLASS::reset()
{
    // Clear vectors & values
    _distancePairs.clear();
    _cameraPairs.clear();
    _limits.first = DBL_MAX;
    _limits.second = 0.0;
    _currentDepth = 0;

    // Initial transform matrix is the modelview matrix
    _viewMatrices.clear();
    _viewMatrices.push_back(_modelview);

    // Set the initial projection matrix
    _projectionMatrices.clear();
    _projectionMatrices.push_back(_projection);

    // Create a frustum without near/far planes, for cull computations
    _localFrusta.clear();
    _bbCorners.clear();
    pushLocalFrustum();
}

void CURRENT_CLASS::computeCameraPairs()
{
    // Nothing in the scene, so no cameras needed
    if(_distancePairs.empty()) return;

    // Entire scene can be handled by just one camera
    if(_limits.first >= _limits.second*_nearFarRatio)
    {
      _cameraPairs.push_back(_limits);
      return;
    }

    PairList::iterator i,j;

    // Sort the list of distance pairs by descending far distance
    std::sort(_distancePairs.begin(), _distancePairs.end(), precedes);

    // Combine overlapping distance pairs. The resulting set of distance
    // pairs (called combined pairs) will not overlap.
    PairList combinedPairs;
    DistancePair currPair = _distancePairs.front();
    for(i = _distancePairs.begin(); i != _distancePairs.end(); i++)
    {
      // Current distance pair does not overlap current combined pair, so
      // save the current combined pair and start a new one.
      if(i->second < 0.99*currPair.first)
      {
        combinedPairs.push_back(currPair);
        currPair = *i;
      }

      // Current distance pair overlaps current combined pair, so expand
      // current combined pair to encompass distance pair.
      else
        currPair.first = std::min(i->first, currPair.first);
    }
    combinedPairs.push_back(currPair); // Add last pair

    // Compute the (near,far) distance pairs for each camera.
    // Each of these distance pairs is called a "view segment".
    double currNearLimit, numSegs, new_ratio;
    double ratio_invlog = 1.0/log(_nearFarRatio);
    unsigned int temp;
    for(i = combinedPairs.begin(); i != combinedPairs.end(); i++)
    {
      currPair = *i; // Save current view segment

      // Compute the fractional number of view segments needed to span
      // the current combined distance pair.
      currNearLimit = currPair.second*_nearFarRatio;
      if(currPair.first >= currNearLimit) numSegs = 1.0;
      else
      {
        numSegs = log(currPair.first/currPair.second)*ratio_invlog;

        // Compute the near plane of the last view segment
        //currNearLimit *= pow(_nearFarRatio, -floor(-numSegs) - 1);
        for(temp = (unsigned int)(-floor(-numSegs)); temp > 1; temp--)
        {
          currNearLimit *= _nearFarRatio;
        }
      }

      // See if the closest view segment can absorb other combined pairs
      for(j = i+1; j != combinedPairs.end(); j++)
      {
        // No other distance pairs can be included
        if(j->first < currNearLimit) break;
      }

      // If we did absorb another combined distance pair, recompute the
      // number of required view segments.
      if(i != j-1)
      {
        i = j-1;
        currPair.first = i->first;
        if(currPair.first >= currPair.second*_nearFarRatio) numSegs = 1.0;
        else numSegs = log(currPair.first/currPair.second)*ratio_invlog;
      }

      /* Compute an integer number of segments by rounding the fractional
         number of segments according to how many segments there are.
         In general, the more segments there are, the more likely that the
         integer number of segments will be rounded down.
         The purpose of this is to try to minimize the number of view segments
         that are used to render any section of the scene without violating
         the specified _nearFarRatio by too much. */
      if(numSegs < 10.0) numSegs = floor(numSegs + 1.0 - 0.1*floor(numSegs));
      else numSegs = floor(numSegs);

      // Compute the near/far ratio that will be used for each view segment
      // in this section of the scene.
      new_ratio = pow(currPair.first/currPair.second, 1.0/numSegs);

      // Add numSegs new view segments to the camera pairs list
      for(temp = (unsigned int)numSegs; temp > 0; temp--)
      {
        currPair.first = currPair.second*new_ratio;
        _cameraPairs.push_back(currPair);
        currPair.second = currPair.first;
      }
    }
}

void CURRENT_CLASS::setNearFarRatio(double ratio)
{
    if(ratio <= 0.0 || ratio >= 1.0) return;
    _nearFarRatio = ratio;
}
#undef CURRENT_CLASS
<commit_msg>From Tim Moore, compile fix for gcc 4.3<commit_after>/* OpenSceneGraph example, osgdepthpartion.
*
*  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 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.
*/

#include "DistanceAccumulator.h"
#include <osg/Geode>
#include <osg/Transform>
#include <osg/Projection>
#include <algorithm>
#include <math.h>
#include <limits.h>

/** Function that sees whether one DistancePair should come before another in
    an sorted list. Used to sort the vector of DistancePairs. */
bool precedes(const DistanceAccumulator::DistancePair &a,
              const DistanceAccumulator::DistancePair &b)
{
    // This results in sorting in order of descending far distances
    if(a.second > b.second) return true;
    else return false;
}

/** Computes distance betwen a point and the viewpoint of a matrix */
double distance(const osg::Vec3 &coord, const osg::Matrix& matrix)
{
    return -( coord[0]*matrix(0,2) + coord[1]*matrix(1,2) +
              coord[2]*matrix(2,2) + matrix(3,2) );
}

#define CURRENT_CLASS DistanceAccumulator
CURRENT_CLASS::CURRENT_CLASS()
    : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
      _nearFarRatio(0.0005), _maxDepth(UINT_MAX)
{
    setMatrices(osg::Matrix::identity(), osg::Matrix::identity());
    reset();
}

CURRENT_CLASS::~CURRENT_CLASS() {}

void CURRENT_CLASS::pushLocalFrustum()
{
    osg::Matrix& currMatrix = _viewMatrices.back();

        // Compute the frustum in local space
        osg::Polytope localFrustum;
        localFrustum.setToUnitFrustum(false, false);
        localFrustum.transformProvidingInverse(currMatrix*_projectionMatrices.back());
        _localFrusta.push_back(localFrustum);

        // Compute new bounding box corners
        bbCornerPair corner;
        corner.second = (currMatrix(0,2)<=0?1:0) |
                        (currMatrix(1,2)<=0?2:0) |
                        (currMatrix(2,2)<=0?4:0);
        corner.first = (~corner.second)&7;
        _bbCorners.push_back(corner);
}

void CURRENT_CLASS::pushDistancePair(double zNear, double zFar)
{
    if(zFar > 0.0) // Make sure some of drawable is visible
    {
      // Make sure near plane is in front of viewpoint.
      if(zNear <= 0.0)
      {
        zNear = zFar*_nearFarRatio;
        if(zNear >= 1.0) zNear = 1.0; // 1.0 limit chosen arbitrarily!
      }

      // Add distance pair for current drawable
      _distancePairs.push_back(DistancePair(zNear, zFar));

      // Override the current nearest/farthest planes if necessary
      if(zNear < _limits.first) _limits.first = zNear;
      if(zFar > _limits.second) _limits.second = zFar;
    }
}

/** Return true if the node should be traversed, and false if the bounding sphere
    of the node is small enough to be rendered by one Camera. If the latter
    is true, then store the node's near & far plane distances. */
bool CURRENT_CLASS::shouldContinueTraversal(osg::Node &node)
{
    // Allow traversal to continue if we haven't reached maximum depth.
    bool keepTraversing = (_currentDepth < _maxDepth);

    const osg::BoundingSphere &bs = node.getBound();
    double zNear = 0.0, zFar = 0.0;

    // Make sure bounding sphere is valid and within viewing volume
    if(bs.valid())
    {
      if(!_localFrusta.back().contains(bs)) keepTraversing = false;
      else
      {
        // Compute near and far planes for this node
        zNear = distance(bs._center, _viewMatrices.back());
        zFar = zNear + bs._radius;
        zNear -= bs._radius;

        // If near/far ratio is big enough, then we don't need to keep
        // traversing children of this node.
        if(zNear >= zFar*_nearFarRatio) keepTraversing = false;
      }
    }

    // If traversal should stop, then store this node's (near,far) pair
    if(!keepTraversing) pushDistancePair(zNear, zFar);

    return keepTraversing;
}

void CURRENT_CLASS::apply(osg::Node &node)
{
    if(shouldContinueTraversal(node))
    {
      // Traverse this node
      _currentDepth++;
      traverse(node);
      _currentDepth--;
    }
}

void CURRENT_CLASS::apply(osg::Projection &proj)
{
    if(shouldContinueTraversal(proj))
    {
      // Push the new projection matrix view frustum
      _projectionMatrices.push_back(proj.getMatrix());
      pushLocalFrustum();

      // Traverse the group
      _currentDepth++;
      traverse(proj);
      _currentDepth--;

      // Reload original matrix and frustum
      _localFrusta.pop_back();
      _bbCorners.pop_back();
      _projectionMatrices.pop_back();
    }
}

void CURRENT_CLASS::apply(osg::Transform &transform)
{
    if(shouldContinueTraversal(transform))
    {
      // Compute transform for current node
      osg::Matrix currMatrix = _viewMatrices.back();
      bool pushMatrix = transform.computeLocalToWorldMatrix(currMatrix, this);

      if(pushMatrix)
      {
        // Store the new modelview matrix and view frustum
        _viewMatrices.push_back(currMatrix);
        pushLocalFrustum();
      }

      _currentDepth++;
      traverse(transform);
      _currentDepth--;

      if(pushMatrix)
      {
        // Restore the old modelview matrix and view frustum
        _localFrusta.pop_back();
        _bbCorners.pop_back();
        _viewMatrices.pop_back();
      }
    }
}

void CURRENT_CLASS::apply(osg::Geode &geode)
{
    // Contained drawables will only be individually considered if we are
    // allowed to continue traversing.
    if(shouldContinueTraversal(geode))
    {
      osg::Drawable *drawable;
      double zNear, zFar;

      // Handle each drawable in this geode
      for(unsigned int i = 0; i < geode.getNumDrawables(); i++)
      {
        drawable = geode.getDrawable(i);

        const osg::BoundingBox &bb = drawable->getBound();
        if(bb.valid())
        {
          // Make sure drawable will be visible in the scene
          if(!_localFrusta.back().contains(bb)) continue;

          // Compute near/far distances for current drawable
          zNear = distance(bb.corner(_bbCorners.back().first),
                               _viewMatrices.back());
          zFar = distance(bb.corner(_bbCorners.back().second),
                          _viewMatrices.back());
          if(zNear > zFar) std::swap(zNear, zFar);
          pushDistancePair(zNear, zFar);
        }
      }
    }
}

void CURRENT_CLASS::setMatrices(const osg::Matrix &modelview,
                                const osg::Matrix &projection)
{
    _modelview = modelview;
    _projection = projection;
}

void CURRENT_CLASS::reset()
{
    // Clear vectors & values
    _distancePairs.clear();
    _cameraPairs.clear();
    _limits.first = DBL_MAX;
    _limits.second = 0.0;
    _currentDepth = 0;

    // Initial transform matrix is the modelview matrix
    _viewMatrices.clear();
    _viewMatrices.push_back(_modelview);

    // Set the initial projection matrix
    _projectionMatrices.clear();
    _projectionMatrices.push_back(_projection);

    // Create a frustum without near/far planes, for cull computations
    _localFrusta.clear();
    _bbCorners.clear();
    pushLocalFrustum();
}

void CURRENT_CLASS::computeCameraPairs()
{
    // Nothing in the scene, so no cameras needed
    if(_distancePairs.empty()) return;

    // Entire scene can be handled by just one camera
    if(_limits.first >= _limits.second*_nearFarRatio)
    {
      _cameraPairs.push_back(_limits);
      return;
    }

    PairList::iterator i,j;

    // Sort the list of distance pairs by descending far distance
    std::sort(_distancePairs.begin(), _distancePairs.end(), precedes);

    // Combine overlapping distance pairs. The resulting set of distance
    // pairs (called combined pairs) will not overlap.
    PairList combinedPairs;
    DistancePair currPair = _distancePairs.front();
    for(i = _distancePairs.begin(); i != _distancePairs.end(); i++)
    {
      // Current distance pair does not overlap current combined pair, so
      // save the current combined pair and start a new one.
      if(i->second < 0.99*currPair.first)
      {
        combinedPairs.push_back(currPair);
        currPair = *i;
      }

      // Current distance pair overlaps current combined pair, so expand
      // current combined pair to encompass distance pair.
      else
        currPair.first = std::min(i->first, currPair.first);
    }
    combinedPairs.push_back(currPair); // Add last pair

    // Compute the (near,far) distance pairs for each camera.
    // Each of these distance pairs is called a "view segment".
    double currNearLimit, numSegs, new_ratio;
    double ratio_invlog = 1.0/log(_nearFarRatio);
    unsigned int temp;
    for(i = combinedPairs.begin(); i != combinedPairs.end(); i++)
    {
      currPair = *i; // Save current view segment

      // Compute the fractional number of view segments needed to span
      // the current combined distance pair.
      currNearLimit = currPair.second*_nearFarRatio;
      if(currPair.first >= currNearLimit) numSegs = 1.0;
      else
      {
        numSegs = log(currPair.first/currPair.second)*ratio_invlog;

        // Compute the near plane of the last view segment
        //currNearLimit *= pow(_nearFarRatio, -floor(-numSegs) - 1);
        for(temp = (unsigned int)(-floor(-numSegs)); temp > 1; temp--)
        {
          currNearLimit *= _nearFarRatio;
        }
      }

      // See if the closest view segment can absorb other combined pairs
      for(j = i+1; j != combinedPairs.end(); j++)
      {
        // No other distance pairs can be included
        if(j->first < currNearLimit) break;
      }

      // If we did absorb another combined distance pair, recompute the
      // number of required view segments.
      if(i != j-1)
      {
        i = j-1;
        currPair.first = i->first;
        if(currPair.first >= currPair.second*_nearFarRatio) numSegs = 1.0;
        else numSegs = log(currPair.first/currPair.second)*ratio_invlog;
      }

      /* Compute an integer number of segments by rounding the fractional
         number of segments according to how many segments there are.
         In general, the more segments there are, the more likely that the
         integer number of segments will be rounded down.
         The purpose of this is to try to minimize the number of view segments
         that are used to render any section of the scene without violating
         the specified _nearFarRatio by too much. */
      if(numSegs < 10.0) numSegs = floor(numSegs + 1.0 - 0.1*floor(numSegs));
      else numSegs = floor(numSegs);

      // Compute the near/far ratio that will be used for each view segment
      // in this section of the scene.
      new_ratio = pow(currPair.first/currPair.second, 1.0/numSegs);

      // Add numSegs new view segments to the camera pairs list
      for(temp = (unsigned int)numSegs; temp > 0; temp--)
      {
        currPair.first = currPair.second*new_ratio;
        _cameraPairs.push_back(currPair);
        currPair.second = currPair.first;
      }
    }
}

void CURRENT_CLASS::setNearFarRatio(double ratio)
{
    if(ratio <= 0.0 || ratio >= 1.0) return;
    _nearFarRatio = ratio;
}
#undef CURRENT_CLASS
<|endoftext|>


<commit_before>// ThreadedAudioDevice.cpp
//
// Base class for all classes which spawn thread to run loop.
//

#include "ThreadedAudioDevice.h"
#include <sys/time.h>
#include <sys/resource.h>	// setpriority()
#include <sys/select.h>
#include <string.h>			// memset()
#include <stdio.h>
#include <assert.h>
#include <errno.h>

#define DEBUG 0

#if DEBUG > 1
#define PRINT0 if (1) printf
#define PRINT1 if (1) printf
#elif DEBUG > 0
#define PRINT0 if (1) printf
#define PRINT1 if (0) printf
#else
#define PRINT0 if (0) printf
#define PRINT1 if (0) printf
#endif

// Uncomment this to make it possible to profile RTcmix code w/ gprof
//#define PROFILE

#ifdef PROFILE
static struct itimerval globalTimerVal;
#endif

ThreadedAudioDevice::ThreadedAudioDevice()
	  : _device(-1), _thread(0), _frameCount(0),
	  _starting(false), _paused(false), _stopping(false), _closing(false)
{
}

ThreadedAudioDevice::~ThreadedAudioDevice()
{
	// This code handles the rare case where the child thread is starting
	// at the same instant that the device is being destroyed.
	PRINT1("~ThreadedAudioDevice\n");
	if (starting() && _thread != 0) {
		waitForThread();
		starting(false);
	}
}

int ThreadedAudioDevice::startThread()
{
	stopping(false);	// Reset.
	if (isPassive())	// Nothing else to do here if passive mode.
		return 0;
	starting(true);
#ifdef PROFILE
	getitimer(ITIMER_PROF, &globalTimerVal);
#endif
	PRINT1("\tThreadedAudioDevice::startThread: starting thread\n");
	int status = pthread_create(&_thread, NULL, _runProcess, this);
	if (status < 0) {
		error("Failed to create thread");
	}
	return status;
}

int ThreadedAudioDevice::doStop()
{
	if (!stopping()) {
		PRINT1("\tThreadedAudioDevice::doStop\n");
		stopping(true);		// signals play thread
		paused(false);
		waitForThread();
		starting(false);
	}
	return 0;
}

int ThreadedAudioDevice::doGetFrameCount() const
{
	return frameCount();
}

// Local method definitions

void ThreadedAudioDevice::waitForThread(int waitMs)
{
	if (!isPassive()) {
		assert(_thread != 0);	// should not get called again!
		PRINT1("ThreadedAudioDevice::waitForThread: waiting for thread to finish\n");
		if (pthread_join(_thread, NULL) == -1) {
			PRINT0("ThreadedAudioDevice::doStop: terminating thread!\n");
			pthread_cancel(_thread);
			_thread = 0;
		}
		PRINT1("\tThreadedAudioDevice::waitForThread: thread done\n");
	}
}

inline void	ThreadedAudioDevice::setFDSet()
{
	fd_set *thisSet = NULL;
#ifdef PREFER_SELECT_ON_WRITE
	if (isRecording() && !isPlaying())
		// Use read fd_set for half-duplex record only.
		thisSet = &_rfdset;
	else if (isPlaying())
		// Use write fd_set for full-duplex and half-duplex play.
		thisSet = &_wfdset;
#else
	if (isRecording())
		// Use read fd_set for for full-duplex and half-duplex record.
		thisSet = &_rfdset;
	else if (isPlaying() && !isRecording())
		// Use write fd_set for half-duplex play only.
		thisSet = &_wfdset;
#endif
	FD_SET(_device, thisSet);
}

void ThreadedAudioDevice::setDevice(int dev)
{
	_device = dev;
	if (_device > 0) {
		FD_ZERO(&_rfdset);
		FD_ZERO(&_wfdset);
		setFDSet();
	}
}

int ThreadedAudioDevice::waitForDevice(unsigned int wTime) {
	int ret;
	unsigned waitSecs = int(wTime / 1000.0);
	unsigned waitUsecs = 1000 * (wTime - unsigned(waitSecs * 1000));
	// Wait wTime msecs for select to return, then bail.
	if (!stopping()) {
		int nfds = _device + 1;
		struct timeval tv;
		tv.tv_sec = waitSecs;
		tv.tv_usec = waitUsecs;
		// If wTime == 0, wait forever by passing NULL as the final arg.
//		if (!isPlaying())
//			printf("select(%d, 0x%x, 0x%x, NULL, 0x%x)...\n",
//					nfds, &_rfdset, &_wfdset, wTime == 0 ?  NULL : &tv);
		int selret = ::select(nfds, &_rfdset, &_wfdset,
							  NULL, wTime == 0 ?  NULL : &tv);
		if (selret <= 0) {
			if (errno != EINTR)
				fprintf(stderr,
						"ThreadedAudioDevice::waitForDevice: select %s\n",
						(selret == 0) ? "timed out" : "returned error");
			ret = -1;
		}
		else {
			setFDSet();
			ret = 0;
		}
	}
	else {
		PRINT1("ThreadedAudioDevice::waitForDevice: stopping == true\n");
		ret = 1;
	}
	return ret;
}

void *ThreadedAudioDevice::_runProcess(void *context)
{
#ifdef PROFILE
	setitimer(ITIMER_PROF, &globalTimerVal, NULL);
	getitimer(ITIMER_PROF, &globalTimerVal);
#endif
	ThreadedAudioDevice *device = (ThreadedAudioDevice *) context;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	int status = pthread_attr_setschedpolicy(&attr, SCHED_RR);
	pthread_attr_destroy(&attr);
	if (status != 0)
	{
		device->error("Failed to set scheduling policy of thread");
		return NULL;
	}
	if (setpriority(PRIO_PROCESS, 0, -20) != 0)
	{
//			perror("ThreadedAudioDevice::startThread: Failed to set priority of thread.");
	}
	device->starting(false);	// Signal that the thread is now running
	device->run();
	return NULL;
}
<commit_msg>Fixed so we actually set the threads scheduling policy.<commit_after>// ThreadedAudioDevice.cpp
//
// Base class for all classes which spawn thread to run loop.
//

#include "ThreadedAudioDevice.h"
#include <sys/time.h>
#include <sys/resource.h>	// setpriority()
#include <sys/select.h>
#include <string.h>			// memset()
#include <stdio.h>
#include <assert.h>
#include <errno.h>

#define DEBUG 0

#if DEBUG > 1
#define PRINT0 if (1) printf
#define PRINT1 if (1) printf
#elif DEBUG > 0
#define PRINT0 if (1) printf
#define PRINT1 if (0) printf
#else
#define PRINT0 if (0) printf
#define PRINT1 if (0) printf
#endif

// Uncomment this to make it possible to profile RTcmix code w/ gprof
//#define PROFILE

#ifdef PROFILE
static struct itimerval globalTimerVal;
#endif

ThreadedAudioDevice::ThreadedAudioDevice()
	  : _device(-1), _thread(0), _frameCount(0),
	  _starting(false), _paused(false), _stopping(false), _closing(false)
{
}

ThreadedAudioDevice::~ThreadedAudioDevice()
{
	// This code handles the rare case where the child thread is starting
	// at the same instant that the device is being destroyed.
	PRINT1("~ThreadedAudioDevice\n");
	if (starting() && _thread != 0) {
		waitForThread();
		starting(false);
	}
}

int ThreadedAudioDevice::startThread()
{
	stopping(false);	// Reset.
	if (isPassive())	// Nothing else to do here if passive mode.
		return 0;
	starting(true);
#ifdef PROFILE
	getitimer(ITIMER_PROF, &globalTimerVal);
#endif
	PRINT1("\tThreadedAudioDevice::startThread: starting thread\n");
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	int status = pthread_attr_setschedpolicy(&attr, SCHED_RR);
	if (status != 0) {
		fprintf(stderr, "startThread: Failed to set scheduling policy\n");
	}
	status = pthread_create(&_thread, &attr, _runProcess, this);
	pthread_attr_destroy(&attr);
	if (status < 0) {
		error("Failed to create thread");
	}
	return status;
}

int ThreadedAudioDevice::doStop()
{
	if (!stopping()) {
		PRINT1("\tThreadedAudioDevice::doStop\n");
		stopping(true);		// signals play thread
		paused(false);
		waitForThread();
		starting(false);
	}
	return 0;
}

int ThreadedAudioDevice::doGetFrameCount() const
{
	return frameCount();
}

// Local method definitions

void ThreadedAudioDevice::waitForThread(int waitMs)
{
	if (!isPassive()) {
		assert(_thread != 0);	// should not get called again!
		PRINT1("ThreadedAudioDevice::waitForThread: waiting for thread to finish\n");
		if (pthread_join(_thread, NULL) == -1) {
			PRINT0("ThreadedAudioDevice::doStop: terminating thread!\n");
			pthread_cancel(_thread);
			_thread = 0;
		}
		PRINT1("\tThreadedAudioDevice::waitForThread: thread done\n");
	}
}

inline void	ThreadedAudioDevice::setFDSet()
{
	fd_set *thisSet = NULL;
#ifdef PREFER_SELECT_ON_WRITE
	if (isRecording() && !isPlaying())
		// Use read fd_set for half-duplex record only.
		thisSet = &_rfdset;
	else if (isPlaying())
		// Use write fd_set for full-duplex and half-duplex play.
		thisSet = &_wfdset;
#else
	if (isRecording())
		// Use read fd_set for for full-duplex and half-duplex record.
		thisSet = &_rfdset;
	else if (isPlaying() && !isRecording())
		// Use write fd_set for half-duplex play only.
		thisSet = &_wfdset;
#endif
	FD_SET(_device, thisSet);
}

void ThreadedAudioDevice::setDevice(int dev)
{
	_device = dev;
	if (_device > 0) {
		FD_ZERO(&_rfdset);
		FD_ZERO(&_wfdset);
		setFDSet();
	}
}

int ThreadedAudioDevice::waitForDevice(unsigned int wTime) {
	int ret;
	unsigned waitSecs = int(wTime / 1000.0);
	unsigned waitUsecs = 1000 * (wTime - unsigned(waitSecs * 1000));
	// Wait wTime msecs for select to return, then bail.
	if (!stopping()) {
		int nfds = _device + 1;
		struct timeval tv;
		tv.tv_sec = waitSecs;
		tv.tv_usec = waitUsecs;
		// If wTime == 0, wait forever by passing NULL as the final arg.
//		if (!isPlaying())
//			printf("select(%d, 0x%x, 0x%x, NULL, 0x%x)...\n",
//					nfds, &_rfdset, &_wfdset, wTime == 0 ?  NULL : &tv);
		int selret = ::select(nfds, &_rfdset, &_wfdset,
							  NULL, wTime == 0 ?  NULL : &tv);
		if (selret <= 0) {
			if (errno != EINTR)
				fprintf(stderr,
						"ThreadedAudioDevice::waitForDevice: select %s\n",
						(selret == 0) ? "timed out" : "returned error");
			ret = -1;
		}
		else {
			setFDSet();
			ret = 0;
		}
	}
	else {
		PRINT1("ThreadedAudioDevice::waitForDevice: stopping == true\n");
		ret = 1;
	}
	return ret;
}

void *ThreadedAudioDevice::_runProcess(void *context)
{
#ifdef PROFILE
	setitimer(ITIMER_PROF, &globalTimerVal, NULL);
	getitimer(ITIMER_PROF, &globalTimerVal);
#endif
	ThreadedAudioDevice *device = (ThreadedAudioDevice *) context;
	if (setpriority(PRIO_PROCESS, 0, -20) != 0)
	{
//			perror("ThreadedAudioDevice::startThread: Failed to set priority of thread.");
	}
	device->starting(false);	// Signal that the thread is now running
	device->run();
	return NULL;
}
<|endoftext|>


<commit_before>// Copyright (C) 1999-2017
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#include <tk.h>

#include "boxannulus.h"
#include "fitsimage.h"

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& s,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = 1;
  annuli_ = new Vector[1];
  annuli_[0] = s;

  strcpy(type_,"boxannulus");
  numHandle = 4;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& inner, const Vector& outer, int num,
		       double ang)
  : BaseBox(p, ctr, ang)
{
  numAnnuli_ = num+1;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = ((outer-inner)/num)*i+inner;

  strcpy(type_,"boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& inner, const Vector& outer, int num,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = num+1;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = ((outer-inner)/num)*i+inner;

  strcpy(type_,"boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       int an, Vector* s,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = an;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = s[i];
  sortAnnuli();

  strcpy(type_, "boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
  doCallBack(CallBack::EDITCB);
}

BoxAnnulus::BoxAnnulus(const BoxAnnulus& a) : BaseBox(a) {}

void BoxAnnulus::editBegin(int h)
{
  if (h<5) {
    switch (h) {
    case 1:
      return;
    case 2:
      annuli_[numAnnuli_-1] = Vector(-annuli_[numAnnuli_-1][0],annuli_[numAnnuli_-1][1]);
      return;
    case 3:
      annuli_[numAnnuli_-1] = -annuli_[numAnnuli_-1];
      return;
    case 4:
      annuli_[numAnnuli_-1] = Vector(annuli_[numAnnuli_-1][0],-annuli_[numAnnuli_-1][1]);
      return;
    }
  }

  doCallBack(CallBack::EDITBEGINCB);
}

void BoxAnnulus::edit(const Vector& v, int h)
{
  Matrix mm = bckMatrix();
  Matrix nn = mm.invert();

  // This sizes about the opposite node
  if (h<5) {
    Vector o = annuli_[numAnnuli_-1];
    Vector n = (annuli_[numAnnuli_-1]/2) - (v*mm);

    // don't go thru opposite node
    if (n[0]!=0 && n[1]!=0) {
      Vector ov = annuli_[numAnnuli_-1]/2 * nn;
      annuli_[numAnnuli_-1] = n;
      Vector nv = annuli_[numAnnuli_-1]/2 * nn;
      center -= nv-ov;

      for (int i=0; i<numAnnuli_-1; i++) {
	annuli_[i][0] *= fabs(n[0]/o[0]);
	annuli_[i][1] *= fabs(n[1]/o[1]);
      }
    }
  }
  else {
    // we must have some length
    double l = (v * mm * 2).length();
    annuli_[h-5] = annuli_[numAnnuli_-1] * l/annuli_[numAnnuli_-1][0];
  }

  updateBBox();
  doCallBack(CallBack::EDITCB);
  doCallBack(CallBack::MOVECB);
}

void BoxAnnulus::editEnd()
{
  for (int i=1; i<numAnnuli_; i++)
    annuli_[i] = annuli_[i].abs();
  sortAnnuli();

  updateBBox();
  doCallBack(CallBack::EDITENDCB);
}

int BoxAnnulus::addAnnuli(const Vector& v)
{
  Matrix mm = bckMatrix();
  double l = (v * mm * 2).length();
  Vector rr = annuli_[numAnnuli_-1] * l/annuli_[numAnnuli_-1][0];

  return insertAnnuli(rr);
}

void BoxAnnulus::analysis(AnalysisTask mm, int which)
{
  switch (mm) {
  case RADIAL:
    if (!analysisRadial_ && which) {
      addCallBack(CallBack::MOVECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITCB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITENDCB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::ROTATECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::UPDATECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::DELETECB, analysisRadialCB_[1],
		  parent->options->cmdName);
    }
    if (analysisRadial_ && !which) {
      deleteCallBack(CallBack::MOVECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::EDITCB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::EDITENDCB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::ROTATECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::UPDATECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::DELETECB, analysisRadialCB_[1]);
    }

    analysisRadial_ = which;
    break;
  case STATS:
    if (!analysisStats_ && which) {
      addCallBack(CallBack::MOVECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITCB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITENDCB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::ROTATECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::UPDATECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::DELETECB, analysisStatsCB_[1],
		  parent->options->cmdName);
    }
    if (analysisStats_ && !which) {
      deleteCallBack(CallBack::MOVECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::EDITCB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::EDITENDCB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::ROTATECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::UPDATECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::DELETECB, analysisStatsCB_[1]);
    }

    analysisStats_ = which;
    break;
  default:
    // na
    break;
  }
}

void BoxAnnulus::analysisRadial(char* xname, char* yname, char* ename,
				Coord::CoordSystem sys)
{
  double* xx;
  double* yy;
  double* ee;

  BBox* bb = new BBox[numAnnuli_];
  Matrix mm = Rotate(angle) * Translate(center);

  for (int ii=0; ii<numAnnuli_; ii++) {
    // during resize, annuli_ can be negative
    Vector vv = annuli_[ii].abs();
    bb[ii] = BBox(-vv * mm);
    bb[ii].bound( vv * mm);
    bb[ii].bound(Vector( vv[0],-vv[1]) * mm);
    bb[ii].bound(Vector(-vv[0], vv[1]) * mm);
  }

  int num = parent->markerAnalysisRadial(this, &xx, &yy, &ee,
					 numAnnuli_-1, annuli_,
					 bb, sys);
  analysisXYEResult(xname, yname, ename, xx, yy, ee, num);
}

void BoxAnnulus::analysisStats(Coord::CoordSystem sys, Coord::SkyFrame sky)
{
  ostringstream str;
  BBox* bb = new BBox[numAnnuli_];
  Matrix mm = Rotate(angle) * Translate(center);

  for (int ii=0; ii<numAnnuli_; ii++) {
    // during resize, annuli_ can be negative
    Vector vv = annuli_[ii].abs();
    bb[ii] = BBox(-vv * mm);
    bb[ii].bound( vv * mm);
    bb[ii].bound(Vector( vv[0],-vv[1]) * mm);
    bb[ii].bound(Vector(-vv[0], vv[1]) * mm);
  }

  parent->markerAnalysisStats(this, str, numAnnuli_-1, bb, sys, sky);
  str << ends;
  Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);
}

// list

void BoxAnnulus::list(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky,
		   Coord::SkyFormat format, int conj, int strip)
{
  FitsImage* ptr = parent->findFits(sys,center);
  listPre(str, sys, sky, ptr, strip, 0);

  switch (sys) {
  case Coord::IMAGE:
  case Coord::PHYSICAL:
  case Coord::DETECTOR:
  case Coord::AMPLIFIER:
    listNonCel(ptr, str, sys);
    break;
  default:
    if (ptr->hasWCSCel(sys)) {
      listRADEC(ptr,center,sys,sky,format);
      double aa = parent->mapAngleFromRef(angle,sys,sky);
      str << "box(" << ra << ',' << dec
	  << setprecision(3) << fixed;
      for (int ii=0; ii<numAnnuli_; ii++) {
	Vector rr = ptr->mapLenFromRef(annuli_[ii],sys,Coord::ARCSEC);
	str << ',' << setunit('"') << rr;
      }
      str.unsetf(ios_base::floatfield);
      str << setprecision(8) << ',' << radToDeg(aa) << ')';
    }
    else
      listNonCel(ptr, str, sys);
  }

  listPost(str, conj, strip);
}

void BoxAnnulus::listNonCel(FitsImage* ptr, ostream& str,
			    Coord::CoordSystem sys)
{
  Vector vv = ptr->mapFromRef(center,sys);
  double aa = parent->mapAngleFromRef(angle,sys);
  str << "box(" << setprecision(8) << vv;
  for (int ii=0; ii<numAnnuli_; ii++) {
    Vector rr = ptr->mapLenFromRef(annuli_[ii],sys);
    str << ',' << rr;
  }
  str << ',' << radToDeg(aa) << ')';
}

void BoxAnnulus::listXML(ostream& str, Coord::CoordSystem sys,
			 Coord::SkyFrame sky, Coord::SkyFormat format)
{
  FitsImage* ptr = parent->findFits(sys,center);

  XMLRowInit();
  XMLRow(XMLSHAPE,type_);

  XMLRowCenter(ptr,sys,sky,format);
  XMLRowRadius(ptr,sys,annuli_,numAnnuli_);
  XMLRowAng(sys,sky);

  XMLRowProps(ptr,sys);
  XMLRowEnd(str);
}

void BoxAnnulus::listPros(ostream& str, Coord::CoordSystem sys,
			  Coord::SkyFrame sky, Coord::SkyFormat format,
			  int strip)
{
  FitsImage* ptr = parent->findFits();

  switch (sys) {
  case Coord::IMAGE:
  case Coord::DETECTOR:
  case Coord::AMPLIFIER:
    sys = Coord::IMAGE;
  case Coord::PHYSICAL:
    {
      Vector vv = ptr->mapFromRef(center,sys);
      for (int ii=0; ii<numAnnuli_; ii++) {
	coord.listProsCoordSystem(str,sys,sky);
	str << "; ";

	Vector rr = ptr->mapLenFromRef(annuli_[ii],Coord::IMAGE);
        str << "box " << setprecision(8) << vv << ' ' << rr << ' '
            << radToDeg(angle);

	if (ii!=0) {
	  Vector r1 = ptr->mapLenFromRef(annuli_[ii-1],Coord::IMAGE);
	  str << " & !box " << vv << ' ' << r1 << ' ' << radToDeg(angle);
	}

	listProsPost(str, strip);
      }
    }
    break;
  default:
    if (ptr->hasWCSCel(sys)) {
      listRADECPros(ptr,center,sys,sky,format);
      switch (format) {
      case Coord::DEGREES:
	for (int ii=0; ii<numAnnuli_; ii++) {
	  coord.listProsCoordSystem(str,sys,sky);
	  str << "; ";

	  Vector rr = ptr->mapLenFromRef(annuli_[ii],sys,Coord::ARCSEC);
	  str << "box " << ra << 'd' << ' ' << dec << 'd' << ' '
	      << setprecision(3) << setunit('"') << fixed << rr << ' ';
	  str.unsetf(ios_base::floatfield);
	  str << setprecision(8) << radToDeg(angle);

	  if (ii!=0) {
	    Vector r1 = ptr->mapLenFromRef(annuli_[ii-1],sys,Coord::ARCSEC);
	    str << " & !box " << ra << 'd' << ' ' << dec << 'd' << ' '
		<< setprecision(3) << setunit('"') << fixed << r1 << ' ';
	    str.unsetf(ios_base::floatfield);
	    str << setprecision(8) << radToDeg(angle);
	  }

	  listProsPost(str, strip);
	}
	break;
      case Coord::SEXAGESIMAL:
	for (int ii=0; ii<numAnnuli_; ii++) {
	  coord.listProsCoordSystem(str,sys,sky);
	  str << "; ";

	  Vector rr = ptr->mapLenFromRef(annuli_[ii],sys,Coord::ARCSEC);
          str << "box " << ra << ' ' << dec << ' '
              << setprecision(3) << setunit('"') << fixed << rr << ' ';
          str.unsetf(ios_base::floatfield);
          str << setprecision(8) << radToDeg(angle);

	  if (ii!=0) {
	    Vector r1 = ptr->mapLenFromRef(annuli_[ii-1],sys,Coord::ARCSEC);
            str << " & !box " << ra << ' ' << dec << ' '
                << setprecision(3) << setunit('"') << fixed << r1 << ' ';
            str.unsetf(ios_base::floatfield);
            str << setprecision(8) << radToDeg(angle);
	  }

	  listProsPost(str, strip);
	}
	break;
      }
    }
  }
}

void BoxAnnulus::listSAOimage(ostream& str, int strip)
{
  FitsImage* ptr = parent->findFits();
  listSAOimagePre(str);

  for (int ii=0; ii<numAnnuli_; ii++) {
    Vector vv = ptr->mapFromRef(center,Coord::IMAGE);
    str << "box(" << setprecision(8) << vv << ','
        << annuli_[ii] << ',' << radToDeg(angle) << ')';

    if (ii!=0)
      str << " & !box(" << setprecision(8) << vv << ','
          << annuli_[ii-1] << ',' << radToDeg(angle) << ')';

    listSAOimagePost(str, strip);
  }
}

<commit_msg>clean up marker code<commit_after>// Copyright (C) 1999-2017
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#include <tk.h>

#include "boxannulus.h"
#include "fitsimage.h"

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& s,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = 1;
  annuli_ = new Vector[1];
  annuli_[0] = s;

  strcpy(type_,"boxannulus");
  numHandle = 4;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& inner, const Vector& outer, int num,
		       double ang)
  : BaseBox(p, ctr, ang)
{
  numAnnuli_ = num+1;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = ((outer-inner)/num)*i+inner;

  strcpy(type_,"boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       const Vector& inner, const Vector& outer, int num,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = num+1;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = ((outer-inner)/num)*i+inner;

  strcpy(type_,"boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
}

BoxAnnulus::BoxAnnulus(Base* p, const Vector& ctr,
		       int an, Vector* s,
		       double ang,
		       const char* clr, int* dsh,
		       int wth, const char* fnt, const char* txt,
		       unsigned short prop, const char* cmt,
		       const List<Tag>& tg, const List<CallBack>& cb)
  : BaseBox(p, ctr, ang, clr, dsh, wth, fnt, txt, prop, cmt, tg, cb)
{
  numAnnuli_ = an;
  annuli_ = new Vector[numAnnuli_];

  for (int i=0; i<numAnnuli_; i++)
    annuli_[i] = s[i];
  sortAnnuli();

  strcpy(type_, "boxannulus");
  numHandle = 4 + numAnnuli_;

  updateBBox();
  doCallBack(CallBack::EDITCB);
}

BoxAnnulus::BoxAnnulus(const BoxAnnulus& a) : BaseBox(a) {}

void BoxAnnulus::editBegin(int h)
{
  if (h<5) {
    switch (h) {
    case 1:
      return;
    case 2:
      annuli_[numAnnuli_-1] = Vector(-annuli_[numAnnuli_-1][0],annuli_[numAnnuli_-1][1]);
      return;
    case 3:
      annuli_[numAnnuli_-1] = -annuli_[numAnnuli_-1];
      return;
    case 4:
      annuli_[numAnnuli_-1] = Vector(annuli_[numAnnuli_-1][0],-annuli_[numAnnuli_-1][1]);
      return;
    }
  }

  doCallBack(CallBack::EDITBEGINCB);
}

void BoxAnnulus::edit(const Vector& v, int h)
{
  Matrix mm = bckMatrix();
  Matrix nn = mm.invert();

  // This sizes about the opposite node
  if (h<5) {
    Vector o = annuli_[numAnnuli_-1];
    Vector n = (annuli_[numAnnuli_-1]/2) - (v*mm);

    // don't go thru opposite node
    if (n[0]!=0 && n[1]!=0) {
      Vector ov = annuli_[numAnnuli_-1]/2 * nn;
      annuli_[numAnnuli_-1] = n;
      Vector nv = annuli_[numAnnuli_-1]/2 * nn;
      center -= nv-ov;

      for (int i=0; i<numAnnuli_-1; i++) {
	annuli_[i][0] *= fabs(n[0]/o[0]);
	annuli_[i][1] *= fabs(n[1]/o[1]);
      }
    }
  }
  else {
    // we must have some length
    double l = (v * mm * 2).length();
    annuli_[h-5] = annuli_[numAnnuli_-1] * l/annuli_[numAnnuli_-1][0];
  }

  updateBBox();
  doCallBack(CallBack::EDITCB);
  doCallBack(CallBack::MOVECB);
}

void BoxAnnulus::editEnd()
{
  for (int i=1; i<numAnnuli_; i++)
    annuli_[i] = annuli_[i].abs();
  sortAnnuli();

  updateBBox();
  doCallBack(CallBack::EDITENDCB);
}

int BoxAnnulus::addAnnuli(const Vector& v)
{
  Matrix mm = bckMatrix();
  double l = (v * mm * 2).length();
  Vector rr = annuli_[numAnnuli_-1] * l/annuli_[numAnnuli_-1][0];

  return insertAnnuli(rr);
}

void BoxAnnulus::analysis(AnalysisTask mm, int which)
{
  switch (mm) {
  case RADIAL:
    if (!analysisRadial_ && which) {
      addCallBack(CallBack::MOVECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITCB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITENDCB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::ROTATECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::UPDATECB, analysisRadialCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::DELETECB, analysisRadialCB_[1],
		  parent->options->cmdName);
    }
    if (analysisRadial_ && !which) {
      deleteCallBack(CallBack::MOVECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::EDITCB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::EDITENDCB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::ROTATECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::UPDATECB, analysisRadialCB_[0]);
      deleteCallBack(CallBack::DELETECB, analysisRadialCB_[1]);
    }

    analysisRadial_ = which;
    break;
  case STATS:
    if (!analysisStats_ && which) {
      addCallBack(CallBack::MOVECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITCB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::EDITENDCB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::ROTATECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::UPDATECB, analysisStatsCB_[0],
		  parent->options->cmdName);
      addCallBack(CallBack::DELETECB, analysisStatsCB_[1],
		  parent->options->cmdName);
    }
    if (analysisStats_ && !which) {
      deleteCallBack(CallBack::MOVECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::EDITCB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::EDITENDCB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::ROTATECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::UPDATECB, analysisStatsCB_[0]);
      deleteCallBack(CallBack::DELETECB, analysisStatsCB_[1]);
    }

    analysisStats_ = which;
    break;
  default:
    // na
    break;
  }
}

void BoxAnnulus::analysisRadial(char* xname, char* yname, char* ename,
				Coord::CoordSystem sys)
{
  double* xx;
  double* yy;
  double* ee;

  BBox* bb = new BBox[numAnnuli_];
  Matrix mm = Rotate(angle) * Translate(center);

  for (int ii=0; ii<numAnnuli_; ii++) {
    // during resize, annuli_ can be negative
    Vector vv = annuli_[ii].abs();
    bb[ii] = BBox(-vv * mm);
    bb[ii].bound( vv * mm);
    bb[ii].bound(Vector( vv[0],-vv[1]) * mm);
    bb[ii].bound(Vector(-vv[0], vv[1]) * mm);
  }

  int num = parent->markerAnalysisRadial(this, &xx, &yy, &ee,
					 numAnnuli_-1, annuli_,
					 bb, sys);
  analysisXYEResult(xname, yname, ename, xx, yy, ee, num);
}

void BoxAnnulus::analysisStats(Coord::CoordSystem sys, Coord::SkyFrame sky)
{
  ostringstream str;
  BBox* bb = new BBox[numAnnuli_];
  Matrix mm = Rotate(angle) * Translate(center);

  for (int ii=0; ii<numAnnuli_; ii++) {
    // during resize, annuli_ can be negative
    Vector vv = annuli_[ii].abs();
    bb[ii] = BBox(-vv * mm);
    bb[ii].bound( vv * mm);
    bb[ii].bound(Vector( vv[0],-vv[1]) * mm);
    bb[ii].bound(Vector(-vv[0], vv[1]) * mm);
  }

  parent->markerAnalysisStats(this, str, numAnnuli_-1, bb, sys, sky);
  str << ends;
  Tcl_AppendResult(parent->interp, str.str().c_str(), NULL);
}

// list

void BoxAnnulus::list(ostream& str, Coord::CoordSystem sys, Coord::SkyFrame sky,
		   Coord::SkyFormat format, int conj, int strip)
{
  FitsImage* ptr = parent->findFits(sys,center);
  listPre(str, sys, sky, ptr, strip, 0);

  switch (sys) {
  case Coord::IMAGE:
  case Coord::PHYSICAL:
  case Coord::DETECTOR:
  case Coord::AMPLIFIER:
    listNonCel(ptr, str, sys);
    break;
  default:
    if (ptr->hasWCSCel(sys)) {
      listRADEC(ptr,center,sys,sky,format);
      double aa = parent->mapAngleFromRef(angle,sys,sky);
      str << "box(" << ra << ',' << dec
	  << setprecision(3) << fixed;
      for (int ii=0; ii<numAnnuli_; ii++) {
	Vector rr = ptr->mapLenFromRef(annuli_[ii],sys,Coord::ARCSEC);
	str << ',' << setunit('"') << rr;
      }
      str.unsetf(ios_base::floatfield);
      str << setprecision(8) << ',' << radToDeg(aa) << ')';
    }
    else
      listNonCel(ptr, str, sys);
  }

  listPost(str, conj, strip);
}

void BoxAnnulus::listNonCel(FitsImage* ptr, ostream& str,
			    Coord::CoordSystem sys)
{
  Vector vv = ptr->mapFromRef(center,sys);
  double aa = parent->mapAngleFromRef(angle,sys);
  str << "box(" << setprecision(8) << vv;
  for (int ii=0; ii<numAnnuli_; ii++) {
    Vector rr = ptr->mapLenFromRef(annuli_[ii],sys);
    str << ',' << rr;
  }
  str << ',' << radToDeg(aa) << ')';
}

void BoxAnnulus::listXML(ostream& str, Coord::CoordSystem sys,
			 Coord::SkyFrame sky, Coord::SkyFormat format)
{
  FitsImage* ptr = parent->findFits(sys,center);

  XMLRowInit();
  XMLRow(XMLSHAPE,type_);

  XMLRowCenter(ptr,sys,sky,format);
  XMLRowRadius(ptr,sys,annuli_,numAnnuli_);
  XMLRowAng(sys,sky);

  XMLRowProps(ptr,sys);
  XMLRowEnd(str);
}

void BoxAnnulus::listPros(ostream& str, Coord::CoordSystem sys,
			  Coord::SkyFrame sky, Coord::SkyFormat format,
			  int strip)
{
  FitsImage* ptr = parent->findFits();

  switch (sys) {
  case Coord::IMAGE:
  case Coord::DETECTOR:
  case Coord::AMPLIFIER:
    sys = Coord::IMAGE;
  case Coord::PHYSICAL:
    {
      Vector vv = ptr->mapFromRef(center,sys);
      for (int ii=0; ii<numAnnuli_; ii++) {
	coord.listProsCoordSystem(str,sys,sky);
	str << "; ";

	Vector rr = ptr->mapLenFromRef(annuli_[ii],Coord::IMAGE);
        str << "box " << setprecision(8) << vv << ' ' << rr << ' '
            << radToDeg(angle);

	if (ii!=0) {
	  Vector r1 = ptr->mapLenFromRef(annuli_[ii-1],Coord::IMAGE);
	  str << " & !box " << vv << ' ' << r1 << ' ' << radToDeg(angle);
	}

	listProsPost(str, strip);
      }
    }
    break;
  default:
    if (ptr->hasWCSCel(sys)) {
      listRADECPros(ptr,center,sys,sky,format);

      for (int ii=0; ii<numAnnuli_; ii++) {
	coord.listProsCoordSystem(str,sys,sky);
	str << "; ";

	Vector rr = ptr->mapLenFromRef(annuli_[ii],sys,Coord::ARCSEC);
	str << "box ";
	switch (format) {
	case Coord::DEGREES:
	  str << ra << 'd' << ' ' << dec << 'd' << ' ';
	    break;
	case Coord::SEXAGESIMAL:
	  str << ra << ' ' << dec << ' ';
	    break;
	}
	str << setprecision(3) << setunit('"') << fixed << rr << ' ';
	str.unsetf(ios_base::floatfield);
	str << setprecision(8) << radToDeg(angle);

	if (ii!=0) {
	  Vector r1 = ptr->mapLenFromRef(annuli_[ii-1],sys,Coord::ARCSEC);
	  str << " & !box ";
	  switch (format) {
	  case Coord::DEGREES:
	    str << ra << 'd' << ' ' << dec << 'd' << ' ';
	      break;
	  case Coord::SEXAGESIMAL:
	    str << ra << ' ' << dec << ' ';
	      break;
	  }
	  str << setprecision(3) << setunit('"') << fixed << r1 << ' ';
	  str.unsetf(ios_base::floatfield);
	  str << setprecision(8) << radToDeg(angle);
	}
	listProsPost(str, strip);
      }
    }
  }
}

void BoxAnnulus::listSAOimage(ostream& str, int strip)
{
  FitsImage* ptr = parent->findFits();
  listSAOimagePre(str);

  for (int ii=0; ii<numAnnuli_; ii++) {
    Vector vv = ptr->mapFromRef(center,Coord::IMAGE);
    str << "box(" << setprecision(8) << vv << ','
        << annuli_[ii] << ',' << radToDeg(angle) << ')';

    if (ii!=0)
      str << " & !box(" << setprecision(8) << vv << ','
          << annuli_[ii-1] << ',' << radToDeg(angle) << ')';

    listSAOimagePost(str, strip);
  }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 *   @author Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tls-cert-verifier-op.h"

#include <TelepathyQt/PendingVariantMap>

#include <KMessageBox>
#include <KLocalizedString>
#include <KDebug>

#include <QSslCertificate>

TlsCertVerifierOp::TlsCertVerifierOp(const Tp::AccountPtr &account,
        const Tp::ConnectionPtr &connection,
        const Tp::ChannelPtr &channel)
    : Tp::PendingOperation(channel),
      m_account(account),
      m_connection(connection),
      m_channel(channel)
{
    QDBusObjectPath certificatePath = qdbus_cast<QDBusObjectPath>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ServerCertificate")));
    m_hostname = qdbus_cast<QString>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".Hostname")));
    m_referenceIdentities = qdbus_cast<QStringList>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ReferenceIdentities")));

    m_authTLSCertificateIface = new Tp::Client::AuthenticationTLSCertificateInterface(
            channel->dbusConnection(), channel->busName(), certificatePath.path());
    connect(m_authTLSCertificateIface->requestAllProperties(),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(gotProperties(Tp::PendingOperation*)));
}

TlsCertVerifierOp::~TlsCertVerifierOp()
{
}

void TlsCertVerifierOp::gotProperties(Tp::PendingOperation *op)
{
    if (op->isError()) {
        kWarning() << "Unable to retrieve properties from AuthenticationTLSCertificate object at" <<
            m_authTLSCertificateIface->path();
        m_channel->requestClose();
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    // everything ok, we can return from handleChannels now
    Q_EMIT ready(this);

    Tp::PendingVariantMap *pvm = qobject_cast<Tp::PendingVariantMap*>(op);
    QVariantMap props = qdbus_cast<QVariantMap>(pvm->result());
    m_certType = qdbus_cast<QString>(props.value(QLatin1String("CertificateType")));
    m_certData = qdbus_cast<CertificateDataList>(props.value(QLatin1String("CertificateChainData")));

    if(m_certType.compare(QLatin1String("x509"), Qt::CaseInsensitive)) {
        kWarning() << "This is not an x509 certificate";
    }

    Q_FOREACH (const QByteArray &data, m_certData) {
        // FIXME How to chech if it is QSsl::Pem or QSsl::Der? QSsl::Der works for kdetalk
        QList<QSslCertificate> certs = QSslCertificate::fromData(data, QSsl::Der);
        Q_FOREACH (const QSslCertificate &cert, certs) {
            kDebug() << cert;
            kDebug() << "Issuer Organization:" << cert.issuerInfo(QSslCertificate::Organization);
            kDebug() << "Issuer Common Name:" << cert.issuerInfo(QSslCertificate::CommonName);
            kDebug() << "Issuer Locality Name:" << cert.issuerInfo(QSslCertificate::LocalityName);
            kDebug() << "Issuer Organizational Unit Name:" << cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Issuer Country Name:" << cert.issuerInfo(QSslCertificate::CountryName);
            kDebug() << "Issuer State or Province Name:" << cert.issuerInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Subject Organization:" << cert.subjectInfo(QSslCertificate::Organization);
            kDebug() << "Subject Common Name:" << cert.subjectInfo(QSslCertificate::CommonName);
            kDebug() << "Subject Locality Name:" << cert.subjectInfo(QSslCertificate::LocalityName);
            kDebug() << "Subject Organizational Unit Name:" << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Subject Country Name:" << cert.subjectInfo(QSslCertificate::CountryName);
            kDebug() << "Subject State Or Province Name:" << cert.subjectInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Effective Date:" << cert.effectiveDate();
            kDebug() << "Expiry Date:" << cert.expiryDate();
            kDebug() << "Public Key:" << cert.publicKey();
            kDebug() << "Serial Number:" << cert.serialNumber();
            kDebug() << "Version" << cert.version();
            kDebug() << "Is Valid?" << cert.isValid();
        }
    }

    //TODO Show a nice dialog
    if (KMessageBox::questionYesNo(0,
                                   i18n("Accept this certificate from %1?
%2
").arg(m_hostname).arg(QString::fromLatin1(m_certData.first().toHex())),
                                   i18n("Untrusted certificate")) == KMessageBox::Yes) {
        // TODO Remember value
        m_authTLSCertificateIface->Accept().waitForFinished();
        setFinished();
    } else {
        Tp::TLSCertificateRejectionList rejections;
        // TODO Add reason
        m_authTLSCertificateIface->Reject(rejections);
        m_channel->requestClose();
        setFinishedWithError(QLatin1String("Cert.Untrusted"),
                             QLatin1String("Certificate rejected by the user"));
    }
}

#include "tls-cert-verifier-op.moc"
<commit_msg>Add missing include<commit_after>/*
 * Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 *   @author Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "tls-cert-verifier-op.h"

#include <TelepathyQt/PendingVariantMap>

#include <KMessageBox>
#include <KLocalizedString>
#include <KDebug>

#include <QSslCertificate>
#include <QSslKey>

TlsCertVerifierOp::TlsCertVerifierOp(const Tp::AccountPtr &account,
        const Tp::ConnectionPtr &connection,
        const Tp::ChannelPtr &channel)
    : Tp::PendingOperation(channel),
      m_account(account),
      m_connection(connection),
      m_channel(channel)
{
    QDBusObjectPath certificatePath = qdbus_cast<QDBusObjectPath>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ServerCertificate")));
    m_hostname = qdbus_cast<QString>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".Hostname")));
    m_referenceIdentities = qdbus_cast<QStringList>(channel->immutableProperties().value(
                TP_QT_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION + QLatin1String(".ReferenceIdentities")));

    m_authTLSCertificateIface = new Tp::Client::AuthenticationTLSCertificateInterface(
            channel->dbusConnection(), channel->busName(), certificatePath.path());
    connect(m_authTLSCertificateIface->requestAllProperties(),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(gotProperties(Tp::PendingOperation*)));
}

TlsCertVerifierOp::~TlsCertVerifierOp()
{
}

void TlsCertVerifierOp::gotProperties(Tp::PendingOperation *op)
{
    if (op->isError()) {
        kWarning() << "Unable to retrieve properties from AuthenticationTLSCertificate object at" <<
            m_authTLSCertificateIface->path();
        m_channel->requestClose();
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    // everything ok, we can return from handleChannels now
    Q_EMIT ready(this);

    Tp::PendingVariantMap *pvm = qobject_cast<Tp::PendingVariantMap*>(op);
    QVariantMap props = qdbus_cast<QVariantMap>(pvm->result());
    m_certType = qdbus_cast<QString>(props.value(QLatin1String("CertificateType")));
    m_certData = qdbus_cast<CertificateDataList>(props.value(QLatin1String("CertificateChainData")));

    if(m_certType.compare(QLatin1String("x509"), Qt::CaseInsensitive)) {
        kWarning() << "This is not an x509 certificate";
    }

    Q_FOREACH (const QByteArray &data, m_certData) {
        // FIXME How to chech if it is QSsl::Pem or QSsl::Der? QSsl::Der works for kdetalk
        QList<QSslCertificate> certs = QSslCertificate::fromData(data, QSsl::Der);
        Q_FOREACH (const QSslCertificate &cert, certs) {
            kDebug() << cert;
            kDebug() << "Issuer Organization:" << cert.issuerInfo(QSslCertificate::Organization);
            kDebug() << "Issuer Common Name:" << cert.issuerInfo(QSslCertificate::CommonName);
            kDebug() << "Issuer Locality Name:" << cert.issuerInfo(QSslCertificate::LocalityName);
            kDebug() << "Issuer Organizational Unit Name:" << cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Issuer Country Name:" << cert.issuerInfo(QSslCertificate::CountryName);
            kDebug() << "Issuer State or Province Name:" << cert.issuerInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Subject Organization:" << cert.subjectInfo(QSslCertificate::Organization);
            kDebug() << "Subject Common Name:" << cert.subjectInfo(QSslCertificate::CommonName);
            kDebug() << "Subject Locality Name:" << cert.subjectInfo(QSslCertificate::LocalityName);
            kDebug() << "Subject Organizational Unit Name:" << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
            kDebug() << "Subject Country Name:" << cert.subjectInfo(QSslCertificate::CountryName);
            kDebug() << "Subject State Or Province Name:" << cert.subjectInfo(QSslCertificate::StateOrProvinceName);
            kDebug() << "Effective Date:" << cert.effectiveDate();
            kDebug() << "Expiry Date:" << cert.expiryDate();
            kDebug() << "Public Key:" << cert.publicKey();
            kDebug() << "Serial Number:" << cert.serialNumber();
            kDebug() << "Version" << cert.version();
            kDebug() << "Is Valid?" << cert.isValid();
        }
    }

    //TODO Show a nice dialog
    if (KMessageBox::questionYesNo(0,
                                   i18n("Accept this certificate from %1?
%2
").arg(m_hostname).arg(QString::fromLatin1(m_certData.first().toHex())),
                                   i18n("Untrusted certificate")) == KMessageBox::Yes) {
        // TODO Remember value
        m_authTLSCertificateIface->Accept().waitForFinished();
        setFinished();
    } else {
        Tp::TLSCertificateRejectionList rejections;
        // TODO Add reason
        m_authTLSCertificateIface->Reject(rejections);
        m_channel->requestClose();
        setFinishedWithError(QLatin1String("Cert.Untrusted"),
                             QLatin1String("Certificate rejected by the user"));
    }
}

#include "tls-cert-verifier-op.moc"
<|endoftext|>