<commit_before>/*
 *  ______                   __  __              __
 * /\  _  \           __    /\ \/\ \            /\ \__
 * \ \ \L\ \  __  __ /\_\   \_\ \ \ \____    ___\ \ ,_\   ____
 *  \ \  __ \/\ \/\ \\/\ \  /'_` \ \ '__`\  / __`\ \ \/  /',__\
 *   \ \ \/\ \ \ \_/ |\ \ \/\ \L\ \ \ \L\ \/\ \L\ \ \ \_/\__, `\
 *    \ \_\ \_\ \___/  \ \_\ \___,_\ \_,__/\ \____/\ \__\/\____/
 *     \/_/\/_/\/__/    \/_/\/__,_ /\/___/  \/___/  \/__/\/___/
 * @copyright Copyright 2017 Avidbots Corp.
 * @name	  laser.cpp
 * @brief   Laser plugin
 * @author  Chunshang Li
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2017, Avidbots Corp.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Avidbots Corp. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

#include <flatland_plugins/laser.h>
#include <flatland_server/collision_filter_registry.h>
#include <flatland_server/exceptions.h>
#include <flatland_server/model_plugin.h>
#include <flatland_server/yaml_reader.h>
#include <geometry_msgs/TransformStamped.h>
#include <pluginlib/class_list_macros.h>
#include <boost/algorithm/string/join.hpp>
#include <cmath>
#include <limits>

using namespace flatland_server;

namespace flatland_plugins {

void Laser::OnInitialize(const YAML::Node &config) {

  float i;
  double b = cos(i);

  ParseParameters(config);

  update_timer_.SetRate(update_rate_);
  scan_publisher_ = nh_.advertise<sensor_msgs::LaserScan>(topic_, 1);

  // construct the body to laser transformation matrix once since it never
  // changes
  double c = cos(origin_.theta);
  double s = sin(origin_.theta);
  double x = origin_.x, y = origin_.y;
  m_body_to_laser_ << c, -s, x, s, c, y, 0, 0, 1;

  int num_laser_points =
      std::lround((max_angle_ - min_angle_) / increment_) + 1;

  // initialize size for the matrix storing the laser points
  m_laser_points_ = Eigen::MatrixXf(3, num_laser_points);
  m_world_laser_points_ = Eigen::MatrixXf(3, num_laser_points);
  v_zero_point_ << 0, 0, 1;

  // pre-calculate the laser points w.r.t to the laser frame, since this never
  // changes
  for (int i = 0; i < num_laser_points; i++) {
    float angle = min_angle_ + i * increment_;

    float x = range_ * cos(angle);
    float y = range_ * sin(angle);

    m_laser_points_(0, i) = x;
    m_laser_points_(1, i) = y;
    m_laser_points_(2, i) = 1;
  }

  // initialize constants in the laser scan message
  laser_scan_.angle_min = min_angle_;
  laser_scan_.angle_max = max_angle_;
  laser_scan_.angle_increment = increment_;
  laser_scan_.time_increment = 0;
  laser_scan_.scan_time = 0;
  laser_scan_.range_min = 0;
  laser_scan_.range_max = range_;
  laser_scan_.ranges.resize(num_laser_points);
  laser_scan_.intensities.resize(0);
  laser_scan_.header.seq = 0;
  laser_scan_.header.frame_id = tf::resolve(model_->GetNameSpace(), frame_id_);

  // Broadcast transform between the body and laser
  tf::Quaternion q;
  q.setRPY(0, 0, origin_.theta);

  static_tf_.header.frame_id =
      tf::resolve(model_->GetNameSpace(), body_->GetName());
  static_tf_.child_frame_id = tf::resolve(model_->GetNameSpace(), frame_id_);
  static_tf_.transform.translation.x = origin_.x;
  static_tf_.transform.translation.y = origin_.y;
  static_tf_.transform.translation.z = 0;
  static_tf_.transform.rotation.x = q.x();
  static_tf_.transform.rotation.y = q.y();
  static_tf_.transform.rotation.z = q.z();
  static_tf_.transform.rotation.w = q.w();
}

void Laser::BeforePhysicsStep(const Timekeeper &timekeeper) {
  // keep the update rate
  if (!update_timer_.CheckUpdate(timekeeper)) {
    return;
  }

  // only compute and publish when the number of subscribers is not zero
  if (scan_publisher_.getNumSubscribers() > 0) {
    ComputeLaserRanges();
    laser_scan_.header.stamp = ros::Time::now();
    scan_publisher_.publish(laser_scan_);
  }

  static_tf_.header.stamp = ros::Time::now();
  tf_broadcaster_.sendTransform(static_tf_);
}

void Laser::ComputeLaserRanges() {
  // get the transformation matrix from the world to the body, and get the
  // world to laser frame transformation matrix by multiplying the world to body
  // and body to laser
  const b2Transform &t = body_->GetPhysicsBody()->GetTransform();
  m_world_to_body_ << t.q.c, -t.q.s, t.p.x, t.q.s, t.q.c, t.p.y, 0, 0, 1;
  m_world_to_laser_ = m_world_to_body_ * m_body_to_laser_;

  // Get the laser points in the world frame by multiplying the laser points in
  // the laser frame to the transformation matrix from world to laser frame
  m_world_laser_points_ = m_world_to_laser_ * m_laser_points_;
  // Get the (0, 0) point in the laser frame
  v_world_laser_origin_ = m_world_to_laser_ * v_zero_point_;

  // Conver to Box2D data types
  b2Vec2 laser_point;
  b2Vec2 laser_origin_point(v_world_laser_origin_(0), v_world_laser_origin_(1));

  // loop through the laser points and call the Box2D world raycast
  for (int i = 0; i < laser_scan_.ranges.size(); ++i) {
    laser_point.x = m_world_laser_points_(0, i);
    laser_point.y = m_world_laser_points_(1, i);

    did_hit_ = false;

    model_->GetPhysicsWorld()->RayCast(this, laser_origin_point, laser_point);

    if (!did_hit_) {
      laser_scan_.ranges[i] = NAN;
    } else {
      laser_scan_.ranges[i] = fraction_ * range_;
    }
  }
}

float Laser::ReportFixture(b2Fixture *fixture, const b2Vec2 &point,
                           const b2Vec2 &normal, float fraction) {
  // only register hit in the specified layers
  if (!(fixture->GetFilterData().categoryBits & layers_bits_)) {
    return -1.0f;  // return -1 to ignore this hit
  }

  did_hit_ = true;
  fraction_ = fraction;

  return fraction;
}

void Laser::ParseParameters(const YAML::Node &config) {
  YamlReader reader(config);
  std::string body_name = reader.Get<std::string>("body");
  topic_ = reader.Get<std::string>("topic", "scan");
  frame_id_ = reader.Get<std::string>("frame", name_);
  update_rate_ = reader.Get<double>("update_rate",
                                    std::numeric_limits<double>::infinity());
  origin_ = reader.GetPose("origin", Pose(0, 0, 0));
  range_ = reader.Get<double>("range");
  std::vector<std::string> layers =
      reader.GetList<std::string>("layers", {"all"}, -1, -1);

  YamlReader angle_reader = reader.Subnode("angle", YamlReader::MAP);
  min_angle_ = angle_reader.Get<double>("min");
  max_angle_ = angle_reader.Get<double>("max");
  increment_ = angle_reader.Get<double>("increment");

  angle_reader.EnsureAccessedAllKeys();
  reader.EnsureAccessedAllKeys();

  if (max_angle_ < min_angle_) {
    throw YAMLException("Invalid \"angle\" params, must have max > min");
  }

  body_ = model_->GetBody(body_name);
  if (!body_) {
    throw YAMLException("Cannot find body with name " + body_name);
  }

  std::vector<std::string> invalid_layers;
  layers_bits_ = model_->GetCfr()->GetCategoryBits(layers, &invalid_layers);
  if (!invalid_layers.empty()) {
    throw YAMLException("Cannot find layer(s): {" +
                        boost::algorithm::join(invalid_layers, ",") + "}");
  }

  ROS_DEBUG_NAMED("LaserPlugin",
                  "Laser %s params: topic(%s) body(%s, %p) origin(%f,%f,%f) "
                  "frame_id(%s) update_rate(%f) range(%f) angle_min(%f) "
                  "angle_max(%f) angle_increment(%f) layers(0x%u {%s})",
                  name_.c_str(), topic_.c_str(), body_name.c_str(), body_,
                  origin_.x, origin_.y, origin_.theta, frame_id_.c_str(),
                  update_rate_, range_, min_angle_, max_angle_, increment_,
                  layers_bits_, boost::algorithm::join(layers, ",").c_str());
}
};

PLUGINLIB_EXPORT_CLASS(flatland_plugins::Laser, flatland_server::ModelPlugin)<commit_msg>clang format<commit_after>/*
 *  ______                   __  __              __
 * /\  _  \           __    /\ \/\ \            /\ \__
 * \ \ \L\ \  __  __ /\_\   \_\ \ \ \____    ___\ \ ,_\   ____
 *  \ \  __ \/\ \/\ \\/\ \  /'_` \ \ '__`\  / __`\ \ \/  /',__\
 *   \ \ \/\ \ \ \_/ |\ \ \/\ \L\ \ \ \L\ \/\ \L\ \ \ \_/\__, `\
 *    \ \_\ \_\ \___/  \ \_\ \___,_\ \_,__/\ \____/\ \__\/\____/
 *     \/_/\/_/\/__/    \/_/\/__,_ /\/___/  \/___/  \/__/\/___/
 * @copyright Copyright 2017 Avidbots Corp.
 * @name	  laser.cpp
 * @brief   Laser plugin
 * @author  Chunshang Li
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2017, Avidbots Corp.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Avidbots Corp. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

#include <flatland_plugins/laser.h>
#include <flatland_server/collision_filter_registry.h>
#include <flatland_server/exceptions.h>
#include <flatland_server/model_plugin.h>
#include <flatland_server/yaml_reader.h>
#include <geometry_msgs/TransformStamped.h>
#include <pluginlib/class_list_macros.h>
#include <boost/algorithm/string/join.hpp>
#include <cmath>
#include <limits>

using namespace flatland_server;

namespace flatland_plugins {

void Laser::OnInitialize(const YAML::Node &config) {
  float i;
  double b = cos(i);

  ParseParameters(config);

  update_timer_.SetRate(update_rate_);
  scan_publisher_ = nh_.advertise<sensor_msgs::LaserScan>(topic_, 1);

  // construct the body to laser transformation matrix once since it never
  // changes
  double c = cos(origin_.theta);
  double s = sin(origin_.theta);
  double x = origin_.x, y = origin_.y;
  m_body_to_laser_ << c, -s, x, s, c, y, 0, 0, 1;

  int num_laser_points =
      std::lround((max_angle_ - min_angle_) / increment_) + 1;

  // initialize size for the matrix storing the laser points
  m_laser_points_ = Eigen::MatrixXf(3, num_laser_points);
  m_world_laser_points_ = Eigen::MatrixXf(3, num_laser_points);
  v_zero_point_ << 0, 0, 1;

  // pre-calculate the laser points w.r.t to the laser frame, since this never
  // changes
  for (int i = 0; i < num_laser_points; i++) {
    float angle = min_angle_ + i * increment_;

    float x = range_ * cos(angle);
    float y = range_ * sin(angle);

    m_laser_points_(0, i) = x;
    m_laser_points_(1, i) = y;
    m_laser_points_(2, i) = 1;
  }

  // initialize constants in the laser scan message
  laser_scan_.angle_min = min_angle_;
  laser_scan_.angle_max = max_angle_;
  laser_scan_.angle_increment = increment_;
  laser_scan_.time_increment = 0;
  laser_scan_.scan_time = 0;
  laser_scan_.range_min = 0;
  laser_scan_.range_max = range_;
  laser_scan_.ranges.resize(num_laser_points);
  laser_scan_.intensities.resize(0);
  laser_scan_.header.seq = 0;
  laser_scan_.header.frame_id = tf::resolve(model_->GetNameSpace(), frame_id_);

  // Broadcast transform between the body and laser
  tf::Quaternion q;
  q.setRPY(0, 0, origin_.theta);

  static_tf_.header.frame_id =
      tf::resolve(model_->GetNameSpace(), body_->GetName());
  static_tf_.child_frame_id = tf::resolve(model_->GetNameSpace(), frame_id_);
  static_tf_.transform.translation.x = origin_.x;
  static_tf_.transform.translation.y = origin_.y;
  static_tf_.transform.translation.z = 0;
  static_tf_.transform.rotation.x = q.x();
  static_tf_.transform.rotation.y = q.y();
  static_tf_.transform.rotation.z = q.z();
  static_tf_.transform.rotation.w = q.w();
}

void Laser::BeforePhysicsStep(const Timekeeper &timekeeper) {
  // keep the update rate
  if (!update_timer_.CheckUpdate(timekeeper)) {
    return;
  }

  // only compute and publish when the number of subscribers is not zero
  if (scan_publisher_.getNumSubscribers() > 0) {
    ComputeLaserRanges();
    laser_scan_.header.stamp = ros::Time::now();
    scan_publisher_.publish(laser_scan_);
  }

  static_tf_.header.stamp = ros::Time::now();
  tf_broadcaster_.sendTransform(static_tf_);
}

void Laser::ComputeLaserRanges() {
  // get the transformation matrix from the world to the body, and get the
  // world to laser frame transformation matrix by multiplying the world to body
  // and body to laser
  const b2Transform &t = body_->GetPhysicsBody()->GetTransform();
  m_world_to_body_ << t.q.c, -t.q.s, t.p.x, t.q.s, t.q.c, t.p.y, 0, 0, 1;
  m_world_to_laser_ = m_world_to_body_ * m_body_to_laser_;

  // Get the laser points in the world frame by multiplying the laser points in
  // the laser frame to the transformation matrix from world to laser frame
  m_world_laser_points_ = m_world_to_laser_ * m_laser_points_;
  // Get the (0, 0) point in the laser frame
  v_world_laser_origin_ = m_world_to_laser_ * v_zero_point_;

  // Conver to Box2D data types
  b2Vec2 laser_point;
  b2Vec2 laser_origin_point(v_world_laser_origin_(0), v_world_laser_origin_(1));

  // loop through the laser points and call the Box2D world raycast
  for (int i = 0; i < laser_scan_.ranges.size(); ++i) {
    laser_point.x = m_world_laser_points_(0, i);
    laser_point.y = m_world_laser_points_(1, i);

    did_hit_ = false;

    model_->GetPhysicsWorld()->RayCast(this, laser_origin_point, laser_point);

    if (!did_hit_) {
      laser_scan_.ranges[i] = NAN;
    } else {
      laser_scan_.ranges[i] = fraction_ * range_;
    }
  }
}

float Laser::ReportFixture(b2Fixture *fixture, const b2Vec2 &point,
                           const b2Vec2 &normal, float fraction) {
  // only register hit in the specified layers
  if (!(fixture->GetFilterData().categoryBits & layers_bits_)) {
    return -1.0f;  // return -1 to ignore this hit
  }

  did_hit_ = true;
  fraction_ = fraction;

  return fraction;
}

void Laser::ParseParameters(const YAML::Node &config) {
  YamlReader reader(config);
  std::string body_name = reader.Get<std::string>("body");
  topic_ = reader.Get<std::string>("topic", "scan");
  frame_id_ = reader.Get<std::string>("frame", name_);
  update_rate_ = reader.Get<double>("update_rate",
                                    std::numeric_limits<double>::infinity());
  origin_ = reader.GetPose("origin", Pose(0, 0, 0));
  range_ = reader.Get<double>("range");
  std::vector<std::string> layers =
      reader.GetList<std::string>("layers", {"all"}, -1, -1);

  YamlReader angle_reader = reader.Subnode("angle", YamlReader::MAP);
  min_angle_ = angle_reader.Get<double>("min");
  max_angle_ = angle_reader.Get<double>("max");
  increment_ = angle_reader.Get<double>("increment");

  angle_reader.EnsureAccessedAllKeys();
  reader.EnsureAccessedAllKeys();

  if (max_angle_ < min_angle_) {
    throw YAMLException("Invalid \"angle\" params, must have max > min");
  }

  body_ = model_->GetBody(body_name);
  if (!body_) {
    throw YAMLException("Cannot find body with name " + body_name);
  }

  std::vector<std::string> invalid_layers;
  layers_bits_ = model_->GetCfr()->GetCategoryBits(layers, &invalid_layers);
  if (!invalid_layers.empty()) {
    throw YAMLException("Cannot find layer(s): {" +
                        boost::algorithm::join(invalid_layers, ",") + "}");
  }

  ROS_DEBUG_NAMED("LaserPlugin",
                  "Laser %s params: topic(%s) body(%s, %p) origin(%f,%f,%f) "
                  "frame_id(%s) update_rate(%f) range(%f) angle_min(%f) "
                  "angle_max(%f) angle_increment(%f) layers(0x%u {%s})",
                  name_.c_str(), topic_.c_str(), body_name.c_str(), body_,
                  origin_.x, origin_.y, origin_.theta, frame_id_.c_str(),
                  update_rate_, range_, min_angle_, max_angle_, increment_,
                  layers_bits_, boost::algorithm::join(layers, ",").c_str());
}
};

PLUGINLIB_EXPORT_CLASS(flatland_plugins::Laser, flatland_server::ModelPlugin)<|endoftext|>


<commit_before># include <cstdlib> // std :: rand ()
# include <vector> // std :: vector <>
# include <list> // std :: list <>
# include <iostream> // std :: cout
# include <iterator> // std :: ostream_iterator <>
# include <algorithm> // std :: reverse , std :: generate
# include <set>
#include <map>

int main ()
{

	std::list <unsigned int> l1(100);
	//Liste mit random-Zahlen füllen
	for (auto& l : l1){
		l = std::rand() % 101;
	}
	// std::copy(std::begin(l1), std::end(l1),
	// 	std::ostream_iterator<int>(std::cout, "\n"));

	std::vector<unsigned int> v1(l1.size());
	//Inhalt der Liste in Vektor kopieren
	std::copy(std::begin(l1), std::end(l1), std::begin(v1));
	std::copy(std::begin(v1), std::end(v1),
		std::ostream_iterator<int>(std::cout, "\n"));

	std::set<int> s1;
	//Inhalt des Vektors in set sortieren (doppelte werden nur 1x einsortiert)
	for(auto& i : v1){
		s1.insert(i);
	}
	std::copy(std::begin(s1), std::end(s1),
	//set ausgeben
		std::ostream_iterator<int>(std::cout, "\n"));

	std::cout << "In der Liste stehen " << s1.size() << " verschiedene Zahlen. \n";

	std::cout << "Diese Zahlen zwischen 0 und 100 fehlen: \n";

	for (int j = 0; j <= 100; ++j){
		//alle Zahlen zw 1 u 100 finden, die nicht im set stehen.
		if(s1.find(j) == s1.end()){
			std::cout << j << "\n";
		}
	}

	std::map<int, int> map1;
	/* mit map, weil man bei map der jeweiligen Zahl (key) einen Wert (value)
	*zuweisen und diesen entsprechend erhöhen kann, wenn die Zahl erneut
	*gefunden wird. Map ist ein assoziativer Container. */
	int i{0};
	int c;
	while(i<v1.size()){
		c = v1[i];
		++map1[c];
		/*Jede Zahl, die in v1 gefunden wird, wird mit Schlüssel 0 hinzugefügt
		*und dann durch ++ um 1 erhöht. Wird sie nochmal gefunden, wird der
		*Schlüssel nochmal um 1 erhöht */
		++i;
	}

	typedef std::map<int,int>::const_iterator Iter;
	//Ausgabe der map als key : value
	for(Iter p = map1.begin(); p!= map1.end(); ++p){
		std::cout << p -> first << " : " << p -> second << '\n';
	}

	return 0;
}
<commit_msg>Add 3.4 Map<commit_after># include <cstdlib> // std :: rand ()
# include <vector> // std :: vector <>
# include <list> // std :: list <>
# include <iostream> // std :: cout
# include <iterator> // std :: ostream_iterator <>
# include <algorithm> // std :: reverse , std :: generate
# include <set>
# include <map>

