<commit_before>#include "physics.h"
#include "GLDebugDrawer.h"
#include "../state/state.h"
#include <iostream>
#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
#include <BulletCollision/CollisionShapes/btTriangleShape.h>
#include <btBulletDynamicsCommon.h>

using namespace Physics;

Simulation::Simulation()
{
	m_broadphase = new btDbvtBroadphase();
	m_collisionConfiguration = new btDefaultCollisionConfiguration();
	m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
	m_solver = new btSequentialImpulseConstraintSolver;
	m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);

	m_world->setGravity(btVector3(0,-5,0));

	mb.request(Events::EventType::Input);
}

Simulation::~Simulation()
{
	/*
	delete m_world;
	delete m_solver;
	delete m_broadphase;
	delete m_dispatcher;
	delete m_collisionConfiguration;
	*/
}

// Tuning
// Credit to:
// http://bullet.googlecode.com/svn-history/r2704/trunk/Demos/ForkLiftDemo/ForkLiftDemo.cpp
// Also:
// https://code.google.com/p/bullet/source/browse/trunk/Demos/VehicleDemo/VehicleDemo.cpp

float	gVehicleSteering = 0.0f;
float	gEngineForce = 0.0f;
float	gBrakingForce = 0.0f;

float	wheelFriction = 5;
float	suspensionStiffness = 10;
float	suspensionDamping = 0.5f;
float	suspensionCompression = 0.3f;
float	rollInfluence = 0.015f; // Keep low to prevent car flipping

btScalar suspensionRestLength(0.1f);// Suspension Interval = rest +/- travel * 0.01
float	suspensionTravelcm = 20;

btRigidBody *Simulation::addRigidBody(double mass, const btTransform& startTransform, btCollisionShape* shape)
{
	btVector3 localInertia(0, 0, 0);
	if (mass != 0.0) {
		shape->calculateLocalInertia((btScalar)mass, localInertia);
	}

	btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);

	btRigidBody::btRigidBodyConstructionInfo cInfo((btScalar)mass,myMotionState,shape,localInertia);

	btRigidBody* body = new btRigidBody(cInfo);
	body->setContactProcessingThreshold(0.1f);

	m_world->addRigidBody(body);

	return body;
}

static bool CustomMaterialCombinerCallback(btManifoldPoint& cp,	const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
{
	btAdjustInternalEdgeContacts(cp,colObj1Wrap,colObj0Wrap, partId1,index1);
	return true;
}

extern ContactAddedCallback gContactAddedCallback;

int Simulation::loadWorld()
{
	// Create car
#define CAR_WIDTH (0.11f)
#define CAR_LENGTH (0.15f)
#define CAR_MASS (800.0f)

	btCollisionShape* chassisShape = new btBoxShape(btVector3(CAR_WIDTH, CAR_WIDTH, CAR_LENGTH));
	btCompoundShape* compound = new btCompoundShape();
	m_collisionShapes.push_back(chassisShape);
	m_collisionShapes.push_back(compound);

	btTransform localTrans;
	localTrans.setIdentity();
	localTrans.setOrigin(btVector3(0,0.05f, 0));
	compound->addChildShape(localTrans, chassisShape);

	btTransform tr;
	tr.setIdentity();
	tr.setOrigin(btVector3(0,2,0));		// This sets where the car initially spawns
	m_carChassis = addRigidBody(CAR_MASS, tr, compound);

	m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_world);

	m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis, m_vehicleRayCaster);
	m_carChassis->setActivationState(DISABLE_DEACTIVATION);
	m_vehicle->setCoordinateSystem(0,1,0);
	m_world->addVehicle(m_vehicle);

	float connectionHeight = 0.10f;
	btVector3 wheelDirectionCS0(0,-1,0);
	btVector3 wheelAxleCS(-1,0,0);

