<commit_before>/*
MIT License

Copyright (c) 2017

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 <iostream>
#include <vector>
#include <utility>
#include <map>
#include <algorithm>
#include <string>
#include <cstring>
#include <sstream>
#include <fstream>
/*
	Program defines
	To be moved to a separate header file
*/

#define ARGC_VAL_MIN (1+4)

/*
	Custom structs
	To be moved to spearate header file
*/

typedef struct {
	std::pair<int,int> id;
	std::pair<int,int> l;
	std::pair<int,int> start;
	std::pair<int,int> end;
	std::pair<int,int> rc;
	double jaccardScore;
	int smm;
} mhapRead_t;

typedef struct {
	std::vector<mhapRead_t*> lOvlp;
	std::vector<mhapRead_t*> rOvlp;
} BOGNode_t;

/*
	Global variables
*/

std::map<int,BOGNode_t> nodes;
std::vector<mhapRead_t> mhapReads;

/*
	local function declarations
*/
int isDoveTail(mhapRead_t* mRead);
int isLeftAligned(mhapRead_t* mRead);

int main(int argc, char** argv) {
	/*
		int main() variables
	*/
	int defaultOutput = 1;
	std::string mhapPath;
	std::string fastaPath;
	std::string outputPath = "output.fasta";

	/*
		parse input arguments
	*/

	if (argc < ARGC_VAL_MIN) {
		std::cout << "Too few parameters! Expected at least " << ARGC_VAL_MIN-1 << ", got " << argc-1 << ".\r\nTerminating." << std::endl;
		return 1;
	} else {
//		std::cout << "Input parameters OK" << std::endl;
	}
	for (int i=1; i<argc; ++i) {
		if (strcmp(argv[i],"-mhap") == 0) {
			mhapPath.assign(argv[++i]);
			// accept only *.mhap for now
			std::string inputExtension;
			std::string::size_type idx = mhapPath.rfind('.');
			if (idx != std::string::npos) {
				inputExtension = mhapPath.substr(idx);
				if (strcmp(inputExtension.c_str(),".mhap")) {
					std::cout << "Please provide a *.mhap file. (got " <<  inputExtension << ")" << std::endl << "Terminating." << std::endl;
					return 1;
				}
			} else {
				std::cout << "Provide input file extension!" << std::endl << "Terminating." << std::endl;
				return 1;
			}
//			std::cout << "Input path: " << inputPath << std::endl;
//			std::cout << "Input extension " << inputExtension << std::endl;
		} else if (strcmp(argv[i],"-fasta") == 0) {
			fastaPath.assign(argv[++i]);
			// accept only *.mhap for now
			std::string inputExtension;
			std::string::size_type idx = fastaPath.rfind('.');
			if (idx != std::string::npos) {
				inputExtension = fastaPath.substr(idx);
				if (strcmp(inputExtension.c_str(),".fasta")) {
					std::cout << "Please provide a *.fasta file. (got " <<  inputExtension << ")" << std::endl << "Terminating." << std::endl;
					return 1;
				}
			} else {
				std::cout << "Provide input file extension!" << std::endl << "Terminating." << std::endl;
				return 1;
			}
		} else if (strcmp(argv[i],"-o") == 0) {
			outputPath.assign(argv[++i]);
			defaultOutput = 0;
			std::ofstream outputFile (outputPath.c_str());
			if (!outputFile) {
				std::cout << "Cannot generate output file!" << std::endl << "Terminating." << std::endl;
			} else {
				outputFile.close();
			}
//			std::cout << "Output path: " << outputPath << std::endl;
		} else {
			std::cout << "invalid cli options" << std::endl << "Terminating" << std::endl;
			return 1;
		}
	}
	if (fastaPath.empty() || mhapPath.empty()) {
		std::cout << "Please provide both *.fasta and *.mhap files!" << std::endl;
		return 1;
	}
	/*
		open input file (fasta or mhap)
			mhap is better, because conversion of ecoli_corrected.fasta to mhap (graphmap) takes about 70 minutes on 4 cores and 10 GB RAM
	*/
	// only mhap for now :)
	std::ifstream inputFile(mhapPath.c_str(),std::ifstream::in);
	if (!inputFile) {
		std::cout << mhapPath <<": No such file" << std::endl;
		return 1;
	}

	/*
		parse input file
	*/
	std::string line;
	while (std::getline(inputFile,line)) {
		std::istringstream inStream(line);
		int ix1,ix2,smm,rc1,rc2,s1,e1,l1,s2,e2,l2;
		double js;
		mhapRead_t cRead;
		inStream >> ix1 >> ix2;
		inStream >> cRead.jaccardScore;
		inStream >> cRead.smm;
		inStream >> rc1 >> s1 >> e1 >> l1;
		inStream >> rc2 >> s2 >> e2 >> l2;
		cRead.id = std::make_pair(ix1,ix2);
		cRead.l = std::make_pair(l1,l2);
		cRead.start = std::make_pair(s1,s2);
		cRead.end = std::make_pair(e1,e2);
		cRead.rc = std::make_pair(rc1,rc2);
//		std::cout << ix1 << " " << ix2 << " " << js << " " << smm << " " << rc1 << " " << s1 << " " << e1 << " " << l1 << " " << rc2 << " " << s2 << " " << e2 << " " << l2 << std::endl;
		// push_back to a vector of reads
		mhapReads.push_back(cRead);
	}

	/*
		generate read and overlap contexts
		build the complete OVERLAP GRAPH
	*/
	for (int i = 0; i<mhapReads.size(); ++i) {
		mhapRead_t* cRead = &mhapReads[i];
		BOGNode_t bNodeF,bNodeS;
		int ixf = cRead->id.first;
		int ixs = cRead->id.second;

		// load existing map record
		std::map<int,BOGNode_t>::iterator it = nodes.find(ixf);
		if (it != nodes.end()) {
			bNodeF = nodes[ixf];
		}
		it = nodes.find(ixs);
		if (it != nodes.end()) {
			bNodeS = nodes[ixs];
		}
		// ignore non-dovetail overlaps
		if (isDoveTail(cRead)) {
			if (isLeftAligned(cRead)) {
				// add to left overlaps
				bNodeF.lOvlp.push_back(cRead);
				bNodeS.rOvlp.push_back(cRead);
			} else {
				// add to right overlaps
				bNodeF.rOvlp.push_back(cRead);
				bNodeS.lOvlp.push_back(cRead);
			}
		}
		nodes[ixf] = bNodeF;
		nodes[ixs] = bNodeS;
	}

	/*
		THE ALGORITHM
		Travel through the overlap graph, remove contained reads, remove cycles, pick best overlaps
		Create the best overlap graph
			1 fasta read per chromosome is optimum
	*/

	/*
		Take the BOG and write i in FASTA format
	*/

	/*
		Notify about success, return 0
	*/
	if (defaultOutput) {
		std::cout << "Output to default: " << outputPath << std::endl;
	} else {
		std::cout << "Output to custom: " << outputPath << std::endl;
	}
	std::ofstream outputFile (outputPath.c_str());
	outputFile << ">The result of the BOG goes here" << std::endl;
	outputFile.close();
	return 0;
}

// not definitive
int isDoveTail(mhapRead_t* mRead) {
	if (mRead->start.first != 0 && mRead->end.first != (mRead->l.first-1)) {
		// doesnt start at the beginning nor does it end at the end, this is a pratial overlap
		return 0;
	}
	if (mRead->start.second != 0 && mRead->end.second != (mRead->l.second-1)) {
		// doesnt start at the beginning nor does it end at the end, this is a pratial overlap
		return 0;
	}
	return 1;
}

// a left aligned overlap is the one where the first index overlaps form 0 to x, x<l-1
// the end of the second read overlaps with the beginning of the first read

// not definitive
int isLeftAligned(mhapRead_t* mRead) {
	return mRead->start.first == 0;
}
<commit_msg>Buildable version before testing what is done so far and before implementing the BOG<commit_after>/*
MIT License

Copyright (c) 2017

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 <iostream>
#include <vector>
#include <utility>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <cstring>
#include <sstream>
#include <fstream>
/*
	Program defines
	To be moved to a separate header file
*/

#define ARGC_VAL_MIN (1+4)

/*
	Custom structs
	To be moved to spearate header file
*/

typedef struct {
	std::pair<int,int> id;
	std::pair<int,int> l;
	std::pair<int,int> start;
	std::pair<int,int> end;
	std::pair<int,int> rc;
	double jaccardScore;
	int smm;
} mhapRead_t;

typedef struct {
	std::vector<mhapRead_t*> lOvlp;
	std::vector<mhapRead_t*> rOvlp;
} BOGNode_t;

bool cmpNodes(mhapRead_t* a, mhapRead_t* b) {
	if (a->jaccardScore != b->jaccardScore) {
		return a->jaccardScore < b->jaccardScore;
	}
	return a->smm > b->smm;
}

/*
	Global variables
*/

std::map<int,BOGNode_t> nodes;
std::vector<mhapRead_t> mhapReads;
std::set<int> readIxs;
std::vector<int> result;

/*
	local function declarations
*/
int isDoveTail(mhapRead_t* mRead);
int isLeftAligned(mhapRead_t* mRead);