int main ()
{

	std::list <unsigned int> l1(100);
	//Liste mit random-Zahlen füllen
	for (auto& l : l1){
		l = std::rand() % 101;
	}
	// std::copy(std::begin(l1), std::end(l1),
	// 	std::ostream_iterator<int>(std::cout, "\n"));

	std::vector<unsigned int> v1(l1.size());
	//Inhalt der Liste in Vektor kopieren
	std::copy(std::begin(l1), std::end(l1), std::begin(v1));
	std::copy(std::begin(v1), std::end(v1),
		std::ostream_iterator<int>(std::cout, "\n"));

	std::set<int> s1;
	//Inhalt des Vektors in set sortieren (doppelte werden nur 1x einsortiert)
	for(auto& i : v1){
		s1.insert(i);
	}
	std::copy(std::begin(s1), std::end(s1),
	//set ausgeben
		std::ostream_iterator<int>(std::cout, "\n"));

	std::cout << "In der Liste stehen " << s1.size() << " verschiedene Zahlen. \n";

	std::cout << "Diese Zahlen zwischen 0 und 100 fehlen: \n";

	for (int j = 0; j <= 100; ++j){
		//alle Zahlen zw 1 u 100 finden, die nicht im set stehen.
		if(s1.find(j) == s1.end()){
			std::cout << j << "\n";
		}
	}

	std::map<int, int> map1;
	/* mit map, weil man bei map der jeweiligen Zahl (key) einen Wert (value)
	*zuweisen und diesen entsprechend erhöhen kann, wenn die Zahl erneut
	*gefunden wird. Map ist ein assoziativer Container. */
	int i{0};
	int c;
	while(i<v1.size()){
		c = v1[i];
		++map1[c];
		/*Jede Zahl, die in v1 gefunden wird, wird mit Schlüssel 0 hinzugefügt
		*und dann durch ++ um 1 erhöht. Wird sie nochmal gefunden, wird der
		*Schlüssel nochmal um 1 erhöht */
		++i;
	}

	typedef std::map<int,int>::const_iterator Iter;
	//Ausgabe der map als key : value
	for(Iter p = map1.begin(); p!= map1.end(); ++p){
		std::cout << p -> first << " : " << p -> second << '\n';
	}

	return 0;
}
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 * $Log$
 * Revision 1.43  2004/07/27 16:35:46  strk
 * Geometry::getEnvelopeInternal() changed to return a const Envelope *.
 * This should reduce object copies as once computed the envelope of a
 * geometry remains the same.
 *
 * Revision 1.42  2004/07/22 07:04:49  strk
 * Documented missing geometry functions.
 *
 * Revision 1.41  2004/07/13 08:33:52  strk
 * Added missing virtual destructor to virtual classes.
 * Fixed implicit unsigned int -> int casts
 *
 * Revision 1.40  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.39  2004/07/06 17:58:22  strk
 * Removed deprecated Geometry constructors based on PrecisionModel and
 * SRID specification. Removed SimpleGeometryPrecisionReducer capability
 * of changing Geometry's factory. Reverted Geometry::factory member
 * to be a reference to external factory.
 *
 * Revision 1.38  2004/07/05 10:50:20  strk
 * deep-dopy construction taken out of Geometry and implemented only
 * in GeometryFactory.
 * Deep-copy geometry construction takes care of cleaning up copies
 * on exception.
 * Implemented clone() method for CoordinateSequence
 * Changed createMultiPoint(CoordinateSequence) signature to reflect
 * copy semantic (by-ref instead of by-pointer).
 * Cleaned up documentation.
 *
 * Revision 1.37  2004/07/02 13:28:26  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.36  2004/07/01 14:12:44  strk
 *
 * Geometry constructors come now in two flavors:
 * 	- deep-copy args (pass-by-reference)
 * 	- take-ownership of args (pass-by-pointer)
 * Same functionality is available through GeometryFactory,
 * including buildGeometry().
 *
 * Revision 1.35  2004/06/28 21:58:24  strk
 * Constructors speedup.
 *
 * Revision 1.34  2004/06/28 21:11:43  strk
 * Moved getGeometryTypeId() definitions from geom.h to each geometry module.
 * Added holes argument check in Polygon.cpp.
 *
 * Revision 1.33  2004/06/15 20:30:47  strk
 * updated to respect deep-copy GeometryCollection interface
 *
 * Revision 1.32  2004/04/20 13:24:15  strk
 * More leaks removed.
 *
 * Revision 1.31  2004/04/20 08:52:01  strk
 * GeometryFactory and Geometry const correctness.
 * Memory leaks removed from SimpleGeometryPrecisionReducer
 * and GeometryFactory.
 *
 * Revision 1.30  2004/04/01 10:44:33  ybychkov
 * All "geom" classes from JTS 1.3 upgraded to JTS 1.4
 *
 * Revision 1.29  2004/03/31 07:50:37  ybychkov
 * "geom" partially upgraded to JTS 1.4
 *
 * Revision 1.28  2004/02/27 17:43:45  strk
 * memory leak fix in Polygon::getArea() - reported by 'Manuel  Prieto Villegas' <mprieto@dap.es>
 *
 * Revision 1.27  2003/11/07 01:23:42  pramsey
 * Add standard CVS headers licence notices and copyrights to all cpp and h
 * files.
 *
 * Revision 1.26  2003/10/31 16:36:04  strk
 * Re-introduced clone() method. Copy constructor could not really
 * replace it.
 *
 * Revision 1.25  2003/10/17 05:51:21  ybychkov
 * Fixed a small memory leak.
 *
 * Revision 1.24  2003/10/16 08:50:00  strk
 * Memory leak fixes. Improved performance by mean of more calls to
 * new getCoordinatesRO() when applicable.
 *
 **********************************************************************/