#define CON1 (CAR_WIDTH)
#define CON2 (CAR_LENGTH)

	float	wheelRadius = 0.15f;

	// Setup front 2 wheels
	bool isFrontWheel=true;
	btVector3 connectionPointCS0(CON1,connectionHeight,CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	connectionPointCS0 = btVector3(-CON1,connectionHeight,CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	// Setup rear  2 wheels
	isFrontWheel = false;

	connectionPointCS0 = btVector3(-CON1,connectionHeight,-CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	connectionPointCS0 = btVector3(CON1,connectionHeight,-CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	for (int i=0;i<m_vehicle->getNumWheels();i++)
	{
		btWheelInfo& wheel = m_vehicle->getWheelInfo(i);

		wheel.m_maxSuspensionTravelCm = suspensionTravelcm;
		wheel.m_suspensionStiffness = suspensionStiffness;
		wheel.m_wheelsDampingRelaxation = suspensionDamping;
		wheel.m_wheelsDampingCompression = suspensionCompression;
		wheel.m_frictionSlip = wheelFriction;
		wheel.m_rollInfluence = rollInfluence;

	}

	// Add map
	// Credit to http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6662
	// for solution to wheels bouncing off triangle edges
	gContactAddedCallback = CustomMaterialCombinerCallback;
	StateData *state = GetMutState();
	btBvhTriangleMeshShape *arenaShape = new btBvhTriangleMeshShape(state->bttmArena, true, true);

	m_arena = addRigidBody(0.0, btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)), arenaShape);
	m_arena->setCollisionFlags(m_arena->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
	btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap();
	btGenerateInternalEdgeInfo(arenaShape, triangleInfoMap);

	for (int i=0;i<m_vehicle->getNumWheels();i++)
	{
		//synchronize the wheels with the (interpolated) chassis worldtransform
		m_vehicle->updateWheelTransform(i,true);
	}

	return 0;
}

void Simulation::step(double seconds)
{
#define STEER_MAX_ANGLE (25)
#define ENGINE_MAX_FORCE (1500)
#define BRAKE_MAX_FORCE (1000)
#define E_BRAKE_FORCE (200)
#define MAX_SPEED (25.0)

	for ( Events::Event *event : (mb.checkMail()) )
	{
		switch ( event->type )
		{
		case Events::EventType::Input:
		{
			Events::InputEvent *input = (Events::InputEvent *)event;

			Real fTurnSqr = pow(input->leftThumbStickRL, 8);
			gVehicleSteering = DEGTORAD(STEER_MAX_ANGLE) * ( input->leftThumbStickRL < 0 ? -fTurnSqr : fTurnSqr );

			gBrakingForce = input->bPressed ? E_BRAKE_FORCE : 0;
			gEngineForce = ENGINE_MAX_FORCE * input->rightTrigger - BRAKE_MAX_FORCE * input->leftTrigger;

			if( GetState().key_map['r'] )
			{
				btTransform trans;
				trans.setOrigin( btVector3( 0, 5, 0 ) );
				trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
				m_vehicle->getRigidBody()->setWorldTransform( trans );
				m_vehicle->getRigidBody()->setLinearVelocity(btVector3(0,0,0));
			}

			if( input->yPressed )
			{
				btTransform trans = m_vehicle->getRigidBody()->getWorldTransform();
				btVector3 orig = trans.getOrigin();
				orig.setY( orig.getY() + 0.01f );
				trans.setOrigin( orig );
				trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
				m_vehicle->getRigidBody()->setWorldTransform( trans );
			}

//			DEBUGOUT("Bforce: %lf, Eforce: %lf, Steer: %f\n", gBrakingForce, gEngineForce, gVehicleSteering);
//			DEBUGOUT("Speed: %f\n", (float)ABS( m_vehicle->getCurrentSpeedKmHour() ) );
		}
		default:
			break;
		}
	}
	mb.emptyMail();

	if( ABS( m_vehicle->getCurrentSpeedKmHour() ) > MAX_SPEED )
		gEngineForce = 0;

	// Apply steering to front wheels
	m_vehicle->setSteeringValue(gVehicleSteering, 0);
	m_vehicle->setSteeringValue(gVehicleSteering, 1);

	// Apply braking and engine force to rear wheels
	m_vehicle->applyEngineForce(gEngineForce, 0);
	m_vehicle->applyEngineForce(gEngineForce, 1);
	m_vehicle->setBrake(gBrakingForce, 2);
	m_vehicle->setBrake(gBrakingForce, 3);

	m_world->stepSimulation((btScalar)seconds, 10);

	if( m_vehicle->getRigidBody()->getWorldTransform().getOrigin().y() < -1.0f )
	{
		btTransform trans;
		trans.setOrigin( btVector3( 0, 5, 0 ) );
		trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
		m_vehicle->getRigidBody()->setWorldTransform( trans );
		m_vehicle->getRigidBody()->setLinearVelocity(btVector3(0,0,0));
	}

	UpdateGameState(seconds);
}

// Updates the car placement in the world state
void Simulation::UpdateGameState(double seconds)
{
	// -- Kart position ------------------------
	StateData *state = GetMutState();
	btTransform car1 = m_vehicle->getChassisWorldTransform();

	btVector3 pos = car1.getOrigin();
	state->Karts[0].vPos.x = (Real)pos.getX();
	state->Karts[0].vPos.y = (Real)pos.getY();
	state->Karts[0].vPos.z = (Real)pos.getZ();

	btQuaternion rot = car1.getRotation();
	state->Karts[0].qOrient.x = (Real)rot.getX();
	state->Karts[0].qOrient.y = (Real)rot.getY();
	state->Karts[0].qOrient.z = (Real)rot.getZ();
	state->Karts[0].qOrient.w = (Real)-rot.getW();

	// -- Chase Cam ----------------------------
	// Get car direction
	btVector3 dir = m_vehicle->getForwardVector() / m_vehicle->getForwardVector().length();
	btVector3 camera = dir.rotate(btVector3(0,1,0), DEGTORAD(90)); // forward vector points left, somehow

	if (camera.getY() < 0.4) {
		camera.setY(0.4);
	}

	// Mixin car direction history
	Real DIR_DROPOFF = 3 * seconds;
	static btVector3 dir_history = camera;
	dir_history *= (1.0 - DIR_DROPOFF);
	dir_history += camera * DIR_DROPOFF;

	camera = dir_history;

	// Mixin historic speeds
	Real SPEED_DROPOFF = 0.1 * seconds;
	Real speed = m_vehicle->getCurrentSpeedKmHour();
	static Real speed_history = speed;
	speed_history *= (1.0 - SPEED_DROPOFF);
	speed_history += speed * SPEED_DROPOFF;

	// Make camera focus during acceleration
	Real diff = (speed - speed_history) / MAX_SPEED;
	diff = diff > 0.0 ? diff : 0;
	diff *= diff;
	diff = (pow(2, diff) - 1) / 1;
	diff = MIN(diff, 0.3);
	Real DIFF_DROPOFF = 0.1;
	static Real diff_history = diff * seconds;
	if (diff > 0.0) {
		diff_history *= (1.0 - DIFF_DROPOFF);
		diff_history += diff * DIFF_DROPOFF;
	}
	diff = diff_history;

	camera.setY((0.9 * (1 - MAX((diff * 3.7), 0.7)) + camera.getY()));
	camera *= 3.0 - diff * 1;
	state->Camera.fFOV = 60.0f * (1 - diff * 1.4);

	// Add camera vector to kart position for camera position
	state->Camera.vPos = state->Karts[0].vPos;
	state->Camera.vPos.x += camera.getX();
	state->Camera.vPos.y += camera.getY();
	state->Camera.vPos.z += camera.getZ();

	// Focus on car
	btVector3 chase = dir.rotate(btVector3(0,1,0), DEGTORAD(-90)); // forward vector points left, somehow
	chase.setY(0);
	btVector3 focus = pos + chase * (2.0 + speed_history * 6 * (diff -0.1));
	Real FOCUS_DROPOFF = seconds * 3;
	FOCUS_DROPOFF = MIN(FOCUS_DROPOFF, 1);
	static btVector3 focus_history = focus;
	focus_history *= (1 - FOCUS_DROPOFF);
	focus_history += focus * FOCUS_DROPOFF;
	state->Camera.vFocus.x = focus_history.getX();
	state->Camera.vFocus.y = focus_history.getY();
	state->Camera.vFocus.z = focus_history.getZ();
}

void Simulation::enableDebugView()
{
}
<commit_msg>Fix car traveling to screen top during tight turns<commit_after>#include "physics.h"
#include "GLDebugDrawer.h"
#include "../state/state.h"
#include <iostream>
#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
#include <BulletCollision/CollisionShapes/btTriangleShape.h>
#include <btBulletDynamicsCommon.h>

using namespace Physics;

Simulation::Simulation()
{
	m_broadphase = new btDbvtBroadphase();
	m_collisionConfiguration = new btDefaultCollisionConfiguration();
	m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
	m_solver = new btSequentialImpulseConstraintSolver;
	m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);

	m_world->setGravity(btVector3(0,-5,0));

	mb.request(Events::EventType::Input);
}

Simulation::~Simulation()
{
	/*
	delete m_world;
	delete m_solver;
	delete m_broadphase;
	delete m_dispatcher;
	delete m_collisionConfiguration;
	*/
}

// Tuning
// Credit to:
// http://bullet.googlecode.com/svn-history/r2704/trunk/Demos/ForkLiftDemo/ForkLiftDemo.cpp
// Also:
// https://code.google.com/p/bullet/source/browse/trunk/Demos/VehicleDemo/VehicleDemo.cpp

float	gVehicleSteering = 0.0f;
float	gEngineForce = 0.0f;
float	gBrakingForce = 0.0f;

float	wheelFriction = 5;
float	suspensionStiffness = 10;
float	suspensionDamping = 0.5f;
float	suspensionCompression = 0.3f;
float	rollInfluence = 0.015f; // Keep low to prevent car flipping

btScalar suspensionRestLength(0.1f);// Suspension Interval = rest +/- travel * 0.01
float	suspensionTravelcm = 20;

btRigidBody *Simulation::addRigidBody(double mass, const btTransform& startTransform, btCollisionShape* shape)
{
	btVector3 localInertia(0, 0, 0);
	if (mass != 0.0) {
		shape->calculateLocalInertia((btScalar)mass, localInertia);
	}

	btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);

	btRigidBody::btRigidBodyConstructionInfo cInfo((btScalar)mass,myMotionState,shape,localInertia);

	btRigidBody* body = new btRigidBody(cInfo);
	body->setContactProcessingThreshold(0.1f);

	m_world->addRigidBody(body);

	return body;
}

static bool CustomMaterialCombinerCallback(btManifoldPoint& cp,	const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
{
	btAdjustInternalEdgeContacts(cp,colObj1Wrap,colObj0Wrap, partId1,index1);
	return true;
}

extern ContactAddedCallback gContactAddedCallback;

int Simulation::loadWorld()
{
	// Create car
#define CAR_WIDTH (0.11f)
#define CAR_LENGTH (0.15f)
#define CAR_MASS (800.0f)

	btCollisionShape* chassisShape = new btBoxShape(btVector3(CAR_WIDTH, CAR_WIDTH, CAR_LENGTH));
	btCompoundShape* compound = new btCompoundShape();
	m_collisionShapes.push_back(chassisShape);
	m_collisionShapes.push_back(compound);

	btTransform localTrans;
	localTrans.setIdentity();
	localTrans.setOrigin(btVector3(0,0.05f, 0));
	compound->addChildShape(localTrans, chassisShape);

	btTransform tr;
	tr.setIdentity();
	tr.setOrigin(btVector3(0,2,0));		// This sets where the car initially spawns
	m_carChassis = addRigidBody(CAR_MASS, tr, compound);

	m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_world);

	m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis, m_vehicleRayCaster);
	m_carChassis->setActivationState(DISABLE_DEACTIVATION);
	m_vehicle->setCoordinateSystem(0,1,0);
	m_world->addVehicle(m_vehicle);

	float connectionHeight = 0.10f;
	btVector3 wheelDirectionCS0(0,-1,0);
	btVector3 wheelAxleCS(-1,0,0);