int main(int argc, char** argv) {
	/*
		int main() variables
	*/
	int defaultOutput = 1;
	std::string mhapPath;
	std::string fastaPath;
	std::string outputPath = "output.fasta";
	double minJaccardScore = 1.0;
	int minJaccardIx;

	/*
		parse input arguments
	*/

	if (argc < ARGC_VAL_MIN) {
		std::cout << "Too few parameters! Expected at least " << ARGC_VAL_MIN-1 << ", got " << argc-1 << ".\r\nTerminating." << std::endl;
		return 1;
	} else {
//		std::cout << "Input parameters OK" << std::endl;
	}
	for (int i=1; i<argc; ++i) {
		if (strcmp(argv[i],"-mhap") == 0) {
			mhapPath.assign(argv[++i]);
			// accept only *.mhap for now
			std::string inputExtension;
			std::string::size_type idx = mhapPath.rfind('.');
			if (idx != std::string::npos) {
				inputExtension = mhapPath.substr(idx);
				if (strcmp(inputExtension.c_str(),".mhap")) {
					std::cout << "Please provide a *.mhap file. (got " <<  inputExtension << ")" << std::endl << "Terminating." << std::endl;
					return 1;
				}
			} else {
				std::cout << "Provide input file extension!" << std::endl << "Terminating." << std::endl;
				return 1;
			}
//			std::cout << "Input path: " << inputPath << std::endl;
//			std::cout << "Input extension " << inputExtension << std::endl;
		} else if (strcmp(argv[i],"-fasta") == 0) {
			fastaPath.assign(argv[++i]);
			// accept only *.mhap for now
			std::string inputExtension;
			std::string::size_type idx = fastaPath.rfind('.');
			if (idx != std::string::npos) {
				inputExtension = fastaPath.substr(idx);
				if (strcmp(inputExtension.c_str(),".fasta")) {
					std::cout << "Please provide a *.fasta file. (got " <<  inputExtension << ")" << std::endl << "Terminating." << std::endl;
					return 1;
				}
			} else {
				std::cout << "Provide input file extension!" << std::endl << "Terminating." << std::endl;
				return 1;
			}
		} else if (strcmp(argv[i],"-o") == 0) {
			outputPath.assign(argv[++i]);
			defaultOutput = 0;
			std::ofstream outputFile (outputPath.c_str());
			if (!outputFile) {
				std::cout << "Cannot generate output file!" << std::endl << "Terminating." << std::endl;
			} else {
				outputFile.close();
			}
//			std::cout << "Output path: " << outputPath << std::endl;
		} else {
			std::cout << "invalid cli options" << std::endl << "Terminating" << std::endl;
			return 1;
		}
	}
	if (fastaPath.empty() || mhapPath.empty()) {
		std::cout << "Please provide both *.fasta and *.mhap files!" << std::endl;
		return 1;
	}
	/*
		open input file (fasta or mhap)
			mhap is better, because conversion of ecoli_corrected.fasta to mhap (graphmap) takes about 70 minutes on 4 cores and 10 GB RAM
	*/
	// only mhap for now :)
	std::ifstream inputFile(mhapPath.c_str(),std::ifstream::in);
	if (!inputFile) {
		std::cout << mhapPath <<": No such file" << std::endl;
		return 1;
	}

	/*
		parse input file
	*/
	std::string line;
	while (std::getline(inputFile,line)) {
		std::istringstream inStream(line);
		int ix1,ix2,smm,rc1,rc2,s1,e1,l1,s2,e2,l2;
		double js;
		mhapRead_t cRead;
		inStream >> ix1 >> ix2;
		inStream >> cRead.jaccardScore;
		inStream >> cRead.smm;
		inStream >> rc1 >> s1 >> e1 >> l1;
		inStream >> rc2 >> s2 >> e2 >> l2;
		cRead.id = std::make_pair(ix1,ix2);
		cRead.l = std::make_pair(l1,l2);
		cRead.start = std::make_pair(s1,s2);
		cRead.end = std::make_pair(e1,e2);
		cRead.rc = std::make_pair(rc1,rc2);
//		std::cout << ix1 << " " << ix2 << " " << js << " " << smm << " " << rc1 << " " << s1 << " " << e1 << " " << l1 << " " << rc2 << " " << s2 << " " << e2 << " " << l2 << std::endl;
		// push_back to a vector of reads
		mhapReads.push_back(cRead);
	}

	/*
		generate read and overlap contexts
		build the complete OVERLAP GRAPH
	*/
	for (int i = 0; i<mhapReads.size(); ++i) {
		mhapRead_t* cRead = &mhapReads[i];
		BOGNode_t bNodeF,bNodeS;
		int ixf = cRead->id.first;
		int ixs = cRead->id.second;

		// load existing map record
		std::map<int,BOGNode_t>::iterator it = nodes.find(ixf);
		if (it != nodes.end()) {
			bNodeF = nodes[ixf];
		} else {
			readIxs.insert(ixf);
		}
		it = nodes.find(ixs);
		if (it != nodes.end()) {
			bNodeS = nodes[ixs];
		} else {
			readIxs.insert(ixs);
		}
		// ignore non-dovetail overlaps
		if (isDoveTail(cRead)) {
			if (isLeftAligned(cRead)) {
				// add to left overlaps
				bNodeF.lOvlp.push_back(cRead);
				bNodeS.rOvlp.push_back(cRead);
			} else {
				// add to right overlaps
				bNodeF.rOvlp.push_back(cRead);
				bNodeS.lOvlp.push_back(cRead);
			}
		}
		nodes[ixf] = bNodeF;
		nodes[ixs] = bNodeS;
	}

	for (int i=0; i<nodes.size(); ++i) {
		// sort by Jaccard score which is not exactly Jaccard score when mhap comes from graphmap but ok
		std::sort(nodes[i].lOvlp.begin(),nodes[i].lOvlp.end(),cmpNodes);
		std::sort(nodes[i].rOvlp.begin(),nodes[i].rOvlp.end(),cmpNodes);
		if (minJaccardScore > nodes[i].rOvlp[0]->jaccardScore) {
			minJaccardScore > nodes[i].rOvlp[0]->jaccardScore;
			minJaccardIx = i;
		}
	}
	// thats it, we have our densely populated overlap graph

	/*
		THE ALGORITHM
		Travel through the overlap graph, remove contained reads, remove cycles, pick best overlaps
		Create the best overlap graph
			1 fasta read per chromosome is optimum
	*/

	// pick the node with the worst left overlap Jaccard score - this will be our starting node
	result.push_back(minJaccardIx);
	readIxs.erase(minJaccardIx);

	/*
		Take the BOG and write i in FASTA format
	*/

	/*
		Notify about success, return 0
	*/
	if (defaultOutput) {
		std::cout << "Output to default: " << outputPath << std::endl;
	} else {
		std::cout << "Output to custom: " << outputPath << std::endl;
	}
	std::ofstream outputFile (outputPath.c_str());
	outputFile << ">The result of the BOG goes here" << std::endl;
	outputFile.close();
	return 0;
}

// not definitive
int isDoveTail(mhapRead_t* mRead) {
	if (mRead->start.first != 0 && mRead->end.first != (mRead->l.first-1)) {
		// doesnt start at the beginning nor does it end at the end, this is a pratial overlap
		return 0;
	}
	if (mRead->start.second != 0 && mRead->end.second != (mRead->l.second-1)) {
		// doesnt start at the beginning nor does it end at the end, this is a pratial overlap
		return 0;
	}
	return 1;
}

// a left aligned overlap is the one where the first index overlaps form 0 to x, x<l-1
// the end of the second read overlaps with the beginning of the first read

// not definitive
int isLeftAligned(mhapRead_t* mRead) {
	return mRead->start.first == 0;
}
<|endoftext|>


<commit_before>#include "PositionModule.hpp"

#include <assert.h>
#include <sys/stat.h>
#include <errno.h>
#include <string>

#include <ros/console.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>

#include "sensor_msgs/Image.h"
#include "api_application/Ping.h"
#include "api_application/Announce.h"

PositionModule::PositionModule(IPositionReceiver* receiver)
{
	assert(receiver != 0);
	this->receiver = receiver;

	_isInitialized = true;
	isCalibrating = false;
	isRunning = false;

	ros::NodeHandle n;

	this->pictureSendingActivationPublisher = n.advertise<camera_application::PictureSendingActivation>("PictureSendingActivation", 4);
	this->pingPublisher = n.advertise<api_application::Ping>("Ping", 4);
	this->pictureSubscriber = n.subscribe("Picture", 128, &PositionModule::pictureCallback, this);

	this->startCalibrationService = n.advertiseService("StartCalibration", &PositionModule::startCalibrationCallback, this);
	this->takeCalibrationPictureService = n.advertiseService("TakeCalibrationPicture", &PositionModule::takeCalibrationPictureCallback, this);
	this->calculateCalibrationService = n.advertiseService("CalculateCalibration", &PositionModule::calculateCalibrationCallback, this);

	// Advertise myself to API
	ros::ServiceClient announceClient = n.serviceClient<api_application::Announce>("Announce");

	api_application::Announce announce;
	announce.request.type = 3; // 3 means position module
	announce.request.initializeServiceName = std::string("InitializePositionModule");

	if (announceClient.call(announce))
	{
		rosId = announce.response.ID;

		if (rosId == ~0 /* -1 */)
		{
			ROS_ERROR("Error! Got id -1");
			_isInitialized = false;
		}
		else
		{
			ROS_INFO("Position module successfully announced. Got id %d", rosId);
		}
	}
	else
	{
		ROS_ERROR("Error! Could not announce myself to API!");
		_isInitialized = false;
	}

	msg = new KitrokopterMessages(rosId);

	if (_isInitialized)
	{
		ROS_DEBUG("PositionModule initialized.");
	}
}

PositionModule::~PositionModule()
{
	msg->~KitrokopterMessages();

	// TODO: Free picture cache.

	ROS_DEBUG("PositionModule destroyed.");
}

// Service
bool PositionModule::startCalibrationCallback(control_application::StartCalibration::Request &req, control_application::StartCalibration::Response &res)
{
	res.ok = !isCalibrating;

	if (!isCalibrating)
	{
		setPictureSendingActivated(true);
		calibrationPictureCount = 0;
		boardSize = cv::Size(req.chessboardWidth, req.chessboardHeight);
	}

	isCalibrating = true;
	return true;
}

// Service
bool PositionModule::takeCalibrationPictureCallback(control_application::TakeCalibrationPicture::Request &req, control_application::TakeCalibrationPicture::Response &res)
{
	int id = 0;

	for (std::vector<cv::Mat*>::iterator it = pictureCache.begin(); it != pictureCache.end(); it++, id++)
	{
		if (*it != 0)
		{
			// TODO: check if image is "good"
			std::vector<cv::Point2f> corners;
			bool foundAllCorners = cv::findChessboardCorners(**it, boardSize, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);

			if (!foundAllCorners)
			{
				ROS_INFO("Took bad picture (id %d)", id);
				continue;
			}
			else
			{
				ROS_INFO("Took good picture (id %d)", id);
			}

			// Create directory for images.
			int error = mkdir("~/calibrationImages", 770);

			if (error != 0 && error != EEXIST)
			{
				ROS_ERROR("Could not create directory for calibration images: %d", error);
				return false;
			}

			std::stringstream ss;
			ss << "~/calibrationImages/cam" << id << "_image" << calibrationPictureCount << ".png";

			cv::imwrite(ss.str(), **it);

			sensor_msgs::Image img;
			img.width = 640;
			img.height = 480;
			img.step = 3 * 640;

			for (int i = 0; i < 640 * 480 * 3; i++)
			{
				img.data[i] = (*it)->data[i];
			}

			res.images.push_back(img);

			delete *it;
			*it = 0;
		}
	}

	calibrationPictureCount++;

	return true;
}

// Service
bool PositionModule::calculateCalibrationCallback(control_application::CalculateCalibration::Request &req, control_application::CalculateCalibration::Response &res)
{
	// TODO: Do stuff with danis code...

	return true;
}

// Topic
void PositionModule::pictureCallback(const camera_application::Picture &msg)
{
	if (isCalibrating)
	{
		// Don't know if it works that way and I really can randomly insert now...
		pictureCache.reserve(msg.ID + 1);
		pictureTimes.reserve(msg.ID + 1);

		if (pictureCache[msg.ID] != 0)
		{
			delete pictureCache[msg.ID];
			pictureCache[msg.ID] = 0;
		}

		cv::Mat* image = new cv::Mat(cv::Size(640, 480), CV_8UC3);

		for (int i = 0; i < 640 * 480 * 3; i++)
		{
			image->data[i] = msg.image[i];
		}

		pictureCache[msg.ID] = image;
		pictureTimes[msg.ID] = msg.timestamp;
	}
}

// Topic
void PositionModule::systemCallback(const api_application::System &msg)
{
	isRunning = msg.command == 1;
}

void PositionModule::setPictureSendingActivated(bool activated)
{
	camera_application::PictureSendingActivation msg;
	msg.ID = 0;
	msg.active = activated;

	pictureSendingActivationPublisher.publish(msg);
}

void PositionModule::sendPing()
{
	api_application::Ping msg;
	msg.ID = rosId;
	pingPublisher.publish(msg);
}

bool PositionModule::isInitialized()
{
	return _isInitialized;
}<commit_msg>Don't send bad pictures.<commit_after>#include "PositionModule.hpp"

#include <assert.h>
#include <sys/stat.h>
#include <errno.h>
#include <string>

#include <ros/console.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>

#include "sensor_msgs/Image.h"
#include "api_application/Ping.h"
#include "api_application/Announce.h"

PositionModule::PositionModule(IPositionReceiver* receiver)
{
	assert(receiver != 0);
	this->receiver = receiver;

	_isInitialized = true;
	isCalibrating = false;
	isRunning = false;

	ros::NodeHandle n;

	this->pictureSendingActivationPublisher = n.advertise<camera_application::PictureSendingActivation>("PictureSendingActivation", 4);
	this->pingPublisher = n.advertise<api_application::Ping>("Ping", 4);
	this->pictureSubscriber = n.subscribe("Picture", 128, &PositionModule::pictureCallback, this);

	this->startCalibrationService = n.advertiseService("StartCalibration", &PositionModule::startCalibrationCallback, this);
	this->takeCalibrationPictureService = n.advertiseService("TakeCalibrationPicture", &PositionModule::takeCalibrationPictureCallback, this);
	this->calculateCalibrationService = n.advertiseService("CalculateCalibration", &PositionModule::calculateCalibrationCallback, this);

	// Advertise myself to API
	ros::ServiceClient announceClient = n.serviceClient<api_application::Announce>("Announce");

	api_application::Announce announce;
	announce.request.type = 3; // 3 means position module
	announce.request.initializeServiceName = std::string("InitializePositionModule");

	if (announceClient.call(announce))
	{
		rosId = announce.response.ID;

		if (rosId == ~0 /* -1 */)
		{
			ROS_ERROR("Error! Got id -1");
			_isInitialized = false;
		}
		else
		{
			ROS_INFO("Position module successfully announced. Got id %d", rosId);
		}
	}
	else
	{
		ROS_ERROR("Error! Could not announce myself to API!");
		_isInitialized = false;
	}

	msg = new KitrokopterMessages(rosId);

	if (_isInitialized)
	{
		ROS_DEBUG("PositionModule initialized.");
	}
}