#include <geos/geom.h>
#include <typeinfo>
#include <geos/geosAlgorithm.h>

namespace geos {

Polygon::Polygon(const Polygon &p): Geometry(p.getFactory()){
	shell=new LinearRing(*p.shell);
	holes=new vector<Geometry *>();
	for(int i=0;i<(int)p.holes->size();i++) {
		LinearRing *h=new LinearRing(* (LinearRing*)(*p.holes)[i]);
		holes->push_back(h);
	}
}

/*
* Constructs a Polygon with the given exterior
* and interior boundaries.
*
* @param  shell     the outer boundary of the new Polygon,
*                   or null or an empty
*                   LinearRing if the empty geometry
*                   is to be created.
*
* @param  holes     the LinearRings defining the inner
*                   boundaries of the new Polygon, or
*                   null or empty LinearRings
*                   if the empty  geometry is to be created.
*
* Polygon will take ownership of Shell and Holes LinearRings
*
*/
Polygon::Polygon(LinearRing *newShell, vector<Geometry *> *newHoles, const GeometryFactory *newFactory): Geometry(newFactory)
{
	if (newShell==NULL) {
		shell=getFactory()->createLinearRing(NULL);
	}
	else
	{
		if (newShell->isEmpty() && hasNonEmptyElements(newHoles)) {
			delete newShell;
			delete newHoles;
			throw new IllegalArgumentException("shell is empty but holes are not");
		}
		shell=newShell;
	}

	if (newHoles==NULL)
	{
		holes=new vector<Geometry *>();
	}
	else
	{
		if (hasNullElements(newHoles)) {
			delete newShell;
			delete newHoles;
			throw new IllegalArgumentException("holes must not contain null elements");
		}
		for (unsigned int i=0; i<newHoles->size(); i++)
			if ( (*newHoles)[i]->getGeometryTypeId() != GEOS_LINEARRING)
				throw new IllegalArgumentException("holes must be LinearRings");
		holes=newHoles;
	}
}

Geometry *Polygon::clone() const {
	return new Polygon(*this);
}

CoordinateSequence* Polygon::getCoordinates() const {
	if (isEmpty()) {
		return getFactory()->getCoordinateSequenceFactory()->create(NULL);
	}

	vector<Coordinate> *cl = new vector<Coordinate>;

	int k = -1;
	const CoordinateSequence* shellCoords=shell->getCoordinatesRO();
	for (int x = 0; x < shellCoords->getSize(); x++) {
		k++;
		cl->push_back(shellCoords->getAt(x));
	}

	for (unsigned int i = 0; i < holes->size(); i++) {
		const CoordinateSequence* childCoords=((LinearRing *)(*holes)[i])->getCoordinatesRO();
		for (int j = 0; j < childCoords->getSize(); j++) {
			k++;
			cl->push_back(childCoords->getAt(j));
		}
	}

	return getFactory()->getCoordinateSequenceFactory()->create(cl);
}

int Polygon::getNumPoints() const {
	int numPoints = shell->getNumPoints();
	for (unsigned int i = 0; i < holes->size(); i++) {
		numPoints += ((LinearRing *)(*holes)[i])->getNumPoints();
	}
	return numPoints;
}

int Polygon::getDimension() const {
	return 2;
}

int Polygon::getBoundaryDimension() const {
	return 1;
}

bool Polygon::isEmpty() const {
	return shell->isEmpty();
}

bool Polygon::isSimple() const {
	return true;
}

const LineString* Polygon::getExteriorRing() const {
	return shell;
}

int Polygon::getNumInteriorRing() const {
	return (int)holes->size();
}

const LineString* Polygon::getInteriorRingN(int n) const {
	return (LineString *) (*holes)[n];
}

string Polygon::getGeometryType() const {
	return "Polygon";
}

// Returns a newly allocated Geometry object
Geometry* Polygon::getBoundary() const {
	if (isEmpty()) {
		return getFactory()->createGeometryCollection(NULL);
	}
	vector<Geometry *> rings(holes->size()+1);
	rings[0]=shell;
	for (unsigned int i=0; i<holes->size(); i++) {
		rings[i + 1] = (*holes)[i];
	}
	MultiLineString *ret =getFactory()->createMultiLineString(rings);
	return ret;
}

Envelope* Polygon::computeEnvelopeInternal() const {
	return new Envelope(*(shell->getEnvelopeInternal()));
}

bool Polygon::equalsExact(const Geometry *other, double tolerance) const {
	if (!isEquivalentClass(other)) {
		return false;
	}
	const Polygon* otherPolygon=dynamic_cast<const Polygon*>(other);
	Geometry* thisShell=dynamic_cast<Geometry *>(shell);
	if (typeid(*(otherPolygon->shell))!=typeid(Geometry)) {
		return false;
	}
	Geometry* otherPolygonShell=dynamic_cast<Geometry *>(otherPolygon->shell);
	if (!shell->equalsExact(otherPolygonShell, tolerance)) {
		return false;
	}
	if (holes->size()!=otherPolygon->holes->size()) {
		return false;
	}
	for (unsigned int i = 0; i < holes->size(); i++) {
		if (!((LinearRing *)(*holes)[i])->equalsExact((*(otherPolygon->holes))[i],tolerance)) {
			return false;
		}
	}
	return true;
}

void Polygon::apply_ro(CoordinateFilter *filter) const {
	shell->apply_ro(filter);
	for (unsigned int i = 0; i < holes->size(); i++) {
		((LinearRing *)(*holes)[i])->apply_ro(filter);
	}
}

void Polygon::apply_rw(CoordinateFilter *filter) {
	shell->apply_rw(filter);
	for (unsigned int i = 0; i < holes->size(); i++) {
		((LinearRing *)(*holes)[i])->apply_rw(filter);
	}
}

void Polygon::apply_rw(GeometryFilter *filter) {
	filter->filter_rw(this);
}

void Polygon::apply_ro(GeometryFilter *filter) const {
	filter->filter_ro(this);
}

Geometry* Polygon::convexHull() const {
	return getExteriorRing()->convexHull();
}

void Polygon::normalize() {
	normalize(shell, true);
	for (unsigned int i = 0; i < holes->size(); i++) {
		normalize((LinearRing *)(*holes)[i], false);
	}
	sort(holes->begin(),holes->end(),greaterThen);
}

int Polygon::compareToSameClass(const Geometry *p) const {
	return shell->compareToSameClass(((Polygon*)p)->shell);
}

void Polygon::normalize(LinearRing *ring, bool clockwise) {
	if (ring->isEmpty()) {
		return;
	}
	CoordinateSequence* uniqueCoordinates=ring->getCoordinates();
	uniqueCoordinates->deleteAt(uniqueCoordinates->getSize()-1);
	const Coordinate* minCoordinate=CoordinateSequence::minCoordinate(uniqueCoordinates);
	CoordinateSequence::scroll(uniqueCoordinates, minCoordinate);
	uniqueCoordinates->add(uniqueCoordinates->getAt(0));
	if (CGAlgorithms::isCCW(uniqueCoordinates)==clockwise) {
		CoordinateSequence::reverse(uniqueCoordinates);
	}
	ring->setPoints(uniqueCoordinates);
	delete(uniqueCoordinates);
}

const Coordinate* Polygon::getCoordinate() const {
	return shell->getCoordinate();
}

/*
*  Returns the area of this Polygon
*
*@return the area of the polygon
*/
double Polygon::getArea() const {
	double area=0.0;
	area+=fabs(CGAlgorithms::signedArea(shell->getCoordinatesRO()));
	for(unsigned int i=0;i<holes->size();i++) {
		CoordinateSequence *h=(*holes)[i]->getCoordinates();
        	area-=fabs(CGAlgorithms::signedArea(h));
		delete h;
	}
	return area;
}

/**
 * Returns the perimeter of this Polygon
 *
 * @return the perimeter of the polygon
 */
double Polygon::getLength() const {
	double len=0.0;
	len+=shell->getLength();
	for(unsigned int i=0;i<holes->size();i++) {
        len+=(*holes)[i]->getLength();
	}
	return len;
}

void Polygon::apply_ro(GeometryComponentFilter *filter) const {
	filter->filter_ro(this);
	shell->apply_ro(filter);
	for(unsigned int i=0;i<holes->size();i++) {
        	(*holes)[i]->apply_ro(filter);
	}
}

void Polygon::apply_rw(GeometryComponentFilter *filter) {
	filter->filter_rw(this);
	shell->apply_rw(filter);
	for(unsigned int i=0;i<holes->size();i++) {
        	(*holes)[i]->apply_rw(filter);
	}
}

Polygon::~Polygon(){
	delete shell;
	for(int i=0;i<(int)holes->size();i++) {
		delete (*holes)[i];
	}
	delete holes;
}
GeometryTypeId
Polygon::getGeometryTypeId() const {
	return GEOS_POLYGON;
}
}