#define CON1 (CAR_WIDTH)
#define CON2 (CAR_LENGTH)

	float	wheelRadius = 0.15f;

	// Setup front 2 wheels
	bool isFrontWheel=true;
	btVector3 connectionPointCS0(CON1,connectionHeight,CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	connectionPointCS0 = btVector3(-CON1,connectionHeight,CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	// Setup rear  2 wheels
	isFrontWheel = false;

	connectionPointCS0 = btVector3(-CON1,connectionHeight,-CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	connectionPointCS0 = btVector3(CON1,connectionHeight,-CON2);
	m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);

	for (int i=0;i<m_vehicle->getNumWheels();i++)
	{
		btWheelInfo& wheel = m_vehicle->getWheelInfo(i);

		wheel.m_maxSuspensionTravelCm = suspensionTravelcm;
		wheel.m_suspensionStiffness = suspensionStiffness;
		wheel.m_wheelsDampingRelaxation = suspensionDamping;
		wheel.m_wheelsDampingCompression = suspensionCompression;
		wheel.m_frictionSlip = wheelFriction;
		wheel.m_rollInfluence = rollInfluence;

	}

	// Add map
	// Credit to http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6662
	// for solution to wheels bouncing off triangle edges
	gContactAddedCallback = CustomMaterialCombinerCallback;
	StateData *state = GetMutState();
	btBvhTriangleMeshShape *arenaShape = new btBvhTriangleMeshShape(state->bttmArena, true, true);

	m_arena = addRigidBody(0.0, btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)), arenaShape);
	m_arena->setCollisionFlags(m_arena->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
	btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap();
	btGenerateInternalEdgeInfo(arenaShape, triangleInfoMap);

	for (int i=0;i<m_vehicle->getNumWheels();i++)
	{
		//synchronize the wheels with the (interpolated) chassis worldtransform
		m_vehicle->updateWheelTransform(i,true);
	}

	return 0;
}

void Simulation::step(double seconds)
{
#define STEER_MAX_ANGLE (25)
#define ENGINE_MAX_FORCE (1500)
#define BRAKE_MAX_FORCE (1000)
#define E_BRAKE_FORCE (200)
#define MAX_SPEED (25.0)

	for ( Events::Event *event : (mb.checkMail()) )
	{
		switch ( event->type )
		{
		case Events::EventType::Input:
		{
			Events::InputEvent *input = (Events::InputEvent *)event;

			Real fTurnSqr = pow(input->leftThumbStickRL, 8);
			gVehicleSteering = DEGTORAD(STEER_MAX_ANGLE) * ( input->leftThumbStickRL < 0 ? -fTurnSqr : fTurnSqr );

			gBrakingForce = input->bPressed ? E_BRAKE_FORCE : 0;
			gEngineForce = ENGINE_MAX_FORCE * input->rightTrigger - BRAKE_MAX_FORCE * input->leftTrigger;

			if( GetState().key_map['r'] )
			{
				btTransform trans;
				trans.setOrigin( btVector3( 0, 5, 0 ) );
				trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
				m_vehicle->getRigidBody()->setWorldTransform( trans );
				m_vehicle->getRigidBody()->setLinearVelocity(btVector3(0,0,0));
			}

			if( input->yPressed )
			{
				btTransform trans = m_vehicle->getRigidBody()->getWorldTransform();
				btVector3 orig = trans.getOrigin();
				orig.setY( orig.getY() + 0.01f );
				trans.setOrigin( orig );
				trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
				m_vehicle->getRigidBody()->setWorldTransform( trans );
			}

//			DEBUGOUT("Bforce: %lf, Eforce: %lf, Steer: %f\n", gBrakingForce, gEngineForce, gVehicleSteering);
//			DEBUGOUT("Speed: %f\n", (float)ABS( m_vehicle->getCurrentSpeedKmHour() ) );
		}
		default:
			break;
		}
	}
	mb.emptyMail();

	if( ABS( m_vehicle->getCurrentSpeedKmHour() ) > MAX_SPEED )
		gEngineForce = 0;

	// Apply steering to front wheels
	m_vehicle->setSteeringValue(gVehicleSteering, 0);
	m_vehicle->setSteeringValue(gVehicleSteering, 1);

	// Apply braking and engine force to rear wheels
	m_vehicle->applyEngineForce(gEngineForce, 0);
	m_vehicle->applyEngineForce(gEngineForce, 1);
	m_vehicle->setBrake(gBrakingForce, 2);
	m_vehicle->setBrake(gBrakingForce, 3);

	m_world->stepSimulation((btScalar)seconds, 10);

	if( m_vehicle->getRigidBody()->getWorldTransform().getOrigin().y() < -1.0f )
	{
		btTransform trans;
		trans.setOrigin( btVector3( 0, 5, 0 ) );
		trans.setRotation( btQuaternion( 0, 0, 0, 1 ) );
		m_vehicle->getRigidBody()->setWorldTransform( trans );
		m_vehicle->getRigidBody()->setLinearVelocity(btVector3(0,0,0));
	}

	UpdateGameState(seconds);
}

// Updates the car placement in the world state
void Simulation::UpdateGameState(double seconds)
{
	// -- Kart position ------------------------
	StateData *state = GetMutState();
	btTransform car1 = m_vehicle->getChassisWorldTransform();

	btVector3 pos = car1.getOrigin();
	state->Karts[0].vPos.x = (Real)pos.getX();
	state->Karts[0].vPos.y = (Real)pos.getY();
	state->Karts[0].vPos.z = (Real)pos.getZ();

	btQuaternion rot = car1.getRotation();
	state->Karts[0].qOrient.x = (Real)rot.getX();
	state->Karts[0].qOrient.y = (Real)rot.getY();
	state->Karts[0].qOrient.z = (Real)rot.getZ();
	state->Karts[0].qOrient.w = (Real)-rot.getW();

	// -- Chase Cam ----------------------------
	// Note: I cannot explain these numbers

	// Get car direction
	btVector3 dir = m_vehicle->getForwardVector() / m_vehicle->getForwardVector().length();
	btVector3 camera = dir.rotate(btVector3(0,1,0), DEGTORAD(90)); // forward vector points left, somehow

	if (camera.getY() < 0.4) {
		camera.setY(0.4);
	}

	// Mixin car direction history
	Real DIR_DROPOFF = 3 * seconds;
	static btVector3 dir_history = camera;
	dir_history *= (1.0 - DIR_DROPOFF);
	dir_history += camera * DIR_DROPOFF;

	camera = dir_history;

	// Mixin historic speeds
	Real SPEED_DROPOFF = 0.1 * seconds;
	Real speed = m_vehicle->getCurrentSpeedKmHour();
	static Real speed_history = speed;
	speed_history *= (1.0 - SPEED_DROPOFF);
	speed_history += speed * SPEED_DROPOFF;

	// Make camera focus during acceleration
	Real diff = (speed - speed_history) / MAX_SPEED;
	diff = diff > 0.0 ? diff : diff / 2;
	diff *= diff;
	diff = (pow(2, diff) - 1) / 1;
	diff = MIN(diff, 0.3);
	Real DIFF_DROPOFF = 0.1;
	static Real diff_history = diff * seconds;
	if (diff > 0.0) {
		diff_history *= (1.0 - DIFF_DROPOFF);
		diff_history += diff * DIFF_DROPOFF;
	}
	diff = diff_history;

	camera.setY(0.1 * (1 - MIN(speed_history , 1)) + camera.getY());
	camera *= 3.0 - diff * 1;
	state->Camera.fFOV = 60.0f * (1 - diff * 1.1);

	// Add camera vector to kart position for camera position
	state->Camera.vPos = state->Karts[0].vPos;
	state->Camera.vPos.x += camera.getX();
	state->Camera.vPos.y += camera.getY();
	state->Camera.vPos.z += camera.getZ();

	// Focus on car
	btVector3 chase = dir.rotate(btVector3(0,1,0), DEGTORAD(-90)); // forward vector points left, somehow
	chase.setY(0);
	btVector3 focus = pos + chase * (1.5 + speed_history * 5 * diff);
	Real FOCUS_DROPOFF = seconds * 3;
	FOCUS_DROPOFF = MIN(FOCUS_DROPOFF, 1);
	static btVector3 focus_history = focus;
	focus_history *= (1 - FOCUS_DROPOFF);
	focus_history += focus * FOCUS_DROPOFF;
	state->Camera.vFocus.x = focus_history.getX();
	state->Camera.vFocus.y = focus_history.getY();
	state->Camera.vFocus.z = focus_history.getZ();
}