PositionModule::~PositionModule()
{
	msg->~KitrokopterMessages();

	// TODO: Free picture cache.

	ROS_DEBUG("PositionModule destroyed.");
}

// Service
bool PositionModule::startCalibrationCallback(control_application::StartCalibration::Request &req, control_application::StartCalibration::Response &res)
{
	res.ok = !isCalibrating;

	if (!isCalibrating)
	{
		setPictureSendingActivated(true);
		calibrationPictureCount = 0;
		boardSize = cv::Size(req.chessboardWidth, req.chessboardHeight);
	}

	isCalibrating = true;
	return true;
}

// Service
bool PositionModule::takeCalibrationPictureCallback(control_application::TakeCalibrationPicture::Request &req, control_application::TakeCalibrationPicture::Response &res)
{
	int id = 0;

	for (std::vector<cv::Mat*>::iterator it = pictureCache.begin(); it != pictureCache.end(); it++, id++)
	{
		if (*it != 0)
		{
			// TODO: check if image is "good"
			std::vector<cv::Point2f> corners;
			bool foundAllCorners = cv::findChessboardCorners(**it, boardSize, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);

			if (!foundAllCorners)
			{
				ROS_INFO("Took bad picture (id %d)", id);
				continue;
			}
			else
			{
				ROS_INFO("Took good picture (id %d)", id);

				// Create directory for images.
				int error = mkdir("~/calibrationImages", 770);

				if (error != 0 && error != EEXIST)
				{
					ROS_ERROR("Could not create directory for calibration images: %d", error);
					return false;
				}

				std::stringstream ss;
				ss << "~/calibrationImages/cam" << id << "_image" << calibrationPictureCount << ".png";

				cv::imwrite(ss.str(), **it);

				sensor_msgs::Image img;
				img.width = 640;
				img.height = 480;
				img.step = 3 * 640;

				for (int i = 0; i < 640 * 480 * 3; i++)
				{
					img.data[i] = (*it)->data[i];
				}

				res.images.push_back(img);
			}

			delete *it;
			*it = 0;
		}
	}

	calibrationPictureCount++;

	return true;
}

// Service
bool PositionModule::calculateCalibrationCallback(control_application::CalculateCalibration::Request &req, control_application::CalculateCalibration::Response &res)
{
	// TODO: Do stuff with danis code...

	return true;
}

// Topic
void PositionModule::pictureCallback(const camera_application::Picture &msg)
{
	if (isCalibrating)
	{
		// Don't know if it works that way and I really can randomly insert now...
		pictureCache.reserve(msg.ID + 1);
		pictureTimes.reserve(msg.ID + 1);

		if (pictureCache[msg.ID] != 0)
		{
			delete pictureCache[msg.ID];
			pictureCache[msg.ID] = 0;
		}

		cv::Mat* image = new cv::Mat(cv::Size(640, 480), CV_8UC3);

		for (int i = 0; i < 640 * 480 * 3; i++)
		{
			image->data[i] = msg.image[i];
		}

		pictureCache[msg.ID] = image;
		pictureTimes[msg.ID] = msg.timestamp;
	}
}

// Topic
void PositionModule::systemCallback(const api_application::System &msg)
{
	isRunning = msg.command == 1;
}

void PositionModule::setPictureSendingActivated(bool activated)
{
	camera_application::PictureSendingActivation msg;
	msg.ID = 0;
	msg.active = activated;

	pictureSendingActivationPublisher.publish(msg);
}

void PositionModule::sendPing()
{
	api_application::Ping msg;
	msg.ID = rosId;
	pingPublisher.publish(msg);
}

bool PositionModule::isInitialized()
{
	return _isInitialized;
}<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include "sbmodule.hxx"

/** === begin UNO includes === **/
/** === end UNO includes === **/

//........................................................................
namespace basic
{
//........................................................................

    //--------------------------------------------------------------------
    extern void createRegistryInfo_SfxDialogLibraryContainer();
    extern void createRegistryInfo_SfxScriptLibraryContainer();

    static void initializeModule()
    {
        static bool bInitialized( false );
        if ( !bInitialized )
        {
            ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
            if ( !bInitialized )
            {
                createRegistryInfo_SfxDialogLibraryContainer();
                createRegistryInfo_SfxScriptLibraryContainer();
            }
        }
    }

//........................................................................
} // namespace basic
//........................................................................

IMPLEMENT_COMPONENT_LIBRARY_API( ::basic::BasicModule, ::basic::initializeModule )

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>maybe temporary fix for crash when accessing basic uno services<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include "sbmodule.hxx"

/** === begin UNO includes === **/
/** === end UNO includes === **/

//........................................................................
namespace basic
{
//........................................................................

    //--------------------------------------------------------------------
    extern void createRegistryInfo_SfxDialogLibraryContainer();
    extern void createRegistryInfo_SfxScriptLibraryContainer();

    static void initializeModule()
    {
        static bool bInitialized( false );
        if ( !bInitialized )
        {
            ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
            if ( !bInitialized )
            {
                static BasicModuleClient aClient;
                createRegistryInfo_SfxDialogLibraryContainer();
                createRegistryInfo_SfxScriptLibraryContainer();
            }
        }
    }

//........................................................................
} // namespace basic
//........................................................................

IMPLEMENT_COMPONENT_LIBRARY_API( ::basic::BasicModule, ::basic::initializeModule )

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*
  This file is part of the Grantlee template system.

  Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either version
  2.1 of the Licence, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "variable.h"

#include "abstractlocalizer.h"
#include "context.h"
#include "exception.h"
#include "metaenumvariable_p.h"
#include "metatype.h"
#include "util.h"

#include <QtCore/QMetaEnum>
#include <QtCore/QStringList>

using namespace Grantlee;

namespace Grantlee
{

class VariablePrivate
{
public:
  VariablePrivate( Variable *variable )
      : q_ptr( variable ),
        m_localize( false )
  {

  }

  Q_DECLARE_PUBLIC( Variable )
  Variable * const q_ptr;

  QString m_varString;
  QVariant m_literal;
  QStringList m_lookups;
  bool m_localize;
};

}

Variable::Variable( const Variable &other )
    : d_ptr( new VariablePrivate( this ) )
{
  d_ptr->m_varString = other.d_ptr->m_varString;
  d_ptr->m_literal = other.d_ptr->m_literal;
  d_ptr->m_lookups = other.d_ptr->m_lookups;
  d_ptr->m_localize = other.d_ptr->m_localize;
}

Variable::Variable()
    : d_ptr( new VariablePrivate( this ) )
{
}

Variable::~Variable()
{
  delete d_ptr;
}

Variable &Variable::operator=( const Variable & other )
{
  d_ptr->m_varString = other.d_ptr->m_varString;
  d_ptr->m_literal = other.d_ptr->m_literal;
  d_ptr->m_lookups = other.d_ptr->m_lookups;
  d_ptr->m_localize = other.d_ptr->m_localize;
  return *this;
}

Variable::Variable( const QString &var )
    : d_ptr( new VariablePrivate( this ) )
{
  Q_D( Variable );
  d->m_varString = var;

  QVariant v( var );
  QString localVar = var;
  if ( var.startsWith( QLatin1String( "_(" ) ) && var.endsWith( QLatin1Char( ')' ) ) ) {
    d->m_localize = true;
    localVar = var.mid( 2, var.size() - 3 );
    v = localVar;
  }
  if ( v.convert( QVariant::Double ) ) {
    d->m_literal = v;
    if ( !var.contains( QLatin1Char( '.' ) ) && !var.contains( QLatin1Char( 'e' ) ) ) {
      if ( var.endsWith( QLatin1Char( '.' ) ) ) {
//         throw Grantlee::Exception( VariableSyntaxError, QString( "Variable may not end with a dot: %1" ).arg( v.toString() ) );
      }
      d->m_literal = v.toInt();
    }
  } else {
    if (( localVar.startsWith( QLatin1Char( '"' ) ) && localVar.endsWith( QLatin1Char( '"' ) ) )
        || ( localVar.startsWith( QLatin1Char( '\'' ) ) && localVar.endsWith( QLatin1Char( '\'' ) ) ) ) {
      const QString unesc = unescapeStringLiteral( localVar );
      const Grantlee::SafeString ss = markSafe( unesc );
      d->m_literal = QVariant::fromValue<Grantlee::SafeString>( ss );
    } else {
      if ( localVar.contains( QLatin1String( "._" ) ) || ( localVar.startsWith( QLatin1Char( '_' ) ) ) ) {
        throw Grantlee::Exception( TagSyntaxError,
            QString::fromLatin1( "Variables and attributes may not begin with underscores: %1" ).arg( localVar ) );
      }
      d->m_lookups = localVar.split( QLatin1Char( '.' ) );
    }
  }
}

bool Variable::isValid() const
{
  Q_D( const Variable );
  return !d->m_varString.isEmpty();
}

bool Variable::isConstant() const
{
  Q_D( const Variable );
  return !d->m_literal.isNull();
}

bool Variable::isTrue( Context *c ) const
{
  return variantIsTrue( resolve( c ) );
}

bool Variable::isLocalized() const
{
  Q_D( const Variable );
  return d->m_localize;
}

QVariant Variable::literal() const
{
  Q_D( const Variable );
  return d->m_literal;
}

QStringList Variable::lookups() const
{
  Q_D( const Variable );
  return d->m_lookups;
}

class StaticQtMetaObject : public QObject
{
public:
  static const QMetaObject* _smo() { return &QObject::staticQtMetaObject; }
};