<commit_msg>Changed ::getBoundary() to return LineString if polygon has no holes. (has required to pass OGC conformance test T20)<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 * $Log$
 * Revision 1.44  2004/11/12 18:12:05  strk
 * Changed ::getBoundary() to return LineString if polygon has no holes.
 * (has required to pass OGC conformance test T20)
 *
 * Revision 1.43  2004/07/27 16:35:46  strk
 * Geometry::getEnvelopeInternal() changed to return a const Envelope *.
 * This should reduce object copies as once computed the envelope of a
 * geometry remains the same.
 *
 * Revision 1.42  2004/07/22 07:04:49  strk
 * Documented missing geometry functions.
 *
 * Revision 1.41  2004/07/13 08:33:52  strk
 * Added missing virtual destructor to virtual classes.
 * Fixed implicit unsigned int -> int casts
 *
 * Revision 1.40  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.39  2004/07/06 17:58:22  strk
 * Removed deprecated Geometry constructors based on PrecisionModel and
 * SRID specification. Removed SimpleGeometryPrecisionReducer capability
 * of changing Geometry's factory. Reverted Geometry::factory member
 * to be a reference to external factory.
 *
 * Revision 1.38  2004/07/05 10:50:20  strk
 * deep-dopy construction taken out of Geometry and implemented only
 * in GeometryFactory.
 * Deep-copy geometry construction takes care of cleaning up copies
 * on exception.
 * Implemented clone() method for CoordinateSequence
 * Changed createMultiPoint(CoordinateSequence) signature to reflect
 * copy semantic (by-ref instead of by-pointer).
 * Cleaned up documentation.
 *
 * Revision 1.37  2004/07/02 13:28:26  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.36  2004/07/01 14:12:44  strk
 *
 * Geometry constructors come now in two flavors:
 * 	- deep-copy args (pass-by-reference)
 * 	- take-ownership of args (pass-by-pointer)
 * Same functionality is available through GeometryFactory,
 * including buildGeometry().
 *
 * Revision 1.35  2004/06/28 21:58:24  strk
 * Constructors speedup.
 *
 * Revision 1.34  2004/06/28 21:11:43  strk
 * Moved getGeometryTypeId() definitions from geom.h to each geometry module.
 * Added holes argument check in Polygon.cpp.
 *
 * Revision 1.33  2004/06/15 20:30:47  strk
 * updated to respect deep-copy GeometryCollection interface
 *
 * Revision 1.32  2004/04/20 13:24:15  strk
 * More leaks removed.
 *
 * Revision 1.31  2004/04/20 08:52:01  strk
 * GeometryFactory and Geometry const correctness.
 * Memory leaks removed from SimpleGeometryPrecisionReducer
 * and GeometryFactory.
 *
 * Revision 1.30  2004/04/01 10:44:33  ybychkov
 * All "geom" classes from JTS 1.3 upgraded to JTS 1.4
 *
 * Revision 1.29  2004/03/31 07:50:37  ybychkov
 * "geom" partially upgraded to JTS 1.4
 *
 * Revision 1.28  2004/02/27 17:43:45  strk
 * memory leak fix in Polygon::getArea() - reported by 'Manuel  Prieto Villegas' <mprieto@dap.es>
 *
 * Revision 1.27  2003/11/07 01:23:42  pramsey
 * Add standard CVS headers licence notices and copyrights to all cpp and h
 * files.
 *
 * Revision 1.26  2003/10/31 16:36:04  strk
 * Re-introduced clone() method. Copy constructor could not really
 * replace it.
 *
 * Revision 1.25  2003/10/17 05:51:21  ybychkov
 * Fixed a small memory leak.
 *
 * Revision 1.24  2003/10/16 08:50:00  strk
 * Memory leak fixes. Improved performance by mean of more calls to
 * new getCoordinatesRO() when applicable.
 *
 **********************************************************************/

#include <geos/geom.h>
#include <typeinfo>
#include <geos/geosAlgorithm.h>

namespace geos {

Polygon::Polygon(const Polygon &p): Geometry(p.getFactory()){
	shell=new LinearRing(*p.shell);
	holes=new vector<Geometry *>();
	for(int i=0;i<(int)p.holes->size();i++) {
		LinearRing *h=new LinearRing(* (LinearRing*)(*p.holes)[i]);
		holes->push_back(h);
	}
}

/*
* Constructs a Polygon with the given exterior
* and interior boundaries.
*
* @param  shell     the outer boundary of the new Polygon,
*                   or null or an empty
*                   LinearRing if the empty geometry
*                   is to be created.
*
* @param  holes     the LinearRings defining the inner
*                   boundaries of the new Polygon, or
*                   null or empty LinearRings
*                   if the empty  geometry is to be created.
*
* Polygon will take ownership of Shell and Holes LinearRings
*
*/
Polygon::Polygon(LinearRing *newShell, vector<Geometry *> *newHoles, const GeometryFactory *newFactory): Geometry(newFactory)
{
	if (newShell==NULL) {
		shell=getFactory()->createLinearRing(NULL);
	}
	else
	{
		if (newShell->isEmpty() && hasNonEmptyElements(newHoles)) {
			delete newShell;
			delete newHoles;
			throw new IllegalArgumentException("shell is empty but holes are not");
		}
		shell=newShell;
	}

	if (newHoles==NULL)
	{
		holes=new vector<Geometry *>();
	}
	else
	{
		if (hasNullElements(newHoles)) {
			delete newShell;
			delete newHoles;
			throw new IllegalArgumentException("holes must not contain null elements");
		}
		for (unsigned int i=0; i<newHoles->size(); i++)
			if ( (*newHoles)[i]->getGeometryTypeId() != GEOS_LINEARRING)
				throw new IllegalArgumentException("holes must be LinearRings");
		holes=newHoles;
	}
}

Geometry *Polygon::clone() const {
	return new Polygon(*this);
}

CoordinateSequence* Polygon::getCoordinates() const {
	if (isEmpty()) {
		return getFactory()->getCoordinateSequenceFactory()->create(NULL);
	}

	vector<Coordinate> *cl = new vector<Coordinate>;

	int k = -1;
	const CoordinateSequence* shellCoords=shell->getCoordinatesRO();
	for (int x = 0; x < shellCoords->getSize(); x++) {
		k++;
		cl->push_back(shellCoords->getAt(x));
	}

	for (unsigned int i = 0; i < holes->size(); i++) {
		const CoordinateSequence* childCoords=((LinearRing *)(*holes)[i])->getCoordinatesRO();
		for (int j = 0; j < childCoords->getSize(); j++) {
			k++;
			cl->push_back(childCoords->getAt(j));
		}
	}

	return getFactory()->getCoordinateSequenceFactory()->create(cl);
}

int Polygon::getNumPoints() const {
	int numPoints = shell->getNumPoints();
	for (unsigned int i = 0; i < holes->size(); i++) {
		numPoints += ((LinearRing *)(*holes)[i])->getNumPoints();
	}
	return numPoints;
}

int Polygon::getDimension() const {
	return 2;
}

int Polygon::getBoundaryDimension() const {
	return 1;
}

bool Polygon::isEmpty() const {
	return shell->isEmpty();
}

bool Polygon::isSimple() const {
	return true;
}

const LineString* Polygon::getExteriorRing() const {
	return shell;
}

int Polygon::getNumInteriorRing() const {
	return (int)holes->size();
}

const LineString* Polygon::getInteriorRingN(int n) const {
	return (LineString *) (*holes)[n];
}

string Polygon::getGeometryType() const {
	return "Polygon";
}

// Returns a newly allocated Geometry object
Geometry* Polygon::getBoundary() const {
	if (isEmpty()) {
		return getFactory()->createGeometryCollection(NULL);
	}
	if ( ! holes->size() )
	{
		return shell->clone();
	}

	vector<Geometry *> rings(holes->size()+1);
	rings[0]=shell;
	for (unsigned int i=0; i<holes->size(); i++) {
		rings[i + 1] = (*holes)[i];
	}
	MultiLineString *ret =getFactory()->createMultiLineString(rings);
	return ret;
}

Envelope* Polygon::computeEnvelopeInternal() const {
	return new Envelope(*(shell->getEnvelopeInternal()));
}

bool Polygon::equalsExact(const Geometry *other, double tolerance) const {
	if (!isEquivalentClass(other)) {
		return false;
	}
	const Polygon* otherPolygon=dynamic_cast<const Polygon*>(other);
	Geometry* thisShell=dynamic_cast<Geometry *>(shell);
	if (typeid(*(otherPolygon->shell))!=typeid(Geometry)) {
		return false;
	}
	Geometry* otherPolygonShell=dynamic_cast<Geometry *>(otherPolygon->shell);
	if (!shell->equalsExact(otherPolygonShell, tolerance)) {
		return false;
	}
	if (holes->size()!=otherPolygon->holes->size()) {
		return false;
	}
	for (unsigned int i = 0; i < holes->size(); i++) {
		if (!((LinearRing *)(*holes)[i])->equalsExact((*(otherPolygon->holes))[i],tolerance)) {
			return false;
		}
	}
	return true;
}

void Polygon::apply_ro(CoordinateFilter *filter) const {
	shell->apply_ro(filter);
	for (unsigned int i = 0; i < holes->size(); i++) {
		((LinearRing *)(*holes)[i])->apply_ro(filter);
	}
}

void Polygon::apply_rw(CoordinateFilter *filter) {
	shell->apply_rw(filter);
	for (unsigned int i = 0; i < holes->size(); i++) {
		((LinearRing *)(*holes)[i])->apply_rw(filter);
	}
}

void Polygon::apply_rw(GeometryFilter *filter) {
	filter->filter_rw(this);
}

void Polygon::apply_ro(GeometryFilter *filter) const {
	filter->filter_ro(this);
}

Geometry* Polygon::convexHull() const {
	return getExteriorRing()->convexHull();
}

void Polygon::normalize() {
	normalize(shell, true);
	for (unsigned int i = 0; i < holes->size(); i++) {
		normalize((LinearRing *)(*holes)[i], false);
	}
	sort(holes->begin(),holes->end(),greaterThen);
}

int Polygon::compareToSameClass(const Geometry *p) const {
	return shell->compareToSameClass(((Polygon*)p)->shell);
}

void Polygon::normalize(LinearRing *ring, bool clockwise) {
	if (ring->isEmpty()) {
		return;
	}
	CoordinateSequence* uniqueCoordinates=ring->getCoordinates();
	uniqueCoordinates->deleteAt(uniqueCoordinates->getSize()-1);
	const Coordinate* minCoordinate=CoordinateSequence::minCoordinate(uniqueCoordinates);
	CoordinateSequence::scroll(uniqueCoordinates, minCoordinate);
	uniqueCoordinates->add(uniqueCoordinates->getAt(0));
	if (CGAlgorithms::isCCW(uniqueCoordinates)==clockwise) {
		CoordinateSequence::reverse(uniqueCoordinates);
	}
	ring->setPoints(uniqueCoordinates);
	delete(uniqueCoordinates);
}

const Coordinate* Polygon::getCoordinate() const {
	return shell->getCoordinate();
}

/*
*  Returns the area of this Polygon
*
*@return the area of the polygon
*/
double Polygon::getArea() const {
	double area=0.0;
	area+=fabs(CGAlgorithms::signedArea(shell->getCoordinatesRO()));
	for(unsigned int i=0;i<holes->size();i++) {
		CoordinateSequence *h=(*holes)[i]->getCoordinates();
        	area-=fabs(CGAlgorithms::signedArea(h));
		delete h;
	}
	return area;
}

/**
 * Returns the perimeter of this Polygon
 *
 * @return the perimeter of the polygon
 */
double Polygon::getLength() const {
	double len=0.0;
	len+=shell->getLength();
	for(unsigned int i=0;i<holes->size();i++) {
        len+=(*holes)[i]->getLength();
	}
	return len;
}

void Polygon::apply_ro(GeometryComponentFilter *filter) const {
	filter->filter_ro(this);
	shell->apply_ro(filter);
	for(unsigned int i=0;i<holes->size();i++) {
        	(*holes)[i]->apply_ro(filter);
	}
}

void Polygon::apply_rw(GeometryComponentFilter *filter) {
	filter->filter_rw(this);
	shell->apply_rw(filter);
	for(unsigned int i=0;i<holes->size();i++) {
        	(*holes)[i]->apply_rw(filter);
	}
}

Polygon::~Polygon(){
	delete shell;
	for(int i=0;i<(int)holes->size();i++) {
		delete (*holes)[i];
	}
	delete holes;
}
GeometryTypeId
Polygon::getGeometryTypeId() const {
	return GEOS_POLYGON;
}
}