void Simulation::enableDebugView()
{
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file UPnP.cpp
 * @authors:
 *   Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "UPnP.h"

#include <stdio.h>
#include <string.h>
#if ETH_MINIUPNPC
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#endif
#include <libdevcore/Exceptions.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;

UPnP::UPnP()
{
#if ETH_MINIUPNPC
	m_urls.reset(new UPNPUrls);
	m_data.reset(new IGDdatas);

	m_ok = false;

	struct UPNPDev* devlist;
	struct UPNPDev* dev;
	char* descXML;
	int descXMLsize = 0;
	int upnperror = 0;
	memset(m_urls.get(), 0, sizeof(struct UPNPUrls));
	memset(m_data.get(), 0, sizeof(struct IGDdatas));
	devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, &upnperror);
	if (devlist)
	{
		dev = devlist;
		while (dev)
		{
			if (strstr (dev->st, "InternetGatewayDevice"))
				break;
			dev = dev->pNext;
		}
		if (!dev)
			dev = devlist; /* defaulting to first device */

		cnote << "UPnP device:" << dev->descURL << "[st:" << dev->st << "]";
#if MINIUPNPC_API_VERSION >= 9
		descXML = (char*)miniwget(dev->descURL, &descXMLsize, 0);
#else
		descXML = (char*)miniwget(dev->descURL, &descXMLsize);
#endif
		if (descXML)
		{
			parserootdesc (descXML, descXMLsize, m_data.get());
			free (descXML); descXML = 0;
#if MINIUPNPC_API_VERSION >= 9
			GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL, 0);
#else
			GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL);
#endif
			m_ok = true;
		}
		freeUPNPDevlist(devlist);
	}
	else
#endif
	{
		cnote << "UPnP device not found.";
		BOOST_THROW_EXCEPTION(NoUPnPDevice());
	}
}

UPnP::~UPnP()
{
	auto r = m_reg;
	for (auto i: r)
		removeRedirect(i);
}

string UPnP::externalIP()
{
#if ETH_MINIUPNPC
	char addr[16];
	if (!UPNP_GetExternalIPAddress(m_urls->controlURL, m_data->first.servicetype, addr))
		return addr;
	else
#endif
		return "0.0.0.0";
}

int UPnP::addRedirect(char const* _addr, int _port)
{
	(void)_addr;
	(void)_port;
#if ETH_MINIUPNPC
	if (m_urls->controlURL[0] == '\0')
	{
		cwarn << "UPnP::addRedirect() called without proper initialisation?";
		return -1;
	}

	// Try direct mapping first (port external, port internal).
	char port_str[16];
	char ext_port_str[16];
	sprintf(port_str, "%d", _port);
	if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
		return _port;

	// Failed - now try (random external, port internal) and cycle up to 10 times.
	srand(time(NULL));
	for (unsigned i = 0; i < 10; ++i)
	{
		_port = rand() % (65535 - 1024) + 1024;
		sprintf(ext_port_str, "%d", _port);
		if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, ext_port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
			return _port;
	}

	// Failed. Try asking the router to give us a free external port.
	if (UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, NULL, _addr, "ethereum", "TCP", NULL, NULL))
		// Failed. Exit.
		return 0;

	// We got mapped, but we don't know which ports we got mapped to. Now to find...
	unsigned num = 0;
	UPNP_GetPortMappingNumberOfEntries(m_urls->controlURL, m_data->first.servicetype, &num);
	for (unsigned i = 0; i < num; ++i)
	{
		char extPort[16];
		char intClient[16];
		char intPort[6];
		char protocol[4];
		char desc[80];
		char enabled[4];
		char rHost[64];
		char duration[16];
		UPNP_GetGenericPortMappingEntry(m_urls->controlURL, m_data->first.servicetype, toString(i).c_str(), extPort, intClient, intPort, protocol, desc, enabled, rHost, duration);
		if (string("ethereum") == desc)
		{
			m_reg.insert(atoi(extPort));
			return atoi(extPort);
		}
	}
	cerr << "ERROR: Mapped port not found." << endl;
#endif
	return 0;
}

void UPnP::removeRedirect(int _port)
{
	(void)_port;
#if ETH_MINIUPNPC
	char port_str[16];
//		int t;
	printf("TB : upnp_rem_redir (%d)\n", _port);
	if (m_urls->controlURL[0] == '\0')
	{
		printf("TB : the init was not done !\n");
		return;
	}
	sprintf(port_str, "%d", _port);
	UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL);
	m_reg.erase(_port);
#endif
}
<commit_msg>remove private ports from upnp port range<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file UPnP.cpp
 * @authors:
 *   Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "UPnP.h"

#include <stdio.h>
#include <string.h>
#if ETH_MINIUPNPC
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#endif
#include <libdevcore/Exceptions.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;

UPnP::UPnP()
{
#if ETH_MINIUPNPC
	m_urls.reset(new UPNPUrls);
	m_data.reset(new IGDdatas);

	m_ok = false;

	struct UPNPDev* devlist;
	struct UPNPDev* dev;
	char* descXML;
	int descXMLsize = 0;
	int upnperror = 0;
	memset(m_urls.get(), 0, sizeof(struct UPNPUrls));
	memset(m_data.get(), 0, sizeof(struct IGDdatas));
	devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, &upnperror);
	if (devlist)
	{
		dev = devlist;
		while (dev)
		{
			if (strstr (dev->st, "InternetGatewayDevice"))
				break;
			dev = dev->pNext;
		}
		if (!dev)
			dev = devlist; /* defaulting to first device */

		cnote << "UPnP device:" << dev->descURL << "[st:" << dev->st << "]";
#if MINIUPNPC_API_VERSION >= 9
		descXML = (char*)miniwget(dev->descURL, &descXMLsize, 0);
#else
		descXML = (char*)miniwget(dev->descURL, &descXMLsize);
#endif
		if (descXML)
		{
			parserootdesc (descXML, descXMLsize, m_data.get());
			free (descXML); descXML = 0;
#if MINIUPNPC_API_VERSION >= 9
			GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL, 0);
#else
			GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL);
#endif
			m_ok = true;
		}
		freeUPNPDevlist(devlist);
	}
	else
#endif
	{
		cnote << "UPnP device not found.";
		BOOST_THROW_EXCEPTION(NoUPnPDevice());
	}
}

UPnP::~UPnP()
{
	auto r = m_reg;
	for (auto i: r)
		removeRedirect(i);
}

string UPnP::externalIP()
{
#if ETH_MINIUPNPC
	char addr[16];
	if (!UPNP_GetExternalIPAddress(m_urls->controlURL, m_data->first.servicetype, addr))
		return addr;
	else
#endif
		return "0.0.0.0";
}