QVariant Variable::resolve( Context *c ) const
{
  Q_D( const Variable );
  QVariant var;
  if ( !d->m_lookups.isEmpty() ) {
    int i = 0;
    if ( d->m_lookups.at( i ) == QLatin1String( "Qt" ) ) {
      ++i;
      const QString nextPart = d->m_lookups.at( i );
      ++i;

      static const QMetaObject *globalMetaObject = StaticQtMetaObject::_smo();

      bool breakout = false;
      for ( int j = 0; j < globalMetaObject->enumeratorCount(); ++j ) {
        const QMetaEnum me = globalMetaObject->enumerator( j );

        if ( QLatin1String( me.name() ) == nextPart ) {
          const MetaEnumVariable mev( me );
          var = QVariant::fromValue( mev );
          break;
        }

        for ( int k = 0; k < me.keyCount(); ++k ) {
          if ( QLatin1String( me.key( k ) ) == nextPart ) {
            const MetaEnumVariable mev( me, k );
            var = QVariant::fromValue( mev );
            breakout = true;
            break;
          }
        }
        if ( breakout )
          break;
      }
      if ( !var.isValid() )
        return QVariant();

    } else {
      var = c->lookup( d->m_lookups.at( i++ ) );
    }
    while ( i < d->m_lookups.size() ) {
      var = MetaType::lookup( var, d->m_lookups.at( i++ ) );
      if ( !var.isValid() )
        return QVariant();
    }
  } else {
    if ( isSafeString( var ) )
      var = QVariant::fromValue( getSafeString( d->m_literal ) );
    else
      var = d->m_literal;
  }

  if ( supportedOutputType( var ) ) {
    if ( d->m_localize ) {
      return c->localizer()->localize( var );
    }
    return var;
  }
  // QStringList with size == 1 is special cased to be convertible to QString.
  // We make sure we don't accidentally invoke that.
  if ( var.type() != QVariant::StringList && var.canConvert( QVariant::String ) ) {
    if ( var.convert( QVariant::String ) ) {
      if ( d->m_localize ) {
        return QVariant::fromValue<Grantlee::SafeString>( c->localizer()->localize( var ) );
      }
      return QVariant::fromValue<Grantlee::SafeString>( var.toString() );
    }
    return QVariant();
  }
  // Could be a list, hash or enum.
  return var;
}
<commit_msg>Actually use the literal value instead of the (empty) var.<commit_after>/*
  This file is part of the Grantlee template system.

  Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either version
  2.1 of the Licence, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "variable.h"

#include "abstractlocalizer.h"
#include "context.h"
#include "exception.h"
#include "metaenumvariable_p.h"
#include "metatype.h"
#include "util.h"

#include <QtCore/QMetaEnum>
#include <QtCore/QStringList>

using namespace Grantlee;

namespace Grantlee
{

class VariablePrivate
{
public:
  VariablePrivate( Variable *variable )
      : q_ptr( variable ),
        m_localize( false )
  {

  }

  Q_DECLARE_PUBLIC( Variable )
  Variable * const q_ptr;

  QString m_varString;
  QVariant m_literal;
  QStringList m_lookups;
  bool m_localize;
};

}

Variable::Variable( const Variable &other )
    : d_ptr( new VariablePrivate( this ) )
{
  d_ptr->m_varString = other.d_ptr->m_varString;
  d_ptr->m_literal = other.d_ptr->m_literal;
  d_ptr->m_lookups = other.d_ptr->m_lookups;
  d_ptr->m_localize = other.d_ptr->m_localize;
}

Variable::Variable()
    : d_ptr( new VariablePrivate( this ) )
{
}

Variable::~Variable()
{
  delete d_ptr;
}

Variable &Variable::operator=( const Variable & other )
{
  d_ptr->m_varString = other.d_ptr->m_varString;
  d_ptr->m_literal = other.d_ptr->m_literal;
  d_ptr->m_lookups = other.d_ptr->m_lookups;
  d_ptr->m_localize = other.d_ptr->m_localize;
  return *this;
}

Variable::Variable( const QString &var )
    : d_ptr( new VariablePrivate( this ) )
{
  Q_D( Variable );
  d->m_varString = var;

  QVariant v( var );
  QString localVar = var;
  if ( var.startsWith( QLatin1String( "_(" ) ) && var.endsWith( QLatin1Char( ')' ) ) ) {
    d->m_localize = true;
    localVar = var.mid( 2, var.size() - 3 );
    v = localVar;
  }
  if ( v.convert( QVariant::Double ) ) {
    d->m_literal = v;
    if ( !var.contains( QLatin1Char( '.' ) ) && !var.contains( QLatin1Char( 'e' ) ) ) {
      if ( var.endsWith( QLatin1Char( '.' ) ) ) {
//         throw Grantlee::Exception( VariableSyntaxError, QString( "Variable may not end with a dot: %1" ).arg( v.toString() ) );
      }
      d->m_literal = v.toInt();
    }
  } else {
    if (( localVar.startsWith( QLatin1Char( '"' ) ) && localVar.endsWith( QLatin1Char( '"' ) ) )
        || ( localVar.startsWith( QLatin1Char( '\'' ) ) && localVar.endsWith( QLatin1Char( '\'' ) ) ) ) {
      const QString unesc = unescapeStringLiteral( localVar );
      const Grantlee::SafeString ss = markSafe( unesc );
      d->m_literal = QVariant::fromValue<Grantlee::SafeString>( ss );
    } else {
      if ( localVar.contains( QLatin1String( "._" ) ) || ( localVar.startsWith( QLatin1Char( '_' ) ) ) ) {
        throw Grantlee::Exception( TagSyntaxError,
            QString::fromLatin1( "Variables and attributes may not begin with underscores: %1" ).arg( localVar ) );
      }
      d->m_lookups = localVar.split( QLatin1Char( '.' ) );
    }
  }
}

bool Variable::isValid() const
{
  Q_D( const Variable );
  return !d->m_varString.isEmpty();
}

bool Variable::isConstant() const
{
  Q_D( const Variable );
  return !d->m_literal.isNull();
}

bool Variable::isTrue( Context *c ) const
{
  return variantIsTrue( resolve( c ) );
}

bool Variable::isLocalized() const
{
  Q_D( const Variable );
  return d->m_localize;
}

QVariant Variable::literal() const
{
  Q_D( const Variable );
  return d->m_literal;
}

QStringList Variable::lookups() const
{
  Q_D( const Variable );
  return d->m_lookups;
}

class StaticQtMetaObject : public QObject
{
public:
  static const QMetaObject* _smo() { return &QObject::staticQtMetaObject; }
};

QVariant Variable::resolve( Context *c ) const
{
  Q_D( const Variable );
  QVariant var;
  if ( !d->m_lookups.isEmpty() ) {
    int i = 0;
    if ( d->m_lookups.at( i ) == QLatin1String( "Qt" ) ) {
      ++i;
      const QString nextPart = d->m_lookups.at( i );
      ++i;

      static const QMetaObject *globalMetaObject = StaticQtMetaObject::_smo();

      bool breakout = false;
      for ( int j = 0; j < globalMetaObject->enumeratorCount(); ++j ) {
        const QMetaEnum me = globalMetaObject->enumerator( j );

        if ( QLatin1String( me.name() ) == nextPart ) {
          const MetaEnumVariable mev( me );
          var = QVariant::fromValue( mev );
          break;
        }

        for ( int k = 0; k < me.keyCount(); ++k ) {
          if ( QLatin1String( me.key( k ) ) == nextPart ) {
            const MetaEnumVariable mev( me, k );
            var = QVariant::fromValue( mev );
            breakout = true;
            break;
          }
        }
        if ( breakout )
          break;
      }
      if ( !var.isValid() )
        return QVariant();

    } else {
      var = c->lookup( d->m_lookups.at( i++ ) );
    }
    while ( i < d->m_lookups.size() ) {
      var = MetaType::lookup( var, d->m_lookups.at( i++ ) );
      if ( !var.isValid() )
        return QVariant();
    }
  } else {
    if ( isSafeString( d->m_literal ) )
      var = QVariant::fromValue( getSafeString( d->m_literal ) );
    else
      var = d->m_literal;
  }

  if ( supportedOutputType( var ) ) {
    if ( d->m_localize ) {
      return c->localizer()->localize( var );
    }
    return var;
  }
  // QStringList with size == 1 is special cased to be convertible to QString.
  // We make sure we don't accidentally invoke that.
  if ( var.type() != QVariant::StringList && var.canConvert( QVariant::String ) ) {
    if ( var.convert( QVariant::String ) ) {
      if ( d->m_localize ) {
        return QVariant::fromValue<Grantlee::SafeString>( c->localizer()->localize( var ) );
      }
      return QVariant::fromValue<Grantlee::SafeString>( var.toString() );
    }
    return QVariant();
  }
  // Could be a list, hash or enum.
  return var;
}
<|endoftext|>


<commit_before>/*=========================================================================
   Library:   TubeTK

   Copyright 2010 Kitware Inc. 28 Corporate Drive,
   Clifton Park, NY, 12065, USA.

   All rights reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
=========================================================================*/
#include <iostream>
#include <sstream>

#include "metaScene.h"

#include "tubeCLIProgressReporter.h"
#include "tubeMessage.h"
#include "tubeMacro.h"
#include "FillGapsInTubeTreeCLP.h"

#include "itkGroupSpatialObject.h"
#include "itkSpatialObjectReader.h"
#include "itkSpatialObjectWriter.h"
#include "itkVesselTubeSpatialObject.h"
#include "itkNumericTraits.h"

#include <itkTimeProbesCollectorBase.h>

template< unsigned int VDimension >
int DoIt( int argc, char * argv[] );

template< unsigned int VDimension >
int FillGap( typename itk::GroupSpatialObject< VDimension >::Pointer &pTubeGroup,
             std::string InterpolationMethod )
{
  //typedefs
  typedef itk::GroupSpatialObject< VDimension >         TubeGroupType;
  typedef typename TubeGroupType::ChildrenListPointer   TubeListPointerType;
  typedef itk::VesselTubeSpatialObject< VDimension >    TubeType;
  typedef typename TubeType::Pointer                    TubePointerType;
  typedef typename TubeType::TubePointType              TubePointType;
  typedef typename TubeType::PointType                  PositionType;
  typedef itk::IndexValueType                           TubeIdType;
  typedef typename TubeType::PointListType              TubePointListType;

  char tubeName[] = "Tube";
  TubeListPointerType pTubeList
    = pTubeGroup->GetChildren(
    pTubeGroup->GetMaximumDepth(), tubeName );

  for( typename TubeGroupType::ChildrenListType::iterator
    itSourceTubes = pTubeList->begin();
    itSourceTubes != pTubeList->end(); ++itSourceTubes )
    {
    TubePointerType pCurTube
      = dynamic_cast< TubeType * >( itSourceTubes->GetPointer() );
    TubeIdType curTubeId = pCurTube->GetId();
    TubeIdType curParentTubeId = pCurTube->GetParentId();
    TubePointType* parentNearestPoint;
    if( pCurTube->GetRoot() == false &&  curParentTubeId != pTubeGroup->GetId() )
      {
      //find parent target tube
      for( typename TubeGroupType::ChildrenListType::iterator
        itTubes = pTubeList->begin();
        itTubes != pTubeList->end(); ++itTubes )
        {
        TubePointerType pTube
          = dynamic_cast< TubeType * >( itTubes->GetPointer() );
        if( pTube->GetId() == curParentTubeId )
          {
          double minDistance = itk::NumericTraits<double>::max();
          int flag =-1;
          for ( int index = 0; index < pTube->GetNumberOfPoints(); index++ )
            {
            TubePointType* tubePoint =
            dynamic_cast< TubePointType* >( pTube->GetPoint( index ) );
            PositionType tubePointPosition = tubePoint->GetPosition();
            double distance = tubePointPosition.SquaredEuclideanDistanceTo
              ( pCurTube->GetPoint( 0 )->GetPosition() );
            if ( minDistance > distance )
              {
              minDistance = distance;
              parentNearestPoint = tubePoint;
              flag = 1;
              }
            distance = tubePointPosition.SquaredEuclideanDistanceTo
              ( pCurTube->GetPoint( pCurTube->GetNumberOfPoints() - 1 )->GetPosition() );
            if ( minDistance > distance )
              {
              minDistance = distance;
              parentNearestPoint = tubePoint;
              flag = 2;
              }
            }

          if( InterpolationMethod == "Straight_Line" )
            {
            if( flag == 1 )//add as the starting point
              {
              TubePointListType targetTubePoints = pCurTube->GetPoints();
              pCurTube->Clear();
              pCurTube->GetPoints().push_back(*parentNearestPoint);
              for( int i=0; i < targetTubePoints.size(); i++ )
                {
                pCurTube->GetPoints().push_back( targetTubePoints[i] );
                }
              }
            if( flag == 2 )// add as an end point
              {
              pCurTube->GetPoints().push_back( *parentNearestPoint );
              }
            }
          break;
          }
        }
      }
    }
  return EXIT_SUCCESS;
}