<|endoftext|>


<commit_before>#include "log_ui.h"
#include "core/log.h"
#include "imgui/imgui.h"

LogUI::LogUI(Lumix::IAllocator& allocator)
	: m_allocator(allocator)
	, m_messages(allocator)
	, m_current_tab(0)
	, m_notifications(allocator)
	, m_last_uid(1)
	, m_guard(false)
{
	m_is_opened = false;
	Lumix::g_log_info.getCallback().bind<LogUI, &LogUI::onInfo>(this);
	Lumix::g_log_error.getCallback().bind<LogUI, &LogUI::onError>(this);
	Lumix::g_log_warning.getCallback().bind<LogUI, &LogUI::onWarning>(this);

	for (int i = 0; i < Count; ++i)
	{
		m_new_message_count[i] = 0;
		m_messages.emplace(allocator);
	}
}

LogUI::~LogUI()
{
	Lumix::g_log_info.getCallback().unbind<LogUI, &LogUI::onInfo>(this);
	Lumix::g_log_error.getCallback().unbind<LogUI, &LogUI::onError>(this);
	Lumix::g_log_warning.getCallback().unbind<LogUI, &LogUI::onWarning>(this);
}

void LogUI::setNotificationTime(int uid, float time)
{
	for (auto& notif : m_notifications)
	{
		if (notif.uid == uid)
		{
			notif.time = time;
			break;
		}
	}
}

int LogUI::addNotification(const char* text)
{
	m_move_notifications_to_front = true;
	auto& notif = m_notifications.emplace(m_allocator);
	notif.time = 10.0f;
	notif.message = text;
	notif.uid = ++m_last_uid;
	return notif.uid;
}

void LogUI::push(Type type, const char* message)
{
	Lumix::MT::SpinLock lock(m_guard);
	++m_new_message_count[type];
	m_messages[type].push(Lumix::string(message, m_allocator));

	if (type == Error || type == Warning)
	{
		addNotification(message);
	}
}

void LogUI::onInfo(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Info, message);
}

void LogUI::onWarning(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Warning, message);
}

void LogUI::onError(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Error, message);
}

void fillLabel(char* output, int max_size, const char* label, int count)
{
	Lumix::copyString(output, max_size, label);
	Lumix::catString(output, max_size, "(");
	int len = Lumix::stringLength(output);
	Lumix::toCString(count, output + len, max_size - len);
	Lumix::catString(output, max_size, ")");
}

void LogUI::showNotifications()
{
	m_are_notifications_hovered = false;
	if (m_notifications.empty()) return;

	ImGui::SetNextWindowPos(ImVec2(10, 30));
	bool opened;
	if (!ImGui::Begin("Notifications",
					  &opened,
					  ImVec2(200, 0),
					  1.0f,
					  ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize |
						  ImGuiWindowFlags_NoMove |
						  ImGuiWindowFlags_NoSavedSettings))
	{
		ImGui::End();
		return;
	}

	m_are_notifications_hovered = ImGui::IsWindowHovered();

	if (ImGui::Button("Close")) m_notifications.clear();

	if (m_move_notifications_to_front) ImGui::BringToFront();
	m_move_notifications_to_front = false;
	for (int i = 0; i < m_notifications.size(); ++i)
	{
		if (i > 0) ImGui::Separator();
		ImGui::Text(m_notifications[i].message.c_str());
	}
	ImGui::End();
}

void LogUI::update(float time_delta)
{
	if (m_are_notifications_hovered) return;

	for (int i = 0; i < m_notifications.size(); ++i)
	{
		m_notifications[i].time -= time_delta;

		if (m_notifications[i].time < 0)
		{
			m_notifications.erase(i);
			--i;
		}
	}
}

void LogUI::onGUI()
{
	Lumix::MT::SpinLock lock(m_guard);
	showNotifications();

	if (ImGui::BeginDock("Log", &m_is_opened))
	{
		const char* labels[] = { "Info", "Warning", "Error", "BGFX" };
		for (int i = 0; i < Lumix::lengthOf(labels); ++i)
		{
			char label[20];
			fillLabel(label, sizeof(label), labels[i], m_new_message_count[i]);
			if(i > 0) ImGui::SameLine();
			if (ImGui::Button(label))
			{
				m_current_tab = i;
				m_new_message_count[i] = 0;
			}
		}

		auto* messages = &m_messages[m_current_tab];

		if (ImGui::Button("Clear"))
		{
			for (int i = 0; i < m_messages.size(); ++i)
			{
				m_messages[i].clear();
				m_new_message_count[i] = 0;
			}
		}

		ImGui::SameLine();
		char filter[128] = "";
		ImGui::InputText("Filter", filter, sizeof(filter));

		if (ImGui::BeginChild("log_messages"))
		{
			for (int i = 0; i < messages->size(); ++i)
			{
				const char* msg = (*messages)[i].c_str();
				if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
				{
					ImGui::Text(msg);
				}
			}
		}
		ImGui::EndChild();
	}
	ImGui::EndDock();
}
<commit_msg>notifications have border<commit_after>#include "log_ui.h"
#include "core/log.h"
#include "imgui/imgui.h"

LogUI::LogUI(Lumix::IAllocator& allocator)
	: m_allocator(allocator)
	, m_messages(allocator)
	, m_current_tab(0)
	, m_notifications(allocator)
	, m_last_uid(1)
	, m_guard(false)
{
	m_is_opened = false;
	Lumix::g_log_info.getCallback().bind<LogUI, &LogUI::onInfo>(this);
	Lumix::g_log_error.getCallback().bind<LogUI, &LogUI::onError>(this);
	Lumix::g_log_warning.getCallback().bind<LogUI, &LogUI::onWarning>(this);

	for (int i = 0; i < Count; ++i)
	{
		m_new_message_count[i] = 0;
		m_messages.emplace(allocator);
	}
}

LogUI::~LogUI()
{
	Lumix::g_log_info.getCallback().unbind<LogUI, &LogUI::onInfo>(this);
	Lumix::g_log_error.getCallback().unbind<LogUI, &LogUI::onError>(this);
	Lumix::g_log_warning.getCallback().unbind<LogUI, &LogUI::onWarning>(this);
}

void LogUI::setNotificationTime(int uid, float time)
{
	for (auto& notif : m_notifications)
	{
		if (notif.uid == uid)
		{
			notif.time = time;
			break;
		}
	}
}

int LogUI::addNotification(const char* text)
{
	m_move_notifications_to_front = true;
	auto& notif = m_notifications.emplace(m_allocator);
	notif.time = 10.0f;
	notif.message = text;
	notif.uid = ++m_last_uid;
	return notif.uid;
}

void LogUI::push(Type type, const char* message)
{
	Lumix::MT::SpinLock lock(m_guard);
	++m_new_message_count[type];
	m_messages[type].push(Lumix::string(message, m_allocator));

	if (type == Error || type == Warning)
	{
		addNotification(message);
	}
}

void LogUI::onInfo(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Info, message);
}

void LogUI::onWarning(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Warning, message);
}

void LogUI::onError(const char* system, const char* message)
{
	push(Lumix::compareString(system, "bgfx") == 0 ? BGFX : Error, message);
}

void fillLabel(char* output, int max_size, const char* label, int count)
{
	Lumix::copyString(output, max_size, label);
	Lumix::catString(output, max_size, "(");
	int len = Lumix::stringLength(output);
	Lumix::toCString(count, output + len, max_size - len);
	Lumix::catString(output, max_size, ")");
}

void LogUI::showNotifications()
{
	m_are_notifications_hovered = false;
	if (m_notifications.empty()) return;

	ImGui::SetNextWindowPos(ImVec2(10, 30));
	bool opened;
	if (!ImGui::Begin("Notifications",
			&opened,
			ImVec2(200, 0),
			1.0f,
			ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize |
				ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
				ImGuiWindowFlags_ShowBorders))
	{
		ImGui::End();
		return;
	}

	m_are_notifications_hovered = ImGui::IsWindowHovered();

	if (ImGui::Button("Close")) m_notifications.clear();

	if (m_move_notifications_to_front) ImGui::BringToFront();
	m_move_notifications_to_front = false;
	for (int i = 0; i < m_notifications.size(); ++i)
	{
		if (i > 0) ImGui::Separator();
		ImGui::Text(m_notifications[i].message.c_str());
	}
	ImGui::End();
}

void LogUI::update(float time_delta)
{
	if (m_are_notifications_hovered) return;

	for (int i = 0; i < m_notifications.size(); ++i)
	{
		m_notifications[i].time -= time_delta;

		if (m_notifications[i].time < 0)
		{
			m_notifications.erase(i);
			--i;
		}
	}
}

void LogUI::onGUI()
{
	Lumix::MT::SpinLock lock(m_guard);
	showNotifications();

	if (ImGui::BeginDock("Log", &m_is_opened))
	{
		const char* labels[] = { "Info", "Warning", "Error", "BGFX" };
		for (int i = 0; i < Lumix::lengthOf(labels); ++i)
		{
			char label[20];
			fillLabel(label, sizeof(label), labels[i], m_new_message_count[i]);
			if(i > 0) ImGui::SameLine();
			if (ImGui::Button(label))
			{
				m_current_tab = i;
				m_new_message_count[i] = 0;
			}
		}

		auto* messages = &m_messages[m_current_tab];

		if (ImGui::Button("Clear"))
		{
			for (int i = 0; i < m_messages.size(); ++i)
			{
				m_messages[i].clear();
				m_new_message_count[i] = 0;
			}
		}

		ImGui::SameLine();
		char filter[128] = "";
		ImGui::InputText("Filter", filter, sizeof(filter));

		if (ImGui::BeginChild("log_messages"))
		{
			for (int i = 0; i < messages->size(); ++i)
			{
				const char* msg = (*messages)[i].c_str();
				if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
				{
					ImGui::Text(msg);
				}
			}
		}
		ImGui::EndChild();
	}
	ImGui::EndDock();
}
<|endoftext|>


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

#include <unistd.h>
#include <cerrno>

#include "shrpx_upstream.h"
#include "shrpx_spdy_upstream.h"
#include "shrpx_https_upstream.h"
#include "shrpx_config.h"
#include "shrpx_http_downstream_connection.h"
#include "shrpx_spdy_downstream_connection.h"
#include "shrpx_accesslog.h"