int UPnP::addRedirect(char const* _addr, int _port)
{
	(void)_addr;
	(void)_port;
#if ETH_MINIUPNPC
	if (m_urls->controlURL[0] == '\0')
	{
		cwarn << "UPnP::addRedirect() called without proper initialisation?";
		return -1;
	}

	// Try direct mapping first (port external, port internal).
	char port_str[16];
	char ext_port_str[16];
	sprintf(port_str, "%d", _port);
	if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
		return _port;

	// Failed - now try (random external, port internal) and cycle up to 10 times.
	srand(time(NULL));
	for (unsigned i = 0; i < 10; ++i)
	{
		_port = rand() % (32768 - 1024) + 1024;
		sprintf(ext_port_str, "%d", _port);
		if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, ext_port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
			return _port;
	}

	// Failed. Try asking the router to give us a free external port.
	if (UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, NULL, _addr, "ethereum", "TCP", NULL, NULL))
		// Failed. Exit.
		return 0;

	// We got mapped, but we don't know which ports we got mapped to. Now to find...
	unsigned num = 0;
	UPNP_GetPortMappingNumberOfEntries(m_urls->controlURL, m_data->first.servicetype, &num);
	for (unsigned i = 0; i < num; ++i)
	{
		char extPort[16];
		char intClient[16];
		char intPort[6];
		char protocol[4];
		char desc[80];
		char enabled[4];
		char rHost[64];
		char duration[16];
		UPNP_GetGenericPortMappingEntry(m_urls->controlURL, m_data->first.servicetype, toString(i).c_str(), extPort, intClient, intPort, protocol, desc, enabled, rHost, duration);
		if (string("ethereum") == desc)
		{
			m_reg.insert(atoi(extPort));
			return atoi(extPort);
		}
	}
	cerr << "ERROR: Mapped port not found." << endl;
#endif
	return 0;
}

void UPnP::removeRedirect(int _port)
{
	(void)_port;
#if ETH_MINIUPNPC
	char port_str[16];
//		int t;
	printf("TB : upnp_rem_redir (%d)\n", _port);
	if (m_urls->controlURL[0] == '\0')
	{
		printf("TB : the init was not done !\n");
		return;
	}
	sprintf(port_str, "%d", _port);
	UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL);
	m_reg.erase(_port);
#endif
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_LAZY_ENTRY_HPP_INCLUDED
#define TORRENT_LAZY_ENTRY_HPP_INCLUDED

#include <utility>
#include <vector>
#include <string>
#include <cstring>
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/size_type.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{
	struct lazy_entry;

	TORRENT_EXPORT char const* parse_int(char const* start, char const* end
		, char delimiter, boost::int64_t& val);
	// return 0 = success
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit = 1000);

	struct pascal_string
	{
		pascal_string(char const* p, int l): len(l), ptr(p) {}
		int len;
		char const* ptr;
		bool operator<(pascal_string const& rhs) const
		{
			return std::memcmp(ptr, rhs.ptr, (std::min)(len, rhs.len)) < 0
				|| len < rhs.len;
		}
	};

	struct lazy_dict_entry;

	struct TORRENT_EXPORT lazy_entry
	{
		enum entry_type_t
		{
			none_t, dict_t, list_t, string_t, int_t
		};

		lazy_entry() : m_type(none_t), m_begin(0), m_end(0)
		{ m_data.start = 0; }

		entry_type_t type() const { return m_type; }

		// start points to the first decimal digit
		// length is the number of digits
		void construct_int(char const* start, int length)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = int_t;
			m_data.start = start;
			m_size = length;
			m_begin = start - 1; // include 'i'
			m_end = start + length + 1; // include 'e'
		}

		size_type int_value() const;

		// string functions
		// ================

		void construct_string(char const* start, int length);

		// the string is not null-terminated!
		char const* string_ptr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return m_data.start;
		}

		// this will return a null terminated string
		// it will write to the source buffer!
		char const* string_cstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			const_cast<char*>(m_data.start)[m_size] = 0;
			return m_data.start;
		}

		pascal_string string_pstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return pascal_string(m_data.start, m_size);
		}

		std::string string_value() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return std::string(m_data.start, m_size);
		}

		int string_length() const
		{ return m_size; }

		// dictionary functions
		// ====================

		void construct_dict(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = dict_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* dict_append(char const* name);
		lazy_entry* dict_find(char const* name);
		lazy_entry const* dict_find(char const* name) const
		{ return const_cast<lazy_entry*>(this)->dict_find(name); }

		std::string dict_find_string_value(char const* name) const;
		pascal_string dict_find_pstr(char const* name) const;
		size_type dict_find_int_value(char const* name, size_type default_val = 0) const;
		lazy_entry const* dict_find_dict(char const* name) const;
		lazy_entry const* dict_find_list(char const* name) const;
		lazy_entry const* dict_find_string(char const* name) const;
		lazy_entry const* dict_find_int(char const* name) const;

		std::pair<std::string, lazy_entry const*> dict_at(int i) const;

		int dict_size() const
		{
			TORRENT_ASSERT(m_type == dict_t);
			return m_size;
		}

		// list functions
		// ==============

		void construct_list(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = list_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* list_append();
		lazy_entry* list_at(int i)
		{
			TORRENT_ASSERT(m_type == list_t);
			TORRENT_ASSERT(i < m_size);
			return &m_data.list[i];
		}
		lazy_entry const* list_at(int i) const
		{ return const_cast<lazy_entry*>(this)->list_at(i); }

		std::string list_string_value_at(int i) const;
		pascal_string list_pstr_at(int i) const;
		size_type list_int_value_at(int i, size_type default_val = 0) const;

		int list_size() const
		{
			TORRENT_ASSERT(m_type == list_t);
			return m_size;
		}

		// end points one byte passed last byte
		void set_end(char const* end)
		{
			TORRENT_ASSERT(end > m_begin);
			m_end = end;
		}

		void clear();

		// releases ownership of any memory allocated
		void release()
		{
			m_data.start = 0;
			m_size = 0;
			m_capacity = 0;
			m_type = none_t;
		}

		~lazy_entry()
		{ clear(); }

		// returns pointers into the source buffer where
		// this entry has its bencoded data
		std::pair<char const*, int> data_section() const;

		void swap(lazy_entry& e)
		{
			using std::swap;
			swap(m_type, e.m_type);
			swap(m_data.start, e.m_data.start);
			swap(m_size, e.m_size);
			swap(m_capacity, e.m_capacity);
			swap(m_begin, e.m_begin);
			swap(m_end, e.m_end);
		}

	private:

		entry_type_t m_type;
		union data_t
		{
			lazy_dict_entry* dict;
			lazy_entry* list;
			char const* start;
		} m_data;

		int m_size; // if list or dictionary, the number of items
		int m_capacity; // if list or dictionary, allocated number of items
		// used for dictionaries and lists to record the range
		// in the original buffer they are based on
		char const* m_begin;
		char const* m_end;

		// non-copyable
		lazy_entry(lazy_entry const&);
		lazy_entry const& operator=(lazy_entry const&);
	};

	struct lazy_dict_entry
	{
		char const* name;
		lazy_entry val;
	};

	TORRENT_EXPORT std::string print_entry(lazy_entry const& e, bool single_line = false);
#if TORRENT_USE_IOSTREAM
	TORRENT_EXPORT std::ostream& operator<<(std::ostream& os, lazy_entry const& e);
#endif

}

#endif

<commit_msg>and this goes with it<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_LAZY_ENTRY_HPP_INCLUDED
#define TORRENT_LAZY_ENTRY_HPP_INCLUDED