template< unsigned int VDimension >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // Ensure that the input image dimension is valid
  // We only support 2D and 3D Images due to the
  // limitation of itkTubeSpatialObject
  if ( VDimension != 2 && VDimension != 3 )
    {
    tube::ErrorMessage(
      "Error: Only 2D and 3D data is currently supported.");
    return EXIT_FAILURE;
    }
  // The timeCollector to perform basic profiling of algorithmic components
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter progressReporter( "FillGapsInTubeTree",
    CLPProcessInformation );
  progressReporter.Start();
  float progress = 0;

  timeCollector.Start( "Loading Input TRE File" );
  // Load TRE File
  tubeStandardOutputMacro( << "\n>> Loading TRE File" );

  typedef itk::SpatialObjectReader< VDimension > TubesReaderType;
  typename TubesReaderType::Pointer tubeFileReader = TubesReaderType::New();

  try
    {
    tubeFileReader->SetFileName( inputTree.c_str() );
    tubeFileReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading TRE File: "
      + std::string( err.GetDescription() ) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading Input TRE File" );
  progress = 0.25;

  timeCollector.Start( "Filling gaps in input tree" );
  tubeStandardOutputMacro( << "\n>> Filling gaps in input tree" );

  FillGap< VDimension >( tubeFileReader->GetGroup(), InterpolationMethod );

  timeCollector.Stop( "Filling gaps in input tree" );
  progress = 0.75;

  timeCollector.Start( "Writing the updates TRE file." );

  typedef itk::SpatialObjectWriter< VDimension > TubeWriterType;
  typename TubeWriterType::Pointer tubeWriter = TubeWriterType::New();

  try
    {
    tubeWriter->SetFileName( outputTree.c_str() );
    tubeWriter->SetInput( tubeFileReader->GetGroup() );
    tubeWriter->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error writing TRE file: "
      + std::string( err.GetDescription() ) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Writing the updates TRE file." );

  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End();

  timeCollector.Report();
  return EXIT_SUCCESS;
}

int main( int argc, char * argv[] )
{
  try
    {
    PARSE_ARGS;
    }
  catch ( const std::exception & err )
    {
    tube::ErrorMessage( err.what() );
    return EXIT_FAILURE;
    }
  PARSE_ARGS;

  MetaScene *mScene = new MetaScene;
  mScene->Read( inputTree.c_str() );
  if( mScene->GetObjectList()->empty() )
    {
    tubeWarningMacro( << "Input TRE file has no spatial objects" );
    return EXIT_SUCCESS;
    }

  switch( mScene->GetObjectList()->front()->NDims() )
    {
    case 2:
      return DoIt<2>( argc, argv );
      break;

    case 3:
      return DoIt<3>( argc, argv );
      break;

    default:
      tubeErrorMacro(<< "Error: Only 2D and 3D data is currently supported.");
      return EXIT_FAILURE;
    }
}
<commit_msg>COMP: Fixed compilation error.<commit_after>/*=========================================================================
   Library:   TubeTK

   Copyright 2010 Kitware Inc. 28 Corporate Drive,
   Clifton Park, NY, 12065, USA.

   All rights reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
=========================================================================*/
#include <iostream>
#include <sstream>

#include "metaScene.h"

#include "tubeCLIProgressReporter.h"
#include "tubeMessage.h"
#include "tubeMacro.h"
#include "FillGapsInTubeTreeCLP.h"

#include "itkGroupSpatialObject.h"
#include "itkSpatialObjectReader.h"
#include "itkSpatialObjectWriter.h"
#include "itkVesselTubeSpatialObject.h"
#include "itkNumericTraits.h"

#include <itkTimeProbesCollectorBase.h>

template< unsigned int VDimension >
int DoIt( int argc, char * argv[] );

template< unsigned int VDimension >
int FillGap( typename itk::GroupSpatialObject< VDimension >::Pointer &pTubeGroup,
             std::string InterpolationMethod )
{
  //typedefs
  typedef itk::GroupSpatialObject< VDimension >         TubeGroupType;
  typedef typename TubeGroupType::ChildrenListPointer   TubeListPointerType;
  typedef itk::VesselTubeSpatialObject< VDimension >    TubeType;
  typedef typename TubeType::Pointer                    TubePointerType;
  typedef typename TubeType::TubePointType              TubePointType;
  typedef typename TubeType::PointType                  PositionType;
  typedef itk::IndexValueType                           TubeIdType;
  typedef typename TubeType::PointListType              TubePointListType;

  char tubeName[] = "Tube";
  TubeListPointerType pTubeList
    = pTubeGroup->GetChildren(
    pTubeGroup->GetMaximumDepth(), tubeName );

  for( typename TubeGroupType::ChildrenListType::iterator
    itSourceTubes = pTubeList->begin();
    itSourceTubes != pTubeList->end(); ++itSourceTubes )
    {
    TubePointerType pCurTube
      = dynamic_cast< TubeType * >( itSourceTubes->GetPointer() );
    TubeIdType curTubeId = pCurTube->GetId();
    TubeIdType curParentTubeId = pCurTube->GetParentId();
    TubePointType* parentNearestPoint;
    if( pCurTube->GetRoot() == false &&  curParentTubeId != pTubeGroup->GetId() )
      {
      //find parent target tube
      for( typename TubeGroupType::ChildrenListType::iterator
        itTubes = pTubeList->begin();
        itTubes != pTubeList->end(); ++itTubes )
        {
        TubePointerType pTube
          = dynamic_cast< TubeType * >( itTubes->GetPointer() );
        if( pTube->GetId() == curParentTubeId )
          {
          double minDistance = itk::NumericTraits<double>::max();
          int flag =-1;
          for ( int index = 0; index < pTube->GetNumberOfPoints(); index++ )
            {
            TubePointType* tubePoint =
            dynamic_cast< TubePointType* >( pTube->GetPoint( index ) );
            PositionType tubePointPosition = tubePoint->GetPosition();
            double distance = tubePointPosition.SquaredEuclideanDistanceTo
              ( pCurTube->GetPoint( 0 )->GetPosition() );
            if ( minDistance > distance )
              {
              minDistance = distance;
              parentNearestPoint = tubePoint;
              flag = 1;
              }
            distance = tubePointPosition.SquaredEuclideanDistanceTo
              ( pCurTube->GetPoint( pCurTube->GetNumberOfPoints() - 1 )->GetPosition() );
            if ( minDistance > distance )
              {
              minDistance = distance;
              parentNearestPoint = tubePoint;
              flag = 2;
              }
            }

          if( InterpolationMethod == "Straight_Line" )
            {
            if( flag == 1 )//add as the starting point
              {
              TubePointListType targetTubePoints = pCurTube->GetPoints();
              pCurTube->Clear();
              pCurTube->GetPoints().push_back(*parentNearestPoint);
              for( int i=0; i < targetTubePoints.size(); i++ )
                {
                pCurTube->GetPoints().push_back( targetTubePoints[i] );
                }
              }
            if( flag == 2 )// add as an end point
              {
              pCurTube->GetPoints().push_back( *parentNearestPoint );
              }
            }
          break;
          }
        }
      }
    }
  return EXIT_SUCCESS;
}

template< unsigned int VDimension >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // Ensure that the input image dimension is valid
  // We only support 2D and 3D Images due to the
  // limitation of itkTubeSpatialObject
  if ( VDimension != 2 && VDimension != 3 )
    {
    tube::ErrorMessage(
      "Error: Only 2D and 3D data is currently supported.");
    return EXIT_FAILURE;
    }
  // The timeCollector to perform basic profiling of algorithmic components
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter progressReporter( "FillGapsInTubeTree",
    CLPProcessInformation );
  progressReporter.Start();
  float progress = 0;

  timeCollector.Start( "Loading Input TRE File" );
  // Load TRE File
  tubeStandardOutputMacro( << "\n>> Loading TRE File" );

  typedef itk::SpatialObjectReader< VDimension > TubesReaderType;
  typename TubesReaderType::Pointer tubeFileReader = TubesReaderType::New();

  try
    {
    tubeFileReader->SetFileName( inputTree.c_str() );
    tubeFileReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading TRE File: "
      + std::string( err.GetDescription() ) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading Input TRE File" );
  progress = 0.25;

  timeCollector.Start( "Filling gaps in input tree" );
  tubeStandardOutputMacro( << "\n>> Filling gaps in input tree" );

  typename itk::GroupSpatialObject< VDimension >::Pointer inputTubes;
  inputTubes = tubeFileReader->GetGroup();
  FillGap< VDimension >( inputTubes, InterpolationMethod );

  timeCollector.Stop( "Filling gaps in input tree" );
  progress = 0.75;

  timeCollector.Start( "Writing the updates TRE file." );

  typedef itk::SpatialObjectWriter< VDimension > TubeWriterType;
  typename TubeWriterType::Pointer tubeWriter = TubeWriterType::New();

  try
    {
    tubeWriter->SetFileName( outputTree.c_str() );
    tubeWriter->SetInput( tubeFileReader->GetGroup() );
    tubeWriter->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error writing TRE file: "
      + std::string( err.GetDescription() ) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Writing the updates TRE file." );

  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End();

  timeCollector.Report();
  return EXIT_SUCCESS;
}

int main( int argc, char * argv[] )
{
  try
    {
    PARSE_ARGS;
    }
  catch ( const std::exception & err )
    {
    tube::ErrorMessage( err.what() );
    return EXIT_FAILURE;
    }
  PARSE_ARGS;

  MetaScene *mScene = new MetaScene;
  mScene->Read( inputTree.c_str() );
  if( mScene->GetObjectList()->empty() )
    {
    tubeWarningMacro( << "Input TRE file has no spatial objects" );
    return EXIT_SUCCESS;
    }

  switch( mScene->GetObjectList()->front()->NDims() )
    {
    case 2:
      return DoIt<2>( argc, argv );
      break;

    case 3:
      return DoIt<3>( argc, argv );
      break;

    default:
      tubeErrorMacro(<< "Error: Only 2D and 3D data is currently supported.");
      return EXIT_FAILURE;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Trail of Bits, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

namespace {
DEF_SEM(DoCLD) {
  FLAG_DF = false;
  return memory;
}

DEF_SEM(DoSTD) {
  FLAG_DF = true;
  return memory;
}

DEF_SEM(DoCLC) {
  FLAG_CF = false;
  return memory;
}

DEF_SEM(DoCMC) {
  FLAG_CF = BNot(FLAG_CF);
  return memory;
}

DEF_SEM(DoSTC) {
  FLAG_CF = BNot(FLAG_CF);
  return memory;
}

DEF_SEM(DoSALC) {
  Write(REG_AL, Unsigned(FLAG_CF));
  return memory;
}

DEF_SEM(DoSAHF) {
  Flags flags = {ZExtTo<uint64_t>(Read(REG_AH))};
  FLAG_CF = UCmpEq(1, flags.cf);
  FLAG_PF = UCmpEq(1, flags.pf);
  FLAG_AF = UCmpEq(1, flags.af);
  FLAG_SF = UCmpEq(1, flags.sf);
  FLAG_ZF = UCmpEq(1, flags.zf);
  return memory;
}

DEF_SEM(DoLAHF) {
  Flags flags = {0};
  flags.cf = Unsigned(FLAG_CF);
  flags.must_be_1 = 1;
  flags.pf = Unsigned(FLAG_PF);
  flags.must_be_0a = 0;
  flags.af = Unsigned(FLAG_AF);
  flags.must_be_0b = 0;
  flags.zf = Unsigned(FLAG_ZF);
  flags.sf = Unsigned(FLAG_SF);
  Write(REG_AH, TruncTo<uint8_t>(flags.flat));
  return memory;
}

DEF_SEM(DoCLAC) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag.ac = false;
  return memory;
}

DEF_SEM(DoSTAC) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag.ac = true;
  return memory;
}

DEF_SEM(DoCLI) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag._if = false;
  return memory;
}

DEF_SEM(DoSTI) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag._if = true;
  return memory;
}
}  // namespace