namespace shrpx {

namespace {
void upstream_readcb(bufferevent *bev, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  int rv = handler->on_read();
  if(rv != 0) {
    delete handler;
  }
}
} // namespace

namespace {
void upstream_writecb(bufferevent *bev, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  // We actually depend on write low-warter mark == 0.
  if(handler->get_outbuf_length() > 0) {
    // Possibly because of deferred callback, we may get this callback
    // when the output buffer is not empty.
    return;
  }
  if(handler->get_should_close_after_write()) {
    delete handler;
  } else {
    Upstream *upstream = handler->get_upstream();
    int rv = upstream->on_write();
    if(rv != 0) {
      delete handler;
    }
  }
}
} // namespace

namespace {
void upstream_eventcb(bufferevent *bev, short events, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  bool finish = false;
  if(events & BEV_EVENT_EOF) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "EOF";
    }
    finish = true;
  }
  if(events & BEV_EVENT_ERROR) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Network error: "
                          << evutil_socket_error_to_string
        (EVUTIL_SOCKET_ERROR());
    }
    finish = true;
  }
  if(events & BEV_EVENT_TIMEOUT) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Time out";
    }
    finish = true;
  }
  if(finish) {
    delete handler;
  } else {
    if(events & BEV_EVENT_CONNECTED) {
      handler->set_tls_handshake(true);
      if(LOG_ENABLED(INFO)) {
        CLOG(INFO, handler) << "SSL/TLS handshake completed";
      }
      handler->set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
      handler->validate_next_proto();
      if(LOG_ENABLED(INFO)) {
        if(SSL_session_reused(handler->get_ssl())) {
          CLOG(INFO, handler) << "SSL/TLS session reused";
        }
      }
      // At this point, input buffer is already filled with some
      // bytes.  The read callback is not called until new data
      // come. So consume input buffer here.
      handler->get_upstream()->on_read();
    }
  }
}
} // namespace

namespace {
void tls_raw_readcb(evbuffer *buffer, const evbuffer_cb_info *info, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  if(handler->get_tls_renegotiation()) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Close connection due to TLS renegotiation";
    }
    delete handler;
  }
}
} // namespace

ClientHandler::ClientHandler(bufferevent *bev, int fd, SSL *ssl,
                             const char *ipaddr)
  : ipaddr_(ipaddr),
    bev_(bev),
    ssl_(ssl),
    upstream_(0),
    spdy_(0),
    fd_(fd),
    should_close_after_write_(false),
    tls_handshake_(false),
    tls_renegotiation_(false)
{
  bufferevent_set_rate_limit(bev_, get_config()->rate_limit_cfg);
  bufferevent_enable(bev_, EV_READ | EV_WRITE);
  bufferevent_setwatermark(bev_, EV_READ, 0, SHRPX_READ_WARTER_MARK);
  set_upstream_timeouts(&get_config()->upstream_read_timeout,
                        &get_config()->upstream_write_timeout);
  if(ssl_) {
    SSL_set_app_data(ssl_, reinterpret_cast<char*>(this));
    set_bev_cb(0, upstream_writecb, upstream_eventcb);
    evbuffer *input = bufferevent_get_input(bufferevent_get_underlying(bev_));
    evbuffer_add_cb(input, tls_raw_readcb, this);
  } else {
    if(get_config()->client_mode) {
      // Client mode
      upstream_ = new HttpsUpstream(this);
    } else {
      // no-TLS SPDY
      upstream_ = new SpdyUpstream(get_config()->spdy_upstream_version, this);
    }
    set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
  }
}

ClientHandler::~ClientHandler()
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Deleting";
  }
  if(ssl_) {
    SSL_set_app_data(ssl_, 0);
    SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
    SSL_shutdown(ssl_);
  }
  bufferevent *underlying = bufferevent_get_underlying(bev_);
  bufferevent_disable(bev_, EV_READ | EV_WRITE);
  bufferevent_free(bev_);
  if(underlying) {
    bufferevent_disable(underlying, EV_READ | EV_WRITE);
    bufferevent_free(underlying);
  }
  if(ssl_) {
    SSL_free(ssl_);
  }
  shutdown(fd_, SHUT_WR);
  close(fd_);
  delete upstream_;
  for(std::set<DownstreamConnection*>::iterator i = dconn_pool_.begin();
      i != dconn_pool_.end(); ++i) {
    delete *i;
  }
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Deleted";
  }
}

Upstream* ClientHandler::get_upstream()
{
  return upstream_;
}

bufferevent* ClientHandler::get_bev() const
{
  return bev_;
}

event_base* ClientHandler::get_evbase() const
{
  return bufferevent_get_base(bev_);
}

void ClientHandler::set_bev_cb
(bufferevent_data_cb readcb, bufferevent_data_cb writecb,
 bufferevent_event_cb eventcb)
{
  bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
}

void ClientHandler::set_upstream_timeouts(const timeval *read_timeout,
                                          const timeval *write_timeout)
{
  bufferevent_set_timeouts(bev_, read_timeout, write_timeout);
}

int ClientHandler::validate_next_proto()
{
  const unsigned char *next_proto = 0;
  unsigned int next_proto_len;
  SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
  if(next_proto) {
    if(LOG_ENABLED(INFO)) {
      std::string proto(next_proto, next_proto+next_proto_len);
      CLOG(INFO, this) << "The negotiated next protocol: " << proto;
    }
    uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
    if(version) {
      SpdyUpstream *spdy_upstream = new SpdyUpstream(version, this);
      upstream_ = spdy_upstream;
      return 0;
    }
  } else {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "No proto negotiated.";
    }
  }
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Use HTTP/1.1";
  }
  HttpsUpstream *https_upstream = new HttpsUpstream(this);
  upstream_ = https_upstream;
  return 0;
}

int ClientHandler::on_read()
{
  return upstream_->on_read();
}

int ClientHandler::on_event()
{
  return upstream_->on_event();
}

const std::string& ClientHandler::get_ipaddr() const
{
  return ipaddr_;
}

bool ClientHandler::get_should_close_after_write() const
{
  return should_close_after_write_;
}

void ClientHandler::set_should_close_after_write(bool f)
{
  should_close_after_write_ = f;
}

void ClientHandler::pool_downstream_connection(DownstreamConnection *dconn)
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn;
  }
  dconn_pool_.insert(dconn);
}

void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn)
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Removing downstream connection DCONN:" << dconn
                     << " from pool";
  }
  dconn_pool_.erase(dconn);
}

DownstreamConnection* ClientHandler::get_downstream_connection()
{
  if(dconn_pool_.empty()) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "Downstream connection pool is empty."
                       << " Create new one";
    }
    if(spdy_) {
      return new SpdyDownstreamConnection(this);
    } else {
      return new HttpDownstreamConnection(this);
    }
  } else {
    DownstreamConnection *dconn = *dconn_pool_.begin();
    dconn_pool_.erase(dconn);
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "Reuse downstream connection DCONN:" << dconn
                       << " from pool";
    }
    return dconn;
  }
}

size_t ClientHandler::get_outbuf_length()
{
  bufferevent *underlying = bufferevent_get_underlying(bev_);
  size_t len = evbuffer_get_length(bufferevent_get_output(bev_));
  if(underlying) {
    len += evbuffer_get_length(bufferevent_get_output(underlying));
  }
  return len;
}

SSL* ClientHandler::get_ssl() const
{
  return ssl_;
}

void ClientHandler::set_spdy_session(SpdySession *spdy)
{
  spdy_ = spdy;
}

SpdySession* ClientHandler::get_spdy_session() const
{
  return spdy_;
}

void ClientHandler::set_tls_handshake(bool f)
{
  tls_handshake_ = f;
}

bool ClientHandler::get_tls_handshake() const
{
  return tls_handshake_;
}

void ClientHandler::set_tls_renegotiation(bool f)
{
  tls_renegotiation_ = f;
}