#include <utility>
#include <vector>
#include <string>
#include <cstring>
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/size_type.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{
	struct lazy_entry;

	TORRENT_EXPORT char const* parse_int(char const* start, char const* end
		, char delimiter, boost::int64_t& val);
	// return 0 = success
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit = 1000);

	struct pascal_string
	{
		pascal_string(char const* p, int l): len(l), ptr(p) {}
		int len;
		char const* ptr;
		bool operator<(pascal_string const& rhs) const
		{
			return std::memcmp(ptr, rhs.ptr, (std::min)(len, rhs.len)) < 0
				|| len < rhs.len;
		}
	};

	struct lazy_dict_entry;

	struct TORRENT_EXPORT lazy_entry
	{
		enum entry_type_t
		{
			none_t, dict_t, list_t, string_t, int_t
		};

		lazy_entry() : m_type(none_t), m_begin(0), m_end(0)
		{ m_data.start = 0; }

		entry_type_t type() const { return m_type; }

		// start points to the first decimal digit
		// length is the number of digits
		void construct_int(char const* start, int length)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = int_t;
			m_data.start = start;
			m_size = length;
			m_begin = start - 1; // include 'i'
			m_end = start + length + 1; // include 'e'
		}

		size_type int_value() const;

		// string functions
		// ================

		void construct_string(char const* start, int length);

		// the string is not null-terminated!
		char const* string_ptr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return m_data.start;
		}

		// this will return a null terminated string
		// it will write to the source buffer!
		char const* string_cstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			const_cast<char*>(m_data.start)[m_size] = 0;
			return m_data.start;
		}

		pascal_string string_pstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return pascal_string(m_data.start, m_size);
		}

		std::string string_value() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return std::string(m_data.start, m_size);
		}

		int string_length() const
		{ return m_size; }

		// dictionary functions
		// ====================

		void construct_dict(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = dict_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* dict_append(char const* name);
		lazy_entry* dict_find(char const* name);
		lazy_entry const* dict_find(char const* name) const
		{ return const_cast<lazy_entry*>(this)->dict_find(name); }

		std::string dict_find_string_value(char const* name) const;
		pascal_string dict_find_pstr(char const* name) const;
		size_type dict_find_int_value(char const* name, size_type default_val = 0) const;
		lazy_entry const* dict_find_dict(char const* name) const;
		lazy_entry const* dict_find_list(char const* name) const;
		lazy_entry const* dict_find_string(char const* name) const;
		lazy_entry const* dict_find_int(char const* name) const;

		std::pair<std::string, lazy_entry const*> dict_at(int i) const;

		int dict_size() const
		{
			TORRENT_ASSERT(m_type == dict_t);
			return m_size;
		}

		// list functions
		// ==============

		void construct_list(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = list_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* list_append();
		lazy_entry* list_at(int i)
		{
			TORRENT_ASSERT(m_type == list_t);
			TORRENT_ASSERT(i < m_size);
			return &m_data.list[i];
		}
		lazy_entry const* list_at(int i) const
		{ return const_cast<lazy_entry*>(this)->list_at(i); }

		std::string list_string_value_at(int i) const;
		pascal_string list_pstr_at(int i) const;
		size_type list_int_value_at(int i, size_type default_val = 0) const;

		int list_size() const
		{
			TORRENT_ASSERT(m_type == list_t);
			return m_size;
		}

		// end points one byte passed last byte
		void set_end(char const* end)
		{
			TORRENT_ASSERT(end > m_begin);
			m_end = end;
		}

		void clear();

		// releases ownership of any memory allocated
		void release()
		{
			m_data.start = 0;
			m_size = 0;
			m_capacity = 0;
			m_type = none_t;
		}

		~lazy_entry()
		{ clear(); }

		// returns pointers into the source buffer where
		// this entry has its bencoded data
		std::pair<char const*, int> data_section() const;

		void swap(lazy_entry& e)
		{
			using std::swap;
			swap(m_type, e.m_type);
			swap(m_data.start, e.m_data.start);
			swap(m_size, e.m_size);
			swap(m_capacity, e.m_capacity);
			swap(m_begin, e.m_begin);
			swap(m_end, e.m_end);
		}

	private:

		entry_type_t m_type;
		union data_t
		{
			lazy_dict_entry* dict;
			lazy_entry* list;
			char const* start;
		} m_data;

		int m_size; // if list or dictionary, the number of items
		int m_capacity; // if list or dictionary, allocated number of items
		// used for dictionaries and lists to record the range
		// in the original buffer they are based on
		char const* m_begin;
		char const* m_end;

		// non-copyable
		lazy_entry(lazy_entry const&);
		lazy_entry const& operator=(lazy_entry const&);
	};

	struct lazy_dict_entry
	{
		char const* name;
		lazy_entry val;
	};

	TORRENT_EXPORT std::string print_entry(lazy_entry const& e
		, bool single_line = false, int indent = 0);
#if TORRENT_USE_IOSTREAM
	TORRENT_EXPORT std::ostream& operator<<(std::ostream& os, lazy_entry const& e);
#endif

}

#endif

<|endoftext|>


<commit_before>#pragma once
#include "base.hpp"
#include "../std/algorithm.hpp"
#include "../std/sstream.hpp"
#include "../std/string.hpp"

#ifndef SRC_LOGGING
#define SRC_LOGGING 1
#endif

#if SRC_LOGGING
#define SRC() my::SrcPoint(__FILE__, __LINE__, __FUNCTION__)
#else
#define SRC() my::SrcPoint()
#endif

namespace my
{
  class SrcPoint
  {
  public:
    SrcPoint() : m_FileName(""), m_Line(-1), m_Function("")
    {
      TruncateFileName();
    }

    SrcPoint(char const * fileName, int line, char const * function)
      : m_FileName(fileName), m_Line(line), m_Function(function)
    {
      TruncateFileName();
    }

    inline char const * FileName() const
    {
      return m_FileName;
    }

    inline int Line() const
    {
      return m_Line;
    }

    inline char const * Function() const
    {
      return m_Function;
    }
  private:
    void TruncateFileName()
    {
      size_t const maxLen = 10000;
      char const * p[] = { m_FileName, m_FileName };
      for (size_t i = 0; i < maxLen && m_FileName[i]; ++i)
      {
        if (m_FileName[i] == '\\' || m_FileName[i] == '/')
        {
          swap(p[0], p[1]);
          p[0] = m_FileName + i + 1;
        }
      }
      m_FileName = p[1];
    }

    char const * m_FileName;
    int m_Line;
    char const * m_Function;
  };
}

inline string DebugPrint(my::SrcPoint const & srcPoint)
{
    ostringstream out;
    if (srcPoint.Line() > 0)
      out << srcPoint.FileName() << ":" << srcPoint.Line() << " " << srcPoint.Function() << "()";
    return out.str();
}

<commit_msg>Improved log formatting - do not print "()" for ObjectiveC functions<commit_after>#pragma once

#include "../std/algorithm.hpp"
#include "../std/sstream.hpp"
#include "../std/string.hpp"

#ifndef SRC_LOGGING
  #define SRC_LOGGING 1
#endif

#if SRC_LOGGING
  #ifndef __OBJC__
    #define SRC() my::SrcPoint(__FILE__, __LINE__, __FUNCTION__, "()")
  #else
    #define SRC() my::SrcPoint(__FILE__, __LINE__, __FUNCTION__)
  #endif
#else
  #define SRC() my::SrcPoint()
#endif

namespace my
{
  class SrcPoint
  {
  public:
    SrcPoint() : m_fileName(""), m_line(-1), m_function("")
    {
      TruncateFileName();
    }

    SrcPoint(char const * fileName, int line, char const * function, char const * postfix = "")
      : m_fileName(fileName), m_line(line), m_function(function), m_postfix(postfix)
    {
      TruncateFileName();
    }

    inline char const * FileName() const
    {
      return m_fileName;
    }

    inline int Line() const
    {
      return m_line;
    }

    inline char const * Function() const
    {
      return m_function;
    }

    inline char const * Postfix() const
    {
      return m_postfix;
    }

  private:
    void TruncateFileName()
    {
      size_t const maxLen = 10000;
      char const * p[] = { m_fileName, m_fileName };
      for (size_t i = 0; i < maxLen && m_fileName[i]; ++i)
      {
        if (m_fileName[i] == '\\' || m_fileName[i] == '/')
        {
          swap(p[0], p[1]);
          p[0] = m_fileName + i + 1;
        }
      }
      m_fileName = p[1];
    }

    char const * m_fileName;
    int m_line;
    char const * m_function;
    char const * m_postfix;
  };
}