DEF_ISEL(CLD) = DoCLD;
DEF_ISEL(STD) = DoSTD;
DEF_ISEL(CLC) = DoCLC;
DEF_ISEL(CMC) = DoCMC;
DEF_ISEL(STC) = DoSTC;
DEF_ISEL(SALC) = DoSALC;
DEF_ISEL(SAHF) = DoSAHF;
DEF_ISEL(LAHF) = DoLAHF;
DEF_ISEL(CLAC) = DoCLAC;
DEF_ISEL(STAC) = DoSTAC;
DEF_ISEL(CLI) = DoCLI;
DEF_ISEL(STI) = DoSTI;
<commit_msg>Fix semantics of STC.<commit_after>/*
 * Copyright (c) 2017 Trail of Bits, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

namespace {
DEF_SEM(DoCLD) {
  FLAG_DF = false;
  return memory;
}

DEF_SEM(DoSTD) {
  FLAG_DF = true;
  return memory;
}

DEF_SEM(DoCLC) {
  FLAG_CF = false;
  return memory;
}

DEF_SEM(DoCMC) {
  FLAG_CF = BNot(FLAG_CF);
  return memory;
}

DEF_SEM(DoSTC) {
  FLAG_CF = true;
  return memory;
}

DEF_SEM(DoSALC) {
  Write(REG_AL, Unsigned(FLAG_CF));
  return memory;
}

DEF_SEM(DoSAHF) {
  Flags flags = {ZExtTo<uint64_t>(Read(REG_AH))};
  FLAG_CF = UCmpEq(1, flags.cf);
  FLAG_PF = UCmpEq(1, flags.pf);
  FLAG_AF = UCmpEq(1, flags.af);
  FLAG_SF = UCmpEq(1, flags.sf);
  FLAG_ZF = UCmpEq(1, flags.zf);
  return memory;
}

DEF_SEM(DoLAHF) {
  Flags flags = {0};
  flags.cf = Unsigned(FLAG_CF);
  flags.must_be_1 = 1;
  flags.pf = Unsigned(FLAG_PF);
  flags.must_be_0a = 0;
  flags.af = Unsigned(FLAG_AF);
  flags.must_be_0b = 0;
  flags.zf = Unsigned(FLAG_ZF);
  flags.sf = Unsigned(FLAG_SF);
  Write(REG_AH, TruncTo<uint8_t>(flags.flat));
  return memory;
}

DEF_SEM(DoCLAC) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag.ac = false;
  return memory;
}

DEF_SEM(DoSTAC) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag.ac = true;
  return memory;
}

DEF_SEM(DoCLI) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag._if = false;
  return memory;
}

DEF_SEM(DoSTI) {
  memory = __remill_sync_hyper_call(
      state, memory, SyncHyperCall::kAssertPrivileged);
  state.rflag._if = true;
  return memory;
}
}  // namespace

DEF_ISEL(CLD) = DoCLD;
DEF_ISEL(STD) = DoSTD;
DEF_ISEL(CLC) = DoCLC;
DEF_ISEL(CMC) = DoCMC;
DEF_ISEL(STC) = DoSTC;
DEF_ISEL(SALC) = DoSALC;
DEF_ISEL(SAHF) = DoSAHF;
DEF_ISEL(LAHF) = DoLAHF;
DEF_ISEL(CLAC) = DoCLAC;
DEF_ISEL(STAC) = DoSTAC;
DEF_ISEL(CLI) = DoCLI;
DEF_ISEL(STI) = DoSTI;
<|endoftext|>


<commit_before>#include "LARA1GUN.H"

#include "CONTROL.H"
#include "SPECIFIC.H"
#ifdef PC_VERSION
#include "GAME.H"
#else
#include "SETUP.H"
#endif
#include "TOMB4FX.H"
#include "DRAW.H"
#include "LARA.H"
#include "LARAFIRE.H"
#include "MISC.H"
#include "OBJECTS.H"
#include "ITEMS.H"

char HKTimer = 0;
char HKShotsFired = 0;

void TriggerGrapplingEffect(long x, long y, long z)//44138(<), ? (F)
{
	long size;
	long lp;
	struct SMOKE_SPARKS* sptr;

	//loc_4416C
	for(lp = 0; lp < 24; lp++)
	{
		sptr = &smoke_spark[GetFreeSmokeSpark()];
		sptr->On = 1;

		sptr->sShade = (GetRandomControl() & 0xF) + 40;
		sptr->dShade = (GetRandomControl() & 0xF) + 64;
		sptr->ColFadeSpeed = 4;
		sptr->FadeToBlack = 16;

		sptr->Life = sptr->sLife = (GetRandomControl() & 3) + 40;
		sptr->TransType = 2;

		sptr->x = x + (GetRandomControl() & 0x1F) - 16;
		sptr->y = y + (GetRandomControl() & 0x1F) - 16;
		sptr->z = z + (GetRandomControl() & 0x1F) - 16;

		sptr->Xvel = (GetRandomControl() & 0x1FF) - 256 << 1;
		sptr->Zvel = (GetRandomControl() & 0x1FF) - 256 << 1;

		if (lp < 12)
		{
			sptr->Yvel = (GetRandomControl() & 0x1F);
			sptr->Friction = 64;
		}
		else
		{
			//loc_4426C
			sptr->Yvel = (GetRandomControl() & 0x1FF) + 256;
			sptr->Friction = 82;
		}

		//loc_44284
		sptr->Flags = 16;
		sptr->RotAng = (GetRandomControl() & 0xFFF);
		sptr->RotAdd = (GetRandomControl() & 0x40) - 32;
		sptr->MaxYvel = 0;
		sptr->Gravity = 0;

		size = (GetRandomControl() & 0xF) + 48;

		sptr->dSize = size << 1;
		sptr->sSize = size >> 2;
		sptr->Size = size >> 2;
		sptr->mirror = 0;
	}
}

void DoGrenadeDamageOnBaddie(struct ITEM_INFO* baddie, struct ITEM_INFO* item)
{
	UNIMPLEMENTED();
}

void AnimateShotgun(int weapon_type)
{
	UNIMPLEMENTED();
}

void undraw_shotgun(int weapon_type)//436B0(<), 43B14(<) (F)
{
	struct ITEM_INFO* item = &items[lara.weapon_item];
	AnimateItem(item);

	if (item->status == ITEM_DEACTIVATED)
	{
		lara.gun_status = LG_NO_ARMS;
		lara.target = NULL;
		lara.right_arm.lock = 0;
		lara.left_arm.lock = 0;
		KillItem(lara.weapon_item);
		lara.weapon_item = -1;
		lara.right_arm.frame_number = 0;
		lara.left_arm.frame_number = 0;
	}//loc_43750
	else
	{
		if (item->current_anim_state == STATE_LARA_JUMP_FORWARD)
		{
			if (anims[item->anim_number].frame_base == item->frame_number - 21)
			{
				undraw_shotgun_meshes(weapon_type);
			}
		}//loc_43798
	}

	lara.right_arm.frame_base = anims[item->frame_number].frame_ptr;
	lara.left_arm.frame_base = anims[item->frame_number].frame_ptr;

	lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;

	lara.right_arm.anim_number = item->anim_number;
	lara.left_arm.anim_number = item->anim_number;
}

void draw_shotgun(int weapon_type)// (F)
{
	struct ITEM_INFO* item;

	if (lara.weapon_item == -1)
	{
		lara.weapon_item = CreateItem();
		item = &items[lara.weapon_item];
		item->object_number = WeaponObject(weapon_type);
		item->anim_number = objects[item->object_number].anim_index;
		item->frame_number = anims[item->anim_number].frame_base;
		item->status = ITEM_ACTIVE;
		item->goal_anim_state = STATE_LARA_RUN_FORWARD;
		item->current_anim_state = STATE_LARA_RUN_FORWARD;
		item->room_number = NO_ROOM;

		lara.left_arm.frame_base = lara.right_arm.frame_base = objects[item->object_number].frame_base;
	}
	else
	{
		item = &items[lara.weapon_item];
	}

	AnimateItem(item);

	if (item->current_anim_state != STATE_LARA_WALK_FORWARD &&
		item->current_anim_state != STATE_LARA_TURN_RIGHT_SLOW)
	{
		if (item->frame_number - anims[item->anim_number].frame_base == weapons[weapon_type].draw_frame)
		{
			draw_shotgun_meshes(weapon_type);
		}
		else if (lara.water_status == LW_UNDERWATER)
		{
			item->goal_anim_state = STATE_LARA_TURN_RIGHT_SLOW;
		}
	}
	else
	{
		ready_shotgun(weapon_type);
	}

	lara.left_arm.frame_base = lara.right_arm.frame_base = anims[item->anim_number].frame_ptr;
	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.anim_number = lara.right_arm.anim_number = item->anim_number;
}

void ControlCrossbow(short item_number)
{
	UNIMPLEMENTED();
}

void CrossbowHitSwitchType78(struct ITEM_INFO* item, struct ITEM_INFO* target, int MustHitLastNode)
{
	UNIMPLEMENTED();
}

void FireCrossbow(struct PHD_3DPOS* Start)
{
	UNIMPLEMENTED();
}

void FireHK(int running)
{
	UNIMPLEMENTED();
}

void FireShotgun()
{
	UNIMPLEMENTED();
}

void RifleHandler(int weapon_type)
{
	UNIMPLEMENTED();
}

void ready_shotgun(int weapon_type)//424E0(<), 42934(<) (F)
{
	struct object_info* object;

	lara.gun_status = LG_READY;
	lara.left_arm.z_rot = 0;
	lara.left_arm.y_rot = 0;
	lara.left_arm.x_rot = 0;

	lara.right_arm.z_rot = 0;
	lara.right_arm.x_rot = 0;
	lara.right_arm.y_rot = 0;

	lara.right_arm.frame_number = 0;
	lara.left_arm.frame_number = 0;

	lara.right_arm.lock = 0;
	lara.left_arm.lock = 0;
	lara.target = NULL;

	object = &objects[WeaponObject(weapon_type)];//v1

	lara.right_arm.frame_base = object->frame_base;
	lara.left_arm.frame_base = object->frame_base;

	return;
}

void undraw_shotgun_meshes(int weapon_type)//42498(<), 428EC(<) (F)
{
	lara.back_gun = WeaponObject(weapon_type);
	lara.mesh_ptrs[LM_RHAND] = meshes[objects[LARA].mesh_index + 2 * LM_RHAND];
}

void draw_shotgun_meshes(int weapon_type)//42444(<), 42898(<) (F)
{
	lara.back_gun = WEAPON_NONE;
	lara.mesh_ptrs[LM_RHAND] = meshes[objects[WeaponObjectMesh(weapon_type)].mesh_index + 2 * LM_RHAND];
}<commit_msg>Add DoGrenadeDamageOnBaddie<commit_after>#include "LARA1GUN.H"

#include "BOX.H"
#include "CONTROL.H"
#include "SAVEGAME.H"
#include "SPECIFIC.H"
#ifdef PC_VERSION
#include "GAME.H"
#else
#include "SETUP.H"
#endif
#include "TOMB4FX.H"
#include "TRAPS.H"
#include "DRAW.H"
#include "LARA.H"
#include "LARAFIRE.H"
#include "MISC.H"
#include "OBJECTS.H"
#include "ITEMS.H"

char HKTimer = 0;
char HKShotsFired = 0;

void TriggerGrapplingEffect(long x, long y, long z)//44138(<), ? (F)
{
	long size;
	long lp;
	struct SMOKE_SPARKS* sptr;

	//loc_4416C
	for(lp = 0; lp < 24; lp++)
	{
		sptr = &smoke_spark[GetFreeSmokeSpark()];
		sptr->On = 1;

		sptr->sShade = (GetRandomControl() & 0xF) + 40;
		sptr->dShade = (GetRandomControl() & 0xF) + 64;
		sptr->ColFadeSpeed = 4;
		sptr->FadeToBlack = 16;

		sptr->Life = sptr->sLife = (GetRandomControl() & 3) + 40;
		sptr->TransType = 2;

		sptr->x = x + (GetRandomControl() & 0x1F) - 16;
		sptr->y = y + (GetRandomControl() & 0x1F) - 16;
		sptr->z = z + (GetRandomControl() & 0x1F) - 16;

		sptr->Xvel = ((GetRandomControl() & 0x1FF) - 256) << 1;
		sptr->Zvel = ((GetRandomControl() & 0x1FF) - 256) << 1;

		if (lp < 12)
		{
			sptr->Yvel = (GetRandomControl() & 0x1F);
			sptr->Friction = 64;
		}
		else
		{
			//loc_4426C
			sptr->Yvel = (GetRandomControl() & 0x1FF) + 256;
			sptr->Friction = 82;
		}

		//loc_44284
		sptr->Flags = 16;
		sptr->RotAng = (GetRandomControl() & 0xFFF);
		sptr->RotAdd = (GetRandomControl() & 0x40) - 32;
		sptr->MaxYvel = 0;
		sptr->Gravity = 0;

		size = (GetRandomControl() & 0xF) + 48;

		sptr->dSize = size << 1;
		sptr->sSize = size >> 2;
		sptr->Size = size >> 2;
		sptr->mirror = 0;
	}
}

void DoGrenadeDamageOnBaddie(struct ITEM_INFO* baddie, struct ITEM_INFO* item)//43FB0(<), ? (F)
{
	if (!(baddie->flags & 0x8000))
	{
		if (baddie == lara_item && baddie->hit_points > 0)
		{
			baddie->hit_points -= 50;

			if (!(room[item->room_number].flags & RF_FILL_WATER) && baddie->hit_points < 51)
			{
				LaraBurn();
			}//loc_44128
		}
		else
		{
			//loc_4404C
			if (item->item_flags[2] == 0)
			{
				baddie->hit_status = 1;

				if (!objects[baddie->object_number].undead)
				{
					HitTarget(baddie, NULL, 30, 1);

					if (baddie != lara_item)
					{
						savegame.Game.AmmoHits++;

						if (baddie->hit_points <= 0)
						{
							savegame.Level.Kills++;
							CreatureDie((baddie - items), 1);
						}//loc_44128
					}//loc_44128
				}//loc_44128
			}//loc_44128
		}
	}//loc_44128
}

void AnimateShotgun(int weapon_type)
{
	UNIMPLEMENTED();
}

void undraw_shotgun(int weapon_type)//436B0(<), 43B14(<) (F)
{
	struct ITEM_INFO* item = &items[lara.weapon_item];
	AnimateItem(item);

	if (item->status == ITEM_DEACTIVATED)
	{
		lara.gun_status = LG_NO_ARMS;
		lara.target = NULL;
		lara.right_arm.lock = 0;
		lara.left_arm.lock = 0;
		KillItem(lara.weapon_item);
		lara.weapon_item = -1;
		lara.right_arm.frame_number = 0;
		lara.left_arm.frame_number = 0;
	}//loc_43750
	else
	{
		if (item->current_anim_state == STATE_LARA_JUMP_FORWARD)
		{
			if (anims[item->anim_number].frame_base == item->frame_number - 21)
			{
				undraw_shotgun_meshes(weapon_type);
			}
		}//loc_43798
	}

	lara.right_arm.frame_base = anims[item->frame_number].frame_ptr;
	lara.left_arm.frame_base = anims[item->frame_number].frame_ptr;

	lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;

	lara.right_arm.anim_number = item->anim_number;
	lara.left_arm.anim_number = item->anim_number;
}

void draw_shotgun(int weapon_type)// (F)
{
	struct ITEM_INFO* item;

	if (lara.weapon_item == -1)
	{
		lara.weapon_item = CreateItem();
		item = &items[lara.weapon_item];
		item->object_number = WeaponObject(weapon_type);
		item->anim_number = objects[item->object_number].anim_index;
		item->frame_number = anims[item->anim_number].frame_base;
		item->status = ITEM_ACTIVE;
		item->goal_anim_state = STATE_LARA_RUN_FORWARD;
		item->current_anim_state = STATE_LARA_RUN_FORWARD;
		item->room_number = NO_ROOM;

		lara.left_arm.frame_base = lara.right_arm.frame_base = objects[item->object_number].frame_base;
	}
	else
	{
		item = &items[lara.weapon_item];
	}

	AnimateItem(item);

	if (item->current_anim_state != STATE_LARA_WALK_FORWARD &&
		item->current_anim_state != STATE_LARA_TURN_RIGHT_SLOW)
	{
		if (item->frame_number - anims[item->anim_number].frame_base == weapons[weapon_type].draw_frame)
		{
			draw_shotgun_meshes(weapon_type);
		}
		else if (lara.water_status == LW_UNDERWATER)
		{
			item->goal_anim_state = STATE_LARA_TURN_RIGHT_SLOW;
		}
	}
	else
	{
		ready_shotgun(weapon_type);
	}

	lara.left_arm.frame_base = lara.right_arm.frame_base = anims[item->anim_number].frame_ptr;
	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.anim_number = lara.right_arm.anim_number = item->anim_number;
}

void ControlCrossbow(short item_number)
{
	UNIMPLEMENTED();
}

void CrossbowHitSwitchType78(struct ITEM_INFO* item, struct ITEM_INFO* target, int MustHitLastNode)
{
	UNIMPLEMENTED();
}

void FireCrossbow(struct PHD_3DPOS* Start)
{
	UNIMPLEMENTED();
}

void FireHK(int running)
{
	UNIMPLEMENTED();
}

void FireShotgun()
{
	UNIMPLEMENTED();
}

void RifleHandler(int weapon_type)
{
	UNIMPLEMENTED();
}

void ready_shotgun(int weapon_type)//424E0(<), 42934(<) (F)
{
	struct object_info* object;

	lara.gun_status = LG_READY;
	lara.left_arm.z_rot = 0;
	lara.left_arm.y_rot = 0;
	lara.left_arm.x_rot = 0;

	lara.right_arm.z_rot = 0;
	lara.right_arm.x_rot = 0;
	lara.right_arm.y_rot = 0;

	lara.right_arm.frame_number = 0;
	lara.left_arm.frame_number = 0;

	lara.right_arm.lock = 0;
	lara.left_arm.lock = 0;
	lara.target = NULL;

	object = &objects[WeaponObject(weapon_type)];//v1

	lara.right_arm.frame_base = object->frame_base;
	lara.left_arm.frame_base = object->frame_base;

	return;
}

void undraw_shotgun_meshes(int weapon_type)//42498(<), 428EC(<) (F)
{
	lara.back_gun = WeaponObject(weapon_type);
	lara.mesh_ptrs[LM_RHAND] = meshes[objects[LARA].mesh_index + 2 * LM_RHAND];
}

void draw_shotgun_meshes(int weapon_type)//42444(<), 42898(<) (F)
{
	lara.back_gun = WEAPON_NONE;
	lara.mesh_ptrs[LM_RHAND] = meshes[objects[WeaponObjectMesh(weapon_type)].mesh_index + 2 * LM_RHAND];
}<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 * Copyright (c) 2014 Crytek
 *
 * 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 "os/os_specific.h"
#include "api/app/renderdoc_app.h"
#include "api/replay/capture_options.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <libgen.h>

#include "serialise/string_utils.h"

static vector<Process::EnvironmentModification> &GetEnvModifications()
{
	static vector<Process::EnvironmentModification> envCallbacks;
	return envCallbacks;
}

static map<string, string> EnvStringToEnvMap(const char **envstring)
{
	map<string, string> ret;

	const char **e = envstring;

	while(*e)
	{
		const char *equals = strchr(*e, '=');

		string name;
		string value;

		name.assign(*e, equals);
		value = equals+1;

		ret[name] = value;

		e++;
	}

	return ret;
}

void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif)
{
	GetEnvModifications().push_back(modif);
}

// on linux we apply environment changes before launching the program, as
// there is no support for injecting/loading renderdoc into a running program
// in any way, and we also have some environment changes that we *have* to make
// for correct hooking (LD_LIBRARY_PATH/LD_PRELOAD)
void Process::ApplyEnvironmentModification()
{
}

static pid_t RunProcess(const char *app, const char *workingDir, const char *cmdLine, char *const *envp)
{
	if(!app) return (pid_t)0;

	// it is safe to use app directly as execve never modifies argv
	char *emptyargv[] = { (char *) app, NULL };
	char **argv = emptyargv;

	const char *c = cmdLine;

	// parse command line into argv[], similar to how bash would
	if(cmdLine)
	{
		int argc = 1;

		// get a rough upper bound on the number of arguments
		while(*c)
		{
			if(*c == ' ' || *c == '\t') argc++;
			c++;
		}

		argv = new char*[argc+2];

		c = cmdLine;

		string a;

		argc = 0; // current argument we're fetching

		// argv[0] is the application name, by convention
		size_t len = strlen(app)+1;
		argv[argc] = new char[len];
		strcpy(argv[argc], app);

		argc++;

		bool dquot = false, squot = false; // are we inside ''s or ""s
		while(*c)
		{
			if(!dquot && !squot && (*c == ' ' || *c == '\t'))
			{
				if(!a.empty())
				{
					// if we've fetched some number of non-space characters
					argv[argc] = new char[a.length()+1];
					memcpy(argv[argc], a.c_str(), a.length()+1);
					argc++;
				}

				a = "";
			}
			else if(!dquot && *c == '"')
			{
				dquot = true;
			}
			else if(!squot && *c == '\'')
			{
				squot = true;
			}
			else if(dquot && *c == '"')
			{
				dquot = false;
			}
			else if(squot && *c == '\'')
			{
				squot = false;
			}
			else if(squot)
			{
				// single quotes don't escape, just copy literally until we leave single quote mode
				a.push_back(*c);
			}
			else if(dquot)
			{
				// handle escaping
				if(*c == '\\')
				{
					c++;
					if(*c)
					{
						a.push_back(*c);
					}
					else
					{
						RDCERR("Malformed command line:\n%s", cmdLine);
						return 0;
					}
				}
				else
				{
					a.push_back(*c);
				}
			}
			else
			{
				a.push_back(*c);
			}

			c++;
		}

		if(!a.empty())
		{
			// if we've fetched some number of non-space characters
			argv[argc] = new char[a.length()+1];
			memcpy(argv[argc], a.c_str(), a.length()+1);
			argc++;
		}

		argv[argc] = NULL;

		if(squot || dquot)
		{
			RDCERR("Malformed command line\n%s", cmdLine);
			return 0;
		}
	}

	pid_t childPid = fork();
	if(childPid == 0)
	{
		if(workingDir)
		{
			chdir(workingDir);
		}
		else
		{
			string exedir = app;
			chdir(dirname((char *)exedir.c_str()));
		}

		execve(app, argv, envp);
		RDCERR("Failed to execute %s: %s", app, strerror(errno));
		exit(0);
	}

	char **argv_delete = argv;

	if(argv != emptyargv)
	{
		while(*argv)
		{
			delete[] *argv;
			argv++;
		}

		delete[] argv_delete;
	}

	return childPid;
}

uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	RDCUNIMPLEMENTED("Injecting into already running processes on linux");
	return 0;
}

uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const char *cmdLine)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	return (uint32_t)RunProcess(app, workingDir, cmdLine, environ);
}

uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine,
                                             const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	// turn environment string to a UTF-8 map
	map<string, string> env = EnvStringToEnvMap((const char **)environ);
	vector<EnvironmentModification> &modifications = GetEnvModifications();

	if (logfile == NULL)
		logfile = "";

	string libpath;
	{
		FileIO::GetExecutableFilename(libpath);
		libpath = dirname(libpath);
	}

	string optstr;
	{
		optstr.reserve(sizeof(CaptureOptions)*2+1);
		byte *b = (byte *)opts;
		for(size_t i=0; i < sizeof(CaptureOptions); i++)
		{
			optstr.push_back(char( 'a' + ((b[i] >> 4)&0xf) ));
			optstr.push_back(char( 'a' + ((b[i]     )&0xf) ));
		}
	}

	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_LIBRARY_PATH", libpath.c_str()));
	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_PRELOAD", "librenderdoc.so"));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_LOGFILE", logfile));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_CAPTUREOPTS", optstr.c_str()));

	for(size_t i=0; i < modifications.size(); i++)
	{
		EnvironmentModification &m = modifications[i];

		string &value = env[m.name];

		switch(m.type)
		{
			case eEnvModification_Replace:
				value = m.value;
				break;
			case eEnvModification_Append:
				value += m.value;
				break;
			case eEnvModification_AppendPlatform:
			case eEnvModification_AppendColon:
				if(!value.empty())
					value += ":";
				value += m.value;
				break;
			case eEnvModification_AppendSemiColon:
				if(!value.empty())
					value += ";";
				value += m.value;
				break;
			case eEnvModification_Prepend:
				value = m.value + value;
				break;
			case eEnvModification_PrependColon:
				if(!value.empty())
					value = m.value + ":" + value;
				else
					value = m.value;
				break;
			case eEnvModification_PrependPlatform:
			case eEnvModification_PrependSemiColon:
				if(!value.empty())
					value = m.value + ";" + value;
				else
					value = m.value;
				break;
			default:
				RDCERR("Unexpected environment modification type");
		}
	}

	char **envp = new char *[env.size()+1];
	envp[env.size()] = NULL;

	int i=0;
	for(auto it=env.begin(); it != env.end(); it++)
	{
		string envline = it->first + "=" + it->second;
		envp[i] = new char[envline.size()+1];
		memcpy(envp[i], envline.c_str(), envline.size()+1);
		i++;
	}

	pid_t childPid = RunProcess(app, workingDir, cmdLine, envp);

	int ret = 0;

	if(childPid != (pid_t)0)
	{
		// wait for child to have /proc/<pid> and read out tcp socket
		usleep(1000);

		string procfile = StringFormat::Fmt("/proc/%d/net/tcp", (int)childPid);

		// try for a little while for the /proc entry to appear
		for(int retry=0; retry < 10; retry++)
		{
			// back-off for each retry
			usleep(1000 + 500 * retry);

			FILE *f =	FileIO::fopen(procfile.c_str(), "r");

			if(f == NULL)
			{
				// try again in a bit
				continue;
			}

			// read through the proc file to check for an open listen socket
			while(ret == 0 && !feof(f))
			{
				const size_t sz = 512;
				char line[sz];line[sz-1] = 0;
				fgets(line, sz-1, f);

				int socketnum = 0, hexip = 0, hexport = 0;
				int num = sscanf(line, " %d: %x:%x", &socketnum, &hexip, &hexport);

				// find open listen socket on 0.0.0.0:port
				if(num == 3 && hexip == 0 &&
						hexport >= RenderDoc_FirstCaptureNetworkPort &&
						hexport <= RenderDoc_LastCaptureNetworkPort)
				{
					ret = hexport;
				}
			}

			FileIO::fclose(f);
		}

		if(waitForExit)
		{
			int dummy = 0;
			waitpid(childPid, &dummy, 0);
		}
	}

	char **envp_delete = envp;

	while(*envp)
	{
		delete[] *envp;
		envp++;
	}

	delete[] envp_delete;

	return ret;
}

void Process::StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions *opts)
{
	RDCUNIMPLEMENTED("Global hooking of all processes on linux");
}

void *Process::LoadModule(const char *module)
{
	return dlopen(module, RTLD_NOW);
}

void *Process::GetFunctionAddress(void *module, const char *function)
{
	if(module == NULL) return NULL;

	return dlsym(module, function);
}

uint32_t Process::GetCurrentPID()
{
	return (uint32_t)getpid();
}
<commit_msg>Use our version of dirname on Linux<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Baldur Karlsson
 * Copyright (c) 2014 Crytek
 *
 * 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 "os/os_specific.h"
#include "api/app/renderdoc_app.h"
#include "api/replay/capture_options.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>

#include "serialise/string_utils.h"

static vector<Process::EnvironmentModification> &GetEnvModifications()
{
	static vector<Process::EnvironmentModification> envCallbacks;
	return envCallbacks;
}

static map<string, string> EnvStringToEnvMap(const char **envstring)
{
	map<string, string> ret;

	const char **e = envstring;

	while(*e)
	{
		const char *equals = strchr(*e, '=');

		string name;
		string value;

		name.assign(*e, equals);
		value = equals+1;

		ret[name] = value;

		e++;
	}

	return ret;
}

void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif)
{
	GetEnvModifications().push_back(modif);
}

// on linux we apply environment changes before launching the program, as
// there is no support for injecting/loading renderdoc into a running program
// in any way, and we also have some environment changes that we *have* to make
// for correct hooking (LD_LIBRARY_PATH/LD_PRELOAD)
void Process::ApplyEnvironmentModification()
{
}

static pid_t RunProcess(const char *app, const char *workingDir, const char *cmdLine, char *const *envp)
{
	if(!app) return (pid_t)0;

	// it is safe to use app directly as execve never modifies argv
	char *emptyargv[] = { (char *) app, NULL };
	char **argv = emptyargv;

	const char *c = cmdLine;

	// parse command line into argv[], similar to how bash would
	if(cmdLine)
	{
		int argc = 1;

		// get a rough upper bound on the number of arguments
		while(*c)
		{
			if(*c == ' ' || *c == '\t') argc++;
			c++;
		}

		argv = new char*[argc+2];

		c = cmdLine;

		string a;

		argc = 0; // current argument we're fetching

		// argv[0] is the application name, by convention
		size_t len = strlen(app)+1;
		argv[argc] = new char[len];
		strcpy(argv[argc], app);

		argc++;

		bool dquot = false, squot = false; // are we inside ''s or ""s
		while(*c)
		{
			if(!dquot && !squot && (*c == ' ' || *c == '\t'))
			{
				if(!a.empty())
				{
					// if we've fetched some number of non-space characters
					argv[argc] = new char[a.length()+1];
					memcpy(argv[argc], a.c_str(), a.length()+1);
					argc++;
				}

				a = "";
			}
			else if(!dquot && *c == '"')
			{
				dquot = true;
			}
			else if(!squot && *c == '\'')
			{
				squot = true;
			}
			else if(dquot && *c == '"')
			{
				dquot = false;
			}
			else if(squot && *c == '\'')
			{
				squot = false;
			}
			else if(squot)
			{
				// single quotes don't escape, just copy literally until we leave single quote mode
				a.push_back(*c);
			}
			else if(dquot)
			{
				// handle escaping
				if(*c == '\\')
				{
					c++;
					if(*c)
					{
						a.push_back(*c);
					}
					else
					{
						RDCERR("Malformed command line:\n%s", cmdLine);
						return 0;
					}
				}
				else
				{
					a.push_back(*c);
				}
			}
			else
			{
				a.push_back(*c);
			}

			c++;
		}

		if(!a.empty())
		{
			// if we've fetched some number of non-space characters
			argv[argc] = new char[a.length()+1];
			memcpy(argv[argc], a.c_str(), a.length()+1);
			argc++;
		}

		argv[argc] = NULL;

		if(squot || dquot)
		{
			RDCERR("Malformed command line\n%s", cmdLine);
			return 0;
		}
	}

	pid_t childPid = fork();
	if(childPid == 0)
	{
		if(workingDir)
		{
			chdir(workingDir);
		}
		else
		{
			string exedir = app;
			chdir(dirname(exedir).c_str());
		}

		execve(app, argv, envp);
		RDCERR("Failed to execute %s: %s", app, strerror(errno));
		exit(0);
	}

	char **argv_delete = argv;

	if(argv != emptyargv)
	{
		while(*argv)
		{
			delete[] *argv;
			argv++;
		}

		delete[] argv_delete;
	}

	return childPid;
}

uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	RDCUNIMPLEMENTED("Injecting into already running processes on linux");
	return 0;
}

uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const char *cmdLine)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	return (uint32_t)RunProcess(app, workingDir, cmdLine, environ);
}

uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine,
                                             const char *logfile, const CaptureOptions *opts, bool waitForExit)
{
	if(app == NULL || app[0] == 0)
	{
		RDCERR("Invalid empty 'app'");
		return 0;
	}

	// turn environment string to a UTF-8 map
	map<string, string> env = EnvStringToEnvMap((const char **)environ);
	vector<EnvironmentModification> &modifications = GetEnvModifications();

	if (logfile == NULL)
		logfile = "";

	string libpath;
	{
		FileIO::GetExecutableFilename(libpath);
		libpath = dirname(libpath);
	}

	string optstr;
	{
		optstr.reserve(sizeof(CaptureOptions)*2+1);
		byte *b = (byte *)opts;
		for(size_t i=0; i < sizeof(CaptureOptions); i++)
		{
			optstr.push_back(char( 'a' + ((b[i] >> 4)&0xf) ));
			optstr.push_back(char( 'a' + ((b[i]     )&0xf) ));
		}
	}

	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_LIBRARY_PATH", libpath.c_str()));
	modifications.push_back(EnvironmentModification(eEnvModification_AppendPlatform, "LD_PRELOAD", "librenderdoc.so"));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_LOGFILE", logfile));
	modifications.push_back(EnvironmentModification(eEnvModification_Replace, "RENDERDOC_CAPTUREOPTS", optstr.c_str()));

	for(size_t i=0; i < modifications.size(); i++)
	{
		EnvironmentModification &m = modifications[i];

		string &value = env[m.name];

		switch(m.type)
		{
			case eEnvModification_Replace:
				value = m.value;
				break;
			case eEnvModification_Append:
				value += m.value;
				break;
			case eEnvModification_AppendPlatform:
			case eEnvModification_AppendColon:
				if(!value.empty())
					value += ":";
				value += m.value;
				break;
			case eEnvModification_AppendSemiColon:
				if(!value.empty())
					value += ";";
				value += m.value;
				break;
			case eEnvModification_Prepend:
				value = m.value + value;
				break;
			case eEnvModification_PrependColon:
				if(!value.empty())
					value = m.value + ":" + value;
				else
					value = m.value;
				break;
			case eEnvModification_PrependPlatform:
			case eEnvModification_PrependSemiColon:
				if(!value.empty())
					value = m.value + ";" + value;
				else
					value = m.value;
				break;
			default:
				RDCERR("Unexpected environment modification type");
		}
	}

	char **envp = new char *[env.size()+1];
	envp[env.size()] = NULL;

	int i=0;
	for(auto it=env.begin(); it != env.end(); it++)
	{
		string envline = it->first + "=" + it->second;
		envp[i] = new char[envline.size()+1];
		memcpy(envp[i], envline.c_str(), envline.size()+1);
		i++;
	}

	pid_t childPid = RunProcess(app, workingDir, cmdLine, envp);

	int ret = 0;

	if(childPid != (pid_t)0)
	{
		// wait for child to have /proc/<pid> and read out tcp socket
		usleep(1000);

		string procfile = StringFormat::Fmt("/proc/%d/net/tcp", (int)childPid);

		// try for a little while for the /proc entry to appear
		for(int retry=0; retry < 10; retry++)
		{
			// back-off for each retry
			usleep(1000 + 500 * retry);

			FILE *f =	FileIO::fopen(procfile.c_str(), "r");

			if(f == NULL)
			{
				// try again in a bit
				continue;
			}

			// read through the proc file to check for an open listen socket
			while(ret == 0 && !feof(f))
			{
				const size_t sz = 512;
				char line[sz];line[sz-1] = 0;
				fgets(line, sz-1, f);

				int socketnum = 0, hexip = 0, hexport = 0;
				int num = sscanf(line, " %d: %x:%x", &socketnum, &hexip, &hexport);

				// find open listen socket on 0.0.0.0:port
				if(num == 3 && hexip == 0 &&
						hexport >= RenderDoc_FirstCaptureNetworkPort &&
						hexport <= RenderDoc_LastCaptureNetworkPort)
				{
					ret = hexport;
				}
			}

			FileIO::fclose(f);
		}

		if(waitForExit)
		{
			int dummy = 0;
			waitpid(childPid, &dummy, 0);
		}
	}

	char **envp_delete = envp;

	while(*envp)
	{
		delete[] *envp;
		envp++;
	}

	delete[] envp_delete;

	return ret;
}

void Process::StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions *opts)
{
	RDCUNIMPLEMENTED("Global hooking of all processes on linux");
}

void *Process::LoadModule(const char *module)
{
	return dlopen(module, RTLD_NOW);
}

void *Process::GetFunctionAddress(void *module, const char *function)
{
	if(module == NULL) return NULL;

	return dlsym(module, function);
}

uint32_t Process::GetCurrentPID()
{
	return (uint32_t)getpid();
}
<|endoftext|>