bool ClientHandler::get_tls_renegotiation() const
{
  return tls_renegotiation_;
}

} // namespace shrpx
<commit_msg>shrpx: Call upstream_writecb when underlying bufferevent buffer gets empty<commit_after>/*
 * Spdylay - SPDY Library
 *
 * Copyright (c) 2012 Tatsuhiro Tsujikawa
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "shrpx_client_handler.h"

#include <unistd.h>
#include <cerrno>

#include "shrpx_upstream.h"
#include "shrpx_spdy_upstream.h"
#include "shrpx_https_upstream.h"
#include "shrpx_config.h"
#include "shrpx_http_downstream_connection.h"
#include "shrpx_spdy_downstream_connection.h"
#include "shrpx_accesslog.h"

namespace shrpx {

namespace {
void upstream_readcb(bufferevent *bev, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  int rv = handler->on_read();
  if(rv != 0) {
    delete handler;
  }
}
} // namespace

namespace {
void upstream_writecb(bufferevent *bev, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  // We actually depend on write low-warter mark == 0.
  if(handler->get_outbuf_length() > 0) {
    // Possibly because of deferred callback, we may get this callback
    // when the output buffer is not empty.
    return;
  }
  if(handler->get_should_close_after_write()) {
    delete handler;
    return;
  }
  Upstream *upstream = handler->get_upstream();
  if(!upstream) {
    return;
  }
  int rv = upstream->on_write();
  if(rv != 0) {
    delete handler;
  }
}
} // namespace

namespace {
void upstream_eventcb(bufferevent *bev, short events, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  bool finish = false;
  if(events & BEV_EVENT_EOF) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "EOF";
    }
    finish = true;
  }
  if(events & BEV_EVENT_ERROR) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Network error: "
                          << evutil_socket_error_to_string
        (EVUTIL_SOCKET_ERROR());
    }
    finish = true;
  }
  if(events & BEV_EVENT_TIMEOUT) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Time out";
    }
    finish = true;
  }
  if(finish) {
    delete handler;
  } else {
    if(events & BEV_EVENT_CONNECTED) {
      handler->set_tls_handshake(true);
      if(LOG_ENABLED(INFO)) {
        CLOG(INFO, handler) << "SSL/TLS handshake completed";
      }
      handler->set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
      handler->validate_next_proto();
      if(LOG_ENABLED(INFO)) {
        if(SSL_session_reused(handler->get_ssl())) {
          CLOG(INFO, handler) << "SSL/TLS session reused";
        }
      }
      // At this point, input buffer is already filled with some
      // bytes.  The read callback is not called until new data
      // come. So consume input buffer here.
      handler->get_upstream()->on_read();
    }
  }
}
} // namespace

namespace {
void tls_raw_readcb(evbuffer *buffer, const evbuffer_cb_info *info, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  if(handler->get_tls_renegotiation()) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, handler) << "Close connection due to TLS renegotiation";
    }
    delete handler;
  }
}
} // namespace

namespace {
void tls_raw_writecb(evbuffer *buffer, const evbuffer_cb_info *info, void *arg)
{
  ClientHandler *handler = static_cast<ClientHandler*>(arg);
  // upstream_writecb() is called when external bufferevent
  // handler->bev's output buffer gets empty. But the underlying
  // bufferevent may have pending output buffer.
  upstream_writecb(handler->get_bev(), handler);
}
} // namespace

ClientHandler::ClientHandler(bufferevent *bev, int fd, SSL *ssl,
                             const char *ipaddr)
  : ipaddr_(ipaddr),
    bev_(bev),
    ssl_(ssl),
    upstream_(0),
    spdy_(0),
    fd_(fd),
    should_close_after_write_(false),
    tls_handshake_(false),
    tls_renegotiation_(false)
{
  bufferevent_set_rate_limit(bev_, get_config()->rate_limit_cfg);
  bufferevent_enable(bev_, EV_READ | EV_WRITE);
  bufferevent_setwatermark(bev_, EV_READ, 0, SHRPX_READ_WARTER_MARK);
  set_upstream_timeouts(&get_config()->upstream_read_timeout,
                        &get_config()->upstream_write_timeout);
  if(ssl_) {
    SSL_set_app_data(ssl_, reinterpret_cast<char*>(this));
    set_bev_cb(0, upstream_writecb, upstream_eventcb);
    evbuffer *input = bufferevent_get_input(bufferevent_get_underlying(bev_));
    evbuffer_add_cb(input, tls_raw_readcb, this);
    evbuffer *output = bufferevent_get_output(bufferevent_get_underlying(bev_));
    evbuffer_add_cb(output, tls_raw_writecb, this);
  } else {
    if(get_config()->client_mode) {
      // Client mode
      upstream_ = new HttpsUpstream(this);
    } else {
      // no-TLS SPDY
      upstream_ = new SpdyUpstream(get_config()->spdy_upstream_version, this);
    }
    set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
  }
}

ClientHandler::~ClientHandler()
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Deleting";
  }
  if(ssl_) {
    SSL_set_app_data(ssl_, 0);
    SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
    SSL_shutdown(ssl_);
  }
  bufferevent *underlying = bufferevent_get_underlying(bev_);
  bufferevent_disable(bev_, EV_READ | EV_WRITE);
  bufferevent_free(bev_);
  if(underlying) {
    bufferevent_disable(underlying, EV_READ | EV_WRITE);
    bufferevent_free(underlying);
  }
  if(ssl_) {
    SSL_free(ssl_);
  }
  shutdown(fd_, SHUT_WR);
  close(fd_);
  delete upstream_;
  for(std::set<DownstreamConnection*>::iterator i = dconn_pool_.begin();
      i != dconn_pool_.end(); ++i) {
    delete *i;
  }
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Deleted";
  }
}

Upstream* ClientHandler::get_upstream()
{
  return upstream_;
}

bufferevent* ClientHandler::get_bev() const
{
  return bev_;
}

event_base* ClientHandler::get_evbase() const
{
  return bufferevent_get_base(bev_);
}

void ClientHandler::set_bev_cb
(bufferevent_data_cb readcb, bufferevent_data_cb writecb,
 bufferevent_event_cb eventcb)
{
  bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
}

void ClientHandler::set_upstream_timeouts(const timeval *read_timeout,
                                          const timeval *write_timeout)
{
  bufferevent_set_timeouts(bev_, read_timeout, write_timeout);
}

int ClientHandler::validate_next_proto()
{
  const unsigned char *next_proto = 0;
  unsigned int next_proto_len;
  SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
  if(next_proto) {
    if(LOG_ENABLED(INFO)) {
      std::string proto(next_proto, next_proto+next_proto_len);
      CLOG(INFO, this) << "The negotiated next protocol: " << proto;
    }
    uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
    if(version) {
      SpdyUpstream *spdy_upstream = new SpdyUpstream(version, this);
      upstream_ = spdy_upstream;
      return 0;
    }
  } else {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "No proto negotiated.";
    }
  }
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Use HTTP/1.1";
  }
  HttpsUpstream *https_upstream = new HttpsUpstream(this);
  upstream_ = https_upstream;
  return 0;
}

int ClientHandler::on_read()
{
  return upstream_->on_read();
}

int ClientHandler::on_event()
{
  return upstream_->on_event();
}

const std::string& ClientHandler::get_ipaddr() const
{
  return ipaddr_;
}

bool ClientHandler::get_should_close_after_write() const
{
  return should_close_after_write_;
}

void ClientHandler::set_should_close_after_write(bool f)
{
  should_close_after_write_ = f;
}

void ClientHandler::pool_downstream_connection(DownstreamConnection *dconn)
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn;
  }
  dconn_pool_.insert(dconn);
}

void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn)
{
  if(LOG_ENABLED(INFO)) {
    CLOG(INFO, this) << "Removing downstream connection DCONN:" << dconn
                     << " from pool";
  }
  dconn_pool_.erase(dconn);
}

DownstreamConnection* ClientHandler::get_downstream_connection()
{
  if(dconn_pool_.empty()) {
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "Downstream connection pool is empty."
                       << " Create new one";
    }
    if(spdy_) {
      return new SpdyDownstreamConnection(this);
    } else {
      return new HttpDownstreamConnection(this);
    }
  } else {
    DownstreamConnection *dconn = *dconn_pool_.begin();
    dconn_pool_.erase(dconn);
    if(LOG_ENABLED(INFO)) {
      CLOG(INFO, this) << "Reuse downstream connection DCONN:" << dconn
                       << " from pool";
    }
    return dconn;
  }
}

size_t ClientHandler::get_outbuf_length()
{
  bufferevent *underlying = bufferevent_get_underlying(bev_);
  size_t len = evbuffer_get_length(bufferevent_get_output(bev_));
  if(underlying) {
    len += evbuffer_get_length(bufferevent_get_output(underlying));
  }
  return len;
}

SSL* ClientHandler::get_ssl() const
{
  return ssl_;
}

void ClientHandler::set_spdy_session(SpdySession *spdy)
{
  spdy_ = spdy;
}

SpdySession* ClientHandler::get_spdy_session() const
{
  return spdy_;
}

void ClientHandler::set_tls_handshake(bool f)
{
  tls_handshake_ = f;
}

bool ClientHandler::get_tls_handshake() const
{
  return tls_handshake_;
}

void ClientHandler::set_tls_renegotiation(bool f)
{
  tls_renegotiation_ = f;
}

bool ClientHandler::get_tls_renegotiation() const
{
  return tls_renegotiation_;
}

} // namespace shrpx
<|endoftext|>


<commit_before>/* libwpd
 * Copyright (C) 2003 William Lachance (william.lachance@sympatico.ca)
 * Copyright (C) 2003 Marc Maurer (j.m.maurer@student.utwente.nl)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * For further information visit http://libwpd.sourceforge.net
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#include "WP5Parser.h"
#include "WPXHeader.h"
#include "WP5Part.h"
#include "WP5HLListener.h"
#include "WP5HLStylesListener.h"
#include "libwpd_internal.h"
#include "WPXTable.h"

WP5Parser::WP5Parser(WPXInputStream *input, WPXHeader *header) :
	WPXParser(input, header)
{
}

WP5Parser::~WP5Parser()
{
}

void WP5Parser::parse(WPXInputStream *input, WP5HLListener *listener)
{
	listener->startDocument();

	input->seek(getHeader()->getDocumentOffset(), WPX_SEEK_SET);

	WPD_DEBUG_MSG(("WordPerfect: Starting document body parse (position = %ld)\n",(long)input->tell()));

	parseDocument(input, listener);

	listener->endDocument();
}

// parseDocument: parses a document body (may call itself recursively, on other streams, or itself)
void WP5Parser::parseDocument(WPXInputStream *input, WP5HLListener *listener)
{
	while (!input->atEOS())
	{
		uint8_t readVal;
		readVal = readU8(input);

		if (readVal == 0 || readVal == 0x7F || readVal == 0xFF)
		{
			// do nothing: this token is meaningless and is likely just corruption
		}
		else if (readVal >= (uint8_t)0x01 && readVal <= (uint8_t)0x1F)
		{
			// control characters

			switch (readVal)
			{
				case 0x0A: // hard new line
					listener->insertEOL();
					break;
				case 0x0B: // soft new page
					listener->insertBreak(WPX_PAGE_BREAK);
					break;
				case 0x0C: // hard new page
					listener->insertBreak(WPX_PAGE_BREAK);
					break;
				case 0x0D: // soft new line
					listener->insertEOL();
					break;
				default:
					// unsupported or undocumented token, ignore
					break;
			}
		}
		else if (readVal >= (uint8_t)0x20 && readVal <= (uint8_t)0x7E)
		{
			listener->insertCharacter( readVal );
		}
/*		else if (readVal >= (uint8_t)0x80 && readVal <= (uint8_t)0xBF)
		{
			// single byte functions
		}*/
		else
		{
			WP5Part *part = WP5Part::constructPart(input, readVal);
			if (part != NULL)
			{
				part->parse(listener);
				DELETEP(part);
			}
		}
	}
}

void WP5Parser::parse(WPXHLListenerImpl *listenerImpl)
{
	WPXInputStream *input = getInput();
	vector<WPXPageSpan *> pageList;
	WPXTableList tableList;

	try
 	{
		// do a "first-pass" parse of the document
		// gather table border information, page properties (per-page)
		WP5HLStylesListener stylesListener(&pageList, &tableList);
		parse(input, &stylesListener);

		// second pass: here is where we actually send the messages to the target app
		// that are necessary to emit the body of the target document
		WP5HLListener listener(&pageList, listenerImpl); // FIXME: SHOULD BE CONTENT_LISTENER, AND SHOULD BE PASSED TABLE DATA!
		parse(input, &listener);

		// cleanup section: free the used resources
		for (vector<WPXPageSpan *>::iterator iterSpan = pageList.begin(); iterSpan != pageList.end(); iterSpan++)
		{
			delete *iterSpan;
		}
	}
	catch(FileException)
	{
		WPD_DEBUG_MSG(("WordPerfect: File Exception. Parse terminated prematurely."));

		for (vector<WPXPageSpan *>::iterator iterSpan = pageList.begin(); iterSpan != pageList.end(); iterSpan++)
		{
			delete *iterSpan;
		}

		throw FileException();
	}
}
<commit_msg>Changing the conversion of Soft returns and Soft Pages in WP5Parser<commit_after>/* libwpd
 * Copyright (C) 2003 William Lachance (william.lachance@sympatico.ca)
 * Copyright (C) 2003 Marc Maurer (j.m.maurer@student.utwente.nl)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * For further information visit http://libwpd.sourceforge.net
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#include "WP5Parser.h"
#include "WPXHeader.h"
#include "WP5Part.h"
#include "WP5HLListener.h"
#include "WP5HLStylesListener.h"
#include "libwpd_internal.h"
#include "WPXTable.h"

WP5Parser::WP5Parser(WPXInputStream *input, WPXHeader *header) :
	WPXParser(input, header)
{
}

WP5Parser::~WP5Parser()
{
}

void WP5Parser::parse(WPXInputStream *input, WP5HLListener *listener)
{
	listener->startDocument();

	input->seek(getHeader()->getDocumentOffset(), WPX_SEEK_SET);

	WPD_DEBUG_MSG(("WordPerfect: Starting document body parse (position = %ld)\n",(long)input->tell()));

	parseDocument(input, listener);

	listener->endDocument();
}

// parseDocument: parses a document body (may call itself recursively, on other streams, or itself)
void WP5Parser::parseDocument(WPXInputStream *input, WP5HLListener *listener)
{
	while (!input->atEOS())
	{
		uint8_t readVal;
		readVal = readU8(input);

		if (readVal == 0 || readVal == 0x7F || readVal == 0xFF)
		{
			// do nothing: this token is meaningless and is likely just corruption
		}
		else if (readVal >= (uint8_t)0x01 && readVal <= (uint8_t)0x1F)
		{
			// control characters

			switch (readVal)
			{
				case 0x0A: // hard new line
					listener->insertEOL();
					break;
				case 0x0B: // soft new page (convert like space)
					listener->insertCharacter((uint16_t) ' ');
					break;
				case 0x0C: // hard new page
					listener->insertBreak(WPX_PAGE_BREAK);
					break;
				case 0x0D: // soft new line (convert like space)
					listener->insertCharacter((uint16_t) ' ');
					break;
				default:
					// unsupported or undocumented token, ignore
					break;
			}
		}
		else if (readVal >= (uint8_t)0x20 && readVal <= (uint8_t)0x7E)
		{
			listener->insertCharacter( readVal );
		}
/*		else if (readVal >= (uint8_t)0x80 && readVal <= (uint8_t)0xBF)
		{
			// single byte functions
		}*/
		else
		{
			WP5Part *part = WP5Part::constructPart(input, readVal);
			if (part != NULL)
			{
				part->parse(listener);
				DELETEP(part);
			}
		}
	}
}