inline string DebugPrint(my::SrcPoint const & srcPoint)
{
  ostringstream out;
  if (srcPoint.Line() > 0)
    out << srcPoint.FileName() << ":" << srcPoint.Line() << " " << srcPoint.Function()
        << srcPoint.Postfix() << " ";
  return out.str();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_UDP_SOCKET_HPP_INCLUDED
#define TORRENT_UDP_SOCKET_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/deadline_timer.hpp"

#include <vector>
#include <boost/function/function4.hpp>

namespace libtorrent
{
	class connection_queue;

	class udp_socket
	{
	public:
		typedef boost::function<void(error_code const& ec
			, udp::endpoint const&, char const* buf, int size)> callback_t;

		udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
		~udp_socket();

		bool is_open() const
		{
			return m_ipv4_sock.is_open()
#if TORRENT_USE_IPV6
				|| m_ipv6_sock.is_open()
#endif
				;
		}
		io_service& get_io_service() { return m_ipv4_sock.get_io_service(); }

		void send(udp::endpoint const& ep, char const* p, int len, error_code& ec);
		void bind(udp::endpoint const& ep, error_code& ec);
		void bind(int port);
		void close();
		int local_port() const { return m_bind_port; }

		void set_proxy_settings(proxy_settings const& ps);
		proxy_settings const& get_proxy_settings() { return m_proxy_settings; }

		bool is_closed() const { return m_abort; }
		tcp::endpoint local_endpoint() const
		{
			udp::endpoint ep = m_ipv4_sock.local_endpoint();
			return tcp::endpoint(ep.address(), ep.port());
		}

	protected:

		struct queued_packet
		{
			udp::endpoint ep;
			buffer buf;
		};

	private:

		callback_t m_callback;

		void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred);
		void on_name_lookup(error_code const& e, tcp::resolver::iterator i);
		void on_timeout();
		void on_connect(int ticket);
		void on_connected(error_code const& ec);
		void handshake1(error_code const& e);
		void handshake2(error_code const& e);
		void handshake3(error_code const& e);
		void handshake4(error_code const& e);
		void socks_forward_udp(mutex::scoped_lock& l);
		void connect1(error_code const& e);
		void connect2(error_code const& e);

		void wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec);
		void unwrap(error_code const& e, char const* buf, int size);

		mutable mutex m_mutex;

		udp::socket m_ipv4_sock;
		udp::endpoint m_v4_ep;
		char m_v4_buf[1600];

#if TORRENT_USE_IPV6
		udp::socket m_ipv6_sock;
		udp::endpoint m_v6_ep;
		char m_v6_buf[1600];
#endif

		int m_bind_port;
		char m_outstanding;

		tcp::socket m_socks5_sock;
		int m_connection_ticket;
		proxy_settings m_proxy_settings;
		connection_queue& m_cc;
		tcp::resolver m_resolver;
		char m_tmp_buf[100];
		bool m_queue_packets;
		bool m_tunnel_packets;
		bool m_abort;
		udp::endpoint m_proxy_addr;
		// while we're connecting to the proxy
		// we have to queue the packets, we'll flush
		// them once we're connected
		std::list<queued_packet> m_queue;
#ifdef TORRENT_DEBUG
		bool m_started;
		int m_magic;
		int m_outstanding_when_aborted;
#endif
	};

	struct rate_limited_udp_socket : public udp_socket
	{
		rate_limited_udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
		void set_rate_limit(int limit) { m_rate_limit = limit; }
		bool can_send() const { return int(m_queue.size()) >= m_queue_size_limit; }
		bool send(udp::endpoint const& ep, char const* p, int len, error_code& ec, int flags = 0);
		void close();

	private:
		void on_tick(error_code const& e);

		deadline_timer m_timer;
		int m_queue_size_limit;
		int m_rate_limit;
		int m_quota;
		ptime m_last_tick;
		std::list<queued_packet> m_queue;
	};
}

#endif

<commit_msg>ignore failures in when asking for local_endpoint<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_UDP_SOCKET_HPP_INCLUDED
#define TORRENT_UDP_SOCKET_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/deadline_timer.hpp"

#include <vector>
#include <boost/function/function4.hpp>

namespace libtorrent
{
	class connection_queue;

	class udp_socket
	{
	public:
		typedef boost::function<void(error_code const& ec
			, udp::endpoint const&, char const* buf, int size)> callback_t;

		udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
		~udp_socket();

		bool is_open() const
		{
			return m_ipv4_sock.is_open()
#if TORRENT_USE_IPV6
				|| m_ipv6_sock.is_open()
#endif
				;
		}
		io_service& get_io_service() { return m_ipv4_sock.get_io_service(); }

		void send(udp::endpoint const& ep, char const* p, int len, error_code& ec);
		void bind(udp::endpoint const& ep, error_code& ec);
		void bind(int port);
		void close();
		int local_port() const { return m_bind_port; }

		void set_proxy_settings(proxy_settings const& ps);
		proxy_settings const& get_proxy_settings() { return m_proxy_settings; }

		bool is_closed() const { return m_abort; }
		tcp::endpoint local_endpoint() const
		{
			error_code ec;
			udp::endpoint ep = m_ipv4_sock.local_endpoint(ec);
			return tcp::endpoint(ep.address(), ep.port());
		}

	protected:

		struct queued_packet
		{
			udp::endpoint ep;
			buffer buf;
		};

	private:

		callback_t m_callback;

		void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred);
		void on_name_lookup(error_code const& e, tcp::resolver::iterator i);
		void on_timeout();
		void on_connect(int ticket);
		void on_connected(error_code const& ec);
		void handshake1(error_code const& e);
		void handshake2(error_code const& e);
		void handshake3(error_code const& e);
		void handshake4(error_code const& e);
		void socks_forward_udp(mutex::scoped_lock& l);
		void connect1(error_code const& e);
		void connect2(error_code const& e);

		void wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec);
		void unwrap(error_code const& e, char const* buf, int size);

		mutable mutex m_mutex;

		udp::socket m_ipv4_sock;
		udp::endpoint m_v4_ep;
		char m_v4_buf[1600];

#if TORRENT_USE_IPV6
		udp::socket m_ipv6_sock;
		udp::endpoint m_v6_ep;
		char m_v6_buf[1600];
#endif

		int m_bind_port;
		char m_outstanding;

		tcp::socket m_socks5_sock;
		int m_connection_ticket;
		proxy_settings m_proxy_settings;
		connection_queue& m_cc;
		tcp::resolver m_resolver;
		char m_tmp_buf[100];
		bool m_queue_packets;
		bool m_tunnel_packets;
		bool m_abort;
		udp::endpoint m_proxy_addr;
		// while we're connecting to the proxy
		// we have to queue the packets, we'll flush
		// them once we're connected
		std::list<queued_packet> m_queue;
#ifdef TORRENT_DEBUG
		bool m_started;
		int m_magic;
		int m_outstanding_when_aborted;
#endif
	};

	struct rate_limited_udp_socket : public udp_socket
	{
		rate_limited_udp_socket(io_service& ios, callback_t const& c, connection_queue& cc);
		void set_rate_limit(int limit) { m_rate_limit = limit; }
		bool can_send() const { return int(m_queue.size()) >= m_queue_size_limit; }
		bool send(udp::endpoint const& ep, char const* p, int len, error_code& ec, int flags = 0);
		void close();

	private:
		void on_tick(error_code const& e);

		deadline_timer m_timer;
		int m_queue_size_limit;
		int m_rate_limit;
		int m_quota;
		ptime m_last_tick;
		std::list<queued_packet> m_queue;
	};
}

#endif

<|endoftext|>


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

#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/automation/url_request_mock_http_job.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/url_request/url_request_unittest.h"

const std::wstring kTestDir = L"save_page";

class SavePageTest : public UITest {
 protected:
  SavePageTest() : UITest() {}

  void CheckFile(const std::wstring& client_file,
                 const std::wstring& server_file,
                 bool check_equal) {
    bool exist = false;
    for (int i = 0; i < 20; ++i) {
      if (file_util::PathExists(client_file)) {
        exist = true;
        break;
      }
      Sleep(sleep_timeout_ms());
    }
    EXPECT_TRUE(exist);

    if (check_equal) {
      std::wstring server_file_name;
      ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA,
                                   &server_file_name));
      server_file_name += L"\\" + kTestDir + L"\\" + server_file;
      ASSERT_TRUE(file_util::PathExists(server_file_name));

      int64 client_file_size = 0;
      int64 server_file_size = 0;
      EXPECT_TRUE(file_util::GetFileSize(client_file, &client_file_size));
      EXPECT_TRUE(file_util::GetFileSize(server_file_name, &server_file_size));
      EXPECT_EQ(client_file_size, server_file_size);
      EXPECT_TRUE(file_util::ContentsEqual(client_file, server_file_name));
    }

    EXPECT_TRUE(DieFileDie(client_file, false));
  }

  virtual void SetUp() {
    UITest::SetUp();
    EXPECT_TRUE(file_util::CreateNewTempDirectory(L"", &save_dir_));
    save_dir_ += FilePath::kSeparators[0];

    download_dir_ = GetDownloadDirectory();
    download_dir_ += FilePath::kSeparators[0];
  }

  virtual void TearDown() {
    UITest::TearDown();
    DieFileDie(save_dir_, true);
  }

  std::wstring save_dir_;
  std::wstring download_dir_;
};

TEST_F(SavePageTest, SaveHTMLOnly) {
  std::wstring file_name = L"a.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"a_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  EXPECT_TRUE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_ONLY_HTML));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));

  CheckFile(full_file_name, file_name, true);
  EXPECT_FALSE(file_util::PathExists(dir));
}

TEST_F(SavePageTest, SaveCompleteHTML) {
  std::wstring file_name = L"b.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"b_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  EXPECT_TRUE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_COMPLETE_HTML));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));

  CheckFile(dir + L"\\1.png", L"1.png", true);
  CheckFile(dir + L"\\1.css", L"1.css", true);
  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(dir, true));
}

TEST_F(SavePageTest, NoSave) {
  std::wstring file_name = L"c.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"c_files";

  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(GURL(L"about:blank")));
  WaitUntilTabCount(1);

  EXPECT_FALSE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_ONLY_HTML));
  EXPECT_FALSE(WaitForDownloadShelfVisible(tab.get()));
}

TEST_F(SavePageTest, FilenameFromPageTitle) {
  std::wstring file_name = L"b.htm";
  std::wstring full_file_name = download_dir_ +
      L"Test page for saving page feature.htm";
  std::wstring dir = download_dir_ +
      L"Test page for saving page feature_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  automation()->SavePackageShouldPromptUser(false);
  EXPECT_TRUE(browser->RunCommand(IDC_SAVE_PAGE));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));
  automation()->SavePackageShouldPromptUser(true);

  CheckFile(dir + L"\\1.png", L"1.png", true);
  CheckFile(dir + L"\\1.css", L"1.css", true);
  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(full_file_name, false));
  EXPECT_TRUE(DieFileDie(dir, true));
}

TEST_F(SavePageTest, CleanFilenameFromPageTitle) {
  std::wstring file_name = L"c.htm";
  std::wstring full_file_name = download_dir_ + L"test.htm";
  std::wstring dir = download_dir_ + L"test_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  automation()->SavePackageShouldPromptUser(false);
  EXPECT_TRUE(browser->RunCommand(IDC_SAVE_PAGE));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));
  automation()->SavePackageShouldPromptUser(true);

  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(full_file_name, false));
  EXPECT_TRUE(DieFileDie(dir, true));
}
<commit_msg>Disable the test SavePageTest.CleanFilenameFromPageTitle due to bug 6514. Review URL: http://codereview.chromium.org/18154<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/automation/url_request_mock_http_job.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/url_request/url_request_unittest.h"

const std::wstring kTestDir = L"save_page";

class SavePageTest : public UITest {
 protected:
  SavePageTest() : UITest() {}

  void CheckFile(const std::wstring& client_file,
                 const std::wstring& server_file,
                 bool check_equal) {
    bool exist = false;
    for (int i = 0; i < 20; ++i) {
      if (file_util::PathExists(client_file)) {
        exist = true;
        break;
      }
      Sleep(sleep_timeout_ms());
    }
    EXPECT_TRUE(exist);

    if (check_equal) {
      std::wstring server_file_name;
      ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA,
                                   &server_file_name));
      server_file_name += L"\\" + kTestDir + L"\\" + server_file;
      ASSERT_TRUE(file_util::PathExists(server_file_name));

      int64 client_file_size = 0;
      int64 server_file_size = 0;
      EXPECT_TRUE(file_util::GetFileSize(client_file, &client_file_size));
      EXPECT_TRUE(file_util::GetFileSize(server_file_name, &server_file_size));
      EXPECT_EQ(client_file_size, server_file_size);
      EXPECT_TRUE(file_util::ContentsEqual(client_file, server_file_name));
    }

    EXPECT_TRUE(DieFileDie(client_file, false));
  }
SavePageTest
  virtual void SetUp() {
    UITest::SetUp();
    EXPECT_TRUE(file_util::CreateNewTempDirectory(L"", &save_dir_));
    save_dir_ += FilePath::kSeparators[0];

    download_dir_ = GetDownloadDirectory();
    download_dir_ += FilePath::kSeparators[0];
  }

  virtual void TearDown() {
    UITest::TearDown();
    DieFileDie(save_dir_, true);
  }

  std::wstring save_dir_;
  std::wstring download_dir_;
};

TEST_F(SavePageTest, SaveHTMLOnly) {
  std::wstring file_name = L"a.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"a_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  EXPECT_TRUE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_ONLY_HTML));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));

  CheckFile(full_file_name, file_name, true);
  EXPECT_FALSE(file_util::PathExists(dir));
}

TEST_F(SavePageTest, SaveCompleteHTML) {
  std::wstring file_name = L"b.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"b_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  EXPECT_TRUE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_COMPLETE_HTML));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));

  CheckFile(dir + L"\\1.png", L"1.png", true);
  CheckFile(dir + L"\\1.css", L"1.css", true);
  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(dir, true));
}

TEST_F(SavePageTest, NoSave) {
  std::wstring file_name = L"c.htm";
  std::wstring full_file_name = save_dir_ + file_name;
  std::wstring dir = save_dir_ + L"c_files";

  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(GURL(L"about:blank")));
  WaitUntilTabCount(1);

  EXPECT_FALSE(tab->SavePage(full_file_name, dir,
      SavePackage::SAVE_AS_ONLY_HTML));
  EXPECT_FALSE(WaitForDownloadShelfVisible(tab.get()));
}

TEST_F(SavePageTest, FilenameFromPageTitle) {
  std::wstring file_name = L"b.htm";
  std::wstring full_file_name = download_dir_ +
      L"Test page for saving page feature.htm";
  std::wstring dir = download_dir_ +
      L"Test page for saving page feature_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  automation()->SavePackageShouldPromptUser(false);
  EXPECT_TRUE(browser->RunCommand(IDC_SAVE_PAGE));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));
  automation()->SavePackageShouldPromptUser(true);

  CheckFile(dir + L"\\1.png", L"1.png", true);
  CheckFile(dir + L"\\1.css", L"1.css", true);
  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(full_file_name, false));
  EXPECT_TRUE(DieFileDie(dir, true));
}

// BUG 6514
TEST_F(SavePageTest, DISABLED_CleanFilenameFromPageTitle) {
  std::wstring file_name = L"c.htm";
  std::wstring full_file_name = download_dir_ + L"test.htm";
  std::wstring dir = download_dir_ + L"test_files";

  GURL url = URLRequestMockHTTPJob::GetMockUrl(kTestDir + L"/" + file_name);
  scoped_ptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab->NavigateToURL(url));
  WaitUntilTabCount(1);

  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  automation()->SavePackageShouldPromptUser(false);
  EXPECT_TRUE(browser->RunCommand(IDC_SAVE_PAGE));
  EXPECT_TRUE(WaitForDownloadShelfVisible(tab.get()));
  automation()->SavePackageShouldPromptUser(true);

  CheckFile(full_file_name, file_name, false);
  EXPECT_TRUE(DieFileDie(full_file_name, false));
  EXPECT_TRUE(DieFileDie(dir, true));
}
<|endoftext|>