void WP5Parser::parse(WPXHLListenerImpl *listenerImpl)
{
	WPXInputStream *input = getInput();
	vector<WPXPageSpan *> pageList;
	WPXTableList tableList;

	try
 	{
		// do a "first-pass" parse of the document
		// gather table border information, page properties (per-page)
		WP5HLStylesListener stylesListener(&pageList, &tableList);
		parse(input, &stylesListener);

		// second pass: here is where we actually send the messages to the target app
		// that are necessary to emit the body of the target document
		WP5HLListener listener(&pageList, listenerImpl); // FIXME: SHOULD BE CONTENT_LISTENER, AND SHOULD BE PASSED TABLE DATA!
		parse(input, &listener);

		// cleanup section: free the used resources
		for (vector<WPXPageSpan *>::iterator iterSpan = pageList.begin(); iterSpan != pageList.end(); iterSpan++)
		{
			delete *iterSpan;
		}
	}
	catch(FileException)
	{
		WPD_DEBUG_MSG(("WordPerfect: File Exception. Parse terminated prematurely."));

		for (vector<WPXPageSpan *>::iterator iterSpan = pageList.begin(); iterSpan != pageList.end(); iterSpan++)
		{
			delete *iterSpan;
		}

		throw FileException();
	}
}
<|endoftext|>


<commit_before>#include <QtCore>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include "automator.h"
#include "ansystemdispatcher.h"

#ifdef Q_OS_ANDROID
#include <QtAndroidExtras/QAndroidJniObject>
#include <QtAndroidExtras/QAndroidJniEnvironment>

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
    Q_UNUSED(vm);
    qDebug("NativeInterface::JNI_OnLoad()");

    // It must call this function within JNI_OnLoad to enable System Dispatcher
    ANSystemDispatcher::registerNatives();

    /* Optional: Register your own service */

    // Call quickandroid.example.ExampleService.start()
    QAndroidJniObject::callStaticMethod<void>("quickandroid/example/ExampleService",
                                              "start",
                                              "()V");

    return JNI_VERSION_1_6;
}
#endif

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    engine.addImportPath("qrc:///");
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    /* Testing Code. Not needed for regular project */
    Automator* automator = new Automator();
    automator->start();

    return app.exec();
}
<commit_msg>tests/instrument/activity/main.cpp: Initial AndroidNative::SystemDispatcher<commit_after>#include <QtCore>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include "automator.h"
#include "AndroidNative/systemdispatcher.h"

#ifdef Q_OS_ANDROID
#include <QtAndroidExtras/QAndroidJniObject>
#include <QtAndroidExtras/QAndroidJniEnvironment>

using namespace AndroidNative;

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
    Q_UNUSED(vm);
    qDebug("NativeInterface::JNI_OnLoad()");

    // It must call this function within JNI_OnLoad to enable System Dispatcher
    SystemDispatcher::registerNatives();

    /* Optional: Register your own service */

    // Call quickandroid.example.ExampleService.start()
    QAndroidJniObject::callStaticMethod<void>("quickandroid/example/ExampleService",
                                              "start",
                                              "()V");

    return JNI_VERSION_1_6;
}
#endif

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    engine.addImportPath("qrc:///");
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    /* Testing Code. Not needed for regular project */
    Automator* automator = new Automator();
    automator->start();

    return app.exec();
}
<|endoftext|>


<commit_before>#include <nanosoft/error.h>
#include <nanosoft/xmlparser.h>
#include <iostream>

using namespace std;

namespace nanosoft
{
	/**
	* Конструктор
	*/
	XMLParser::XMLParser(): parsing(false), resetNeed(false)
	{
		initParser();
	}

	/**
	* Деструктор
	*/
	XMLParser::~XMLParser()
	{
		XML_ParserFree(parser);
	}

	/**
	* Инициализация парсера
	*/
	void XMLParser::initParser()
	{
		parser = XML_ParserCreate((XML_Char *) "UTF-8");
		if ( parser == 0 ) error("[XMLParser] XML_ParserCreate() fault");
		XML_SetUserData(parser, (void*) this);
		XML_SetElementHandler(parser, startElementCallback, endElementCallback);
		XML_SetCharacterDataHandler(parser, characterDataCallback);
	}

	/**
	* Парсинг
	* @param buf буфер с данными
	* @param len длина буфера с данными
	* @param isFinal TRUE - последний кусок, FALSE - будет продолжение
	* @return TRUE - успешно, FALSE - ошибка парсинга
	*/
	bool XMLParser::parseXML(const char *buf, size_t len, bool isFinal)
	{
		cout << "\nparse: \033[22;31m" << string(buf, len) << "\033[0m\n";
		parsing = true;
		int r = XML_Parse(parser, buf, len, isFinal);
		parsing = false;
		if ( resetNeed ) realResetParser();
		else if ( ! r )
		{
			onParseError(XML_ErrorString(XML_GetErrorCode(parser)));
			return false;
		}
		return true;
	}

	/**
	* Реальная переинициализация парсера
	*/
	void XMLParser::realResetParser()
	{
		XML_ParserFree(parser);
		initParser();
	}

	/**
	* Сбросить парсер, начать парсить новый поток
	*/
	void XMLParser::resetParser()
	{
		if ( parsing ) resetNeed = true;
		else realResetParser();
	}

	/**
	* Обработчик открытия тега
	*/
	void XMLParser::startElementCallback(void *user_data, const XML_Char *name, const XML_Char **atts)
	{
		attributtes_t attributes;
		for(int i = 0; atts[i]; i += 2) {
			attributes[ atts[i] ] = atts[i + 1];
		}
		static_cast<XMLParser *>(user_data)->onStartElement(name, attributes);
	}

	/**
	* Отработчик символьных данных
	*/
	void XMLParser::characterDataCallback(void *user_data, const XML_Char *s, int len)
	{
		static_cast<XMLParser *>(user_data)->onCharacterData(string(s, len));
	}

	/**
	* Отбработчик закрытия тега
	*/
	void XMLParser::endElementCallback(void *user_data, const XML_Char *name)
	{
		static_cast<XMLParser *>(user_data)->onEndElement(name);
	}
}
<commit_msg>fix: resetNeed = false после сброса парсера<commit_after>#include <nanosoft/error.h>
#include <nanosoft/xmlparser.h>
#include <iostream>

using namespace std;

namespace nanosoft
{
	/**
	* Конструктор
	*/
	XMLParser::XMLParser(): parsing(false), resetNeed(false)
	{
		initParser();
	}

	/**
	* Деструктор
	*/
	XMLParser::~XMLParser()
	{
		XML_ParserFree(parser);
	}

	/**
	* Инициализация парсера
	*/
	void XMLParser::initParser()
	{
		parser = XML_ParserCreate((XML_Char *) "UTF-8");
		if ( parser == 0 ) error("[XMLParser] XML_ParserCreate() fault");
		XML_SetUserData(parser, (void*) this);
		XML_SetElementHandler(parser, startElementCallback, endElementCallback);
		XML_SetCharacterDataHandler(parser, characterDataCallback);
	}

	/**
	* Парсинг
	* @param buf буфер с данными
	* @param len длина буфера с данными
	* @param isFinal TRUE - последний кусок, FALSE - будет продолжение
	* @return TRUE - успешно, FALSE - ошибка парсинга
	*/
	bool XMLParser::parseXML(const char *buf, size_t len, bool isFinal)
	{
		cout << "\nparse: \033[22;31m" << string(buf, len) << "\033[0m\n";
		parsing = true;
		int r = XML_Parse(parser, buf, len, isFinal);
		parsing = false;
		if ( resetNeed ) realResetParser();
		else if ( ! r )
		{
			onParseError(XML_ErrorString(XML_GetErrorCode(parser)));
			return false;
		}
		return true;
	}

	/**
	* Реальная переинициализация парсера
	*/
	void XMLParser::realResetParser()
	{
		XML_ParserFree(parser);
		initParser();
		resetNeed = false;
	}

	/**
	* Сбросить парсер, начать парсить новый поток
	*/
	void XMLParser::resetParser()
	{
		if ( parsing ) resetNeed = true;
		else realResetParser();
	}

	/**
	* Обработчик открытия тега
	*/
	void XMLParser::startElementCallback(void *user_data, const XML_Char *name, const XML_Char **atts)
	{
		attributtes_t attributes;
		for(int i = 0; atts[i]; i += 2) {
			attributes[ atts[i] ] = atts[i + 1];
		}
		static_cast<XMLParser *>(user_data)->onStartElement(name, attributes);
	}

	/**
	* Отработчик символьных данных
	*/
	void XMLParser::characterDataCallback(void *user_data, const XML_Char *s, int len)
	{
		static_cast<XMLParser *>(user_data)->onCharacterData(string(s, len));
	}

	/**
	* Отбработчик закрытия тега
	*/
	void XMLParser::endElementCallback(void *user_data, const XML_Char *name)
	{
		static_cast<XMLParser *>(user_data)->onEndElement(name);
	}
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include <string>
#include <iostream>
#include <fstream>

using namespace std;

bool displayTextFile(const string &dirPath, const string &fileName)
{
    string fullPath = dirPath + fileName;
    ifstream istream(fullPath.c_str());
    if (!istream.is_open()) {
        cout << "Cannot open " << fileName << endl;
        return false;
    }
    cout << "---" << fileName << "---" << endl;
    char buf[256];
    unsigned int i = 1;
    while (istream.good()) {
        istream.getline(buf, sizeof(buf));
        cout << i++ << ": " << buf << endl;
    }
    return true;
}

int main(int, char **argv)
{
    string appPath(argv[0]);
    size_t i = appPath.find_last_of('/');
    if (i == string::npos)
        i = appPath.find_last_of('\\');
    if (i != string::npos)
        appPath.resize(i + 1);
    if (!displayTextFile(appPath, "foo.txt"))
        return 1;
    if (!displayTextFile(appPath, "bar.txt"))
        return 2;
    cout << "-------------" << endl;
    return 0;
}

<commit_msg>Tests: Fix transformer test plain execution on Windows<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include <string>
#include <iostream>
#include <fstream>

using namespace std;

bool displayTextFile(const string &dirPath, const string &fileName)
{
    string fullPath = dirPath + fileName;
    ifstream istream(fullPath.c_str());
    if (!istream.is_open()) {
        cout << "Cannot open " << fileName << endl;
        return false;
    }
    cout << "---" << fileName << "---" << endl;
    char buf[256];
    unsigned int i = 1;
    while (istream.good()) {
        istream.getline(buf, sizeof(buf));
        cout << i++ << ": " << buf << endl;
    }
    return true;
}

int main(int, char **argv)
{
    string appPath(argv[0]);
    size_t i = appPath.find_last_of('/');
    if (i == string::npos)
        i = appPath.find_last_of('\\');
    if (i == string::npos) // No path, plain executable was called
        appPath.clear();
    else
        appPath.resize(i + 1);
    if (!displayTextFile(appPath, "foo.txt"))
        return 1;
    if (!displayTextFile(appPath, "bar.txt"))
        return 2;
    cout << "-------------" << endl;
    return 0;
}

<|endoftext|>