<commit_before>#include "Controller.h"
using Hydra::Logger;

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
		for (auto profile = profiles.begin(); profile != profiles.end(); profile++) //Delete cooldown timers
		{
			for (auto control = profile->second.begin(); control != profile->second.end(); control++)
				delete control->second.btn.cooldownTimer;
		}
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels" id="5">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load_file(filename.c_str());
		Logger::log(string("XML Load Result: ") + result.description(), "sysLog");

		for (pugi::xml_node profile: doc.child("ControlConfig").children("profile"))
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;
			Logger::log(string("Found profile ") + profile.attribute("name").as_string(), "sysLog");

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				Logger::log(string("Found control ") + control.attribute("name").as_string(), "sysLog");

				if (control.attribute("type").as_string() == string("button"))
				{
					Logger::log("Control is of type button", "sysLog");
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("value").as_double();
					newCtrl.btn.cooldownTimer->Start();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
					newCtrl.btn.on = new bool(false); //Can't do this in a constructor...
				}
				else
				{
					Logger::log("Control is of type joystick", "sysLog");
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
			{
				Logger::log(string("Switching to active profile ") + profile.attribute("name").as_string(), "sysLog");
				switchProfile(profile.attribute("name").as_string());
			}

		}
		Logger::log("Finished parsing config file", "sysLog");
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
		else
			Logger::log("Couldn't switch to profile - it doesn't exist!", "sysLog", Hydra::error);
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 * @note If you get inexplicable crashes originating from this class, check to make sure you gave it a joystick.
	 */
	double Controller::operator[](const string& name)
	{
		if (profiles[currentProfile].count(name) == 0)
		{
			Logger::log("Could not find control " + name, "sysLog", Hydra::error);
			return 0; //There IS no control by this name!
		}

		ctrlCfg control = profiles[currentProfile][name];
		if (control.type == ctrlCfg::BUTTON)
		{
			if (!control.btn.toggle)
				return control.inverse ? !joystick->GetRawButton(control.id) : joystick->GetRawButton(control.id);
			else if (joystick->GetRawButton(control.id) || (!joystick->GetRawButton(control.id) && control.inverse))
			{
				//Toggles
				if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
				{
					*control.btn.on = !*control.btn.on;
					control.btn.cooldownTimer->Stop();
					control.btn.cooldownTimer->Reset(); //Just makes all timer calls relative to NOW.
					control.btn.cooldownTimer->Start(); //These function calls may or may not be needed
				}
			}
			return control.inverse ? !*control.btn.on : *control.btn.on;
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double slope = (control.jys.maxVal - control.jys.minVal) / 2.0;
			return (slope * value) - slope + control.jys.maxVal;

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<commit_msg>Add toggle to non-toggle buttons, reorganize button code<commit_after>#include "Controller.h"
using Hydra::Logger;

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
		for (auto profile = profiles.begin(); profile != profiles.end(); profile++) //Delete cooldown timers
		{
			for (auto control = profile->second.begin(); control != profile->second.end(); control++)
				delete control->second.btn.cooldownTimer;
		}
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels" id="5">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load_file(filename.c_str());
		Logger::log(string("XML Load Result: ") + result.description(), "sysLog");

		for (pugi::xml_node profile: doc.child("ControlConfig").children("profile"))
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;
			Logger::log(string("Found profile ") + profile.attribute("name").as_string(), "sysLog");

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				Logger::log(string("Found control ") + control.attribute("name").as_string(), "sysLog");

				if (control.attribute("type").as_string() == string("button"))
				{
					Logger::log("Control is of type button", "sysLog");
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("value").as_double();
					newCtrl.btn.cooldownTimer->Start();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
					newCtrl.btn.on = new bool(false); //Can't do this in a constructor...
				}
				else
				{
					Logger::log("Control is of type joystick", "sysLog");
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
			{
				Logger::log(string("Switching to active profile ") + profile.attribute("name").as_string(), "sysLog");
				switchProfile(profile.attribute("name").as_string());
			}

		}
		Logger::log("Finished parsing config file", "sysLog");
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
		else
			Logger::log("Couldn't switch to profile - it doesn't exist!", "sysLog", Hydra::error);
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 * @note If you get inexplicable crashes originating from this class, check to make sure you gave it a joystick.
	 */
	double Controller::operator[](const string& name)
	{
		if (profiles[currentProfile].count(name) == 0)
		{
			Logger::log("Could not find control " + name, "sysLog", Hydra::error);
			return 0; //There IS no control by this name!
		}

		ctrlCfg control = profiles[currentProfile][name];
		if (control.type == ctrlCfg::BUTTON)
		{
			bool ret = false;
			if (control.btn.toggle)
			{
				//Toggles
				if (joystick->GetRawButton(control.id) && control.btn.cooldownTimer->Get() >= control.btn.cooldown)
					*control.btn.on = !*control.btn.on;
				ret = *control.btn.on;
			}
			else
			{
				//Non-toggle, still needs cooldown
				if (joystick->GetRawButton(control.id) && control.btn.cooldownTimer->Get() >= control.btn.cooldown)
					ret = true;
			}

			if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
			{ //Reset cooldown timer if its time is too high.
				control.btn.cooldownTimer->Stop();
				control.btn.cooldownTimer->Reset(); //All of these function calls may not be needed, but screw timers.
				control.btn.cooldownTimer->Start();
			}
			return control.inverse ? !ret : ret;
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double slope = (control.jys.maxVal - control.jys.minVal) / 2.0;
			return (slope * value) - slope + control.jys.maxVal;

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<|endoftext|>


<commit_before>/*
 * FogLAMP storage service client
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Mark Riddoch, Massimiliano Pinto
 */
#include <reading_set.h>
#include <string>
#include <rapidjson/document.h>
#include <sstream>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <logger.h>

#include <boost/algorithm/string/replace.hpp>

#define ASSET_NAME_INVALID_READING "error_invalid_reading"

using namespace std;
using namespace rapidjson;

// List of characters to be escaped in JSON
const vector<string> JSON_characters_to_be_escaped = {
	"\\",
	"\""
};

/**
 * Construct an empty reading set
 */
ReadingSet::ReadingSet() : m_count(0)
{
}

/**
 * Construct a reading set from a vector<Reading *> pointer
 * NOTE: readings are copied into m_readings
 *
 * @param readings	The  vector<Reading *> pointer
 *			of readings to be copied
 *			into m_readings vector
 */
ReadingSet::ReadingSet(vector<Reading *>* readings)
{
	m_count = readings->size();
	for (auto it = readings->begin(); it != readings->end(); ++it)
	{
		m_readings.push_back(*it);
	}
}

/**
 * Construct a reading set from a JSON document returned from
 * the FogLAMP storage service query or notification.
 *
 * @param json	The JSON document (as string) with readings data
 */
ReadingSet::ReadingSet(const std::string& json)
{
	unsigned long rows = 0;
	Document doc;
	doc.Parse(json.c_str());
	if (doc.HasParseError())
	{
		throw new ReadingSetException("Unable to parse results json document");
	}
	// Check we have "count" and "rows"
	bool docHasRows =  doc.HasMember("rows"); // Query
	bool docHasReadings =  doc.HasMember("readings"); // Notification

	// Check we have "rows" or "readings"
	if (!docHasRows && !docHasReadings)
	{
		throw new ReadingSetException("Missing readings or rows array");
	}

	// Check we have "count" and "rows"
	if (doc.HasMember("count") && docHasRows)
	{
		m_count = doc["count"].GetUint();
		// No readings
		if (!m_count)
		{
			m_last_id = 0;
			return;
		}
	}
	else
	{
		// These fields might be updated later
		m_count = 0;
		m_last_id = 0;
	}

	// Get "rows" or "readings" data
	const Value& readings = docHasRows ? doc["rows"] : doc["readings"];
	if (readings.IsArray())
	{
		unsigned long id = 0;
		// Process every rows and create the result set
		for (auto& reading : readings.GetArray())
		{
			if (!reading.IsObject())
			{
				throw new ReadingSetException("Expected reading to be an object");
			}
			JSONReading *value = new JSONReading(reading);
			m_readings.push_back(value);

			// Get the Reading Id
			id = value->getId();

			// We don't have count informations with "readings"
			if (docHasReadings)
			{
				rows++;
			}

		}
		// Set the last id
		m_last_id = id;

		// Set count informations with "readings"
		if (docHasReadings)
		{
			m_count = rows;
		}
	}
	else
	{
		throw new ReadingSetException("Expected array of rows in result set");
	}
}

/**
 * Destructor for a result set
 */
ReadingSet::~ReadingSet()
{
	/* Delete the readings */
	for (auto it = m_readings.cbegin(); it != m_readings.cend(); it++)
	{
		delete *it;
	}
}

/**
 * Append the readings in a second reading set to this reading set.
 * The readings are removed from the original reading set
 */
void
ReadingSet::append(ReadingSet *readings)
{
	append(readings->getAllReadings());
	readings->clear();
}

/**
 * Append the readings in a second reading set to this reading set.
 * The readings are removed from the original reading set
 */
void
ReadingSet::append(ReadingSet& readings)
{
	append(readings.getAllReadings());
	readings.clear();
}

/**
 * Append a set of readings to this reading set.
 */
void
ReadingSet::append(const vector<Reading *>& readings)
{
	for (auto it = readings.cbegin(); it != readings.cend(); it++)
	{
		m_readings.push_back(*it);
		m_count++;
	}
}

/**
 * Remove all readings from the reading set and delete the memory
 * After this call the reading set exists but contains no readings.
 */
void
ReadingSet::removeAll()
{
	for (auto it = m_readings.cbegin(); it != m_readings.cend(); it++)
	{
		delete *it;
	}
	m_readings.clear();
}

/**
 * Remove the readings from the vector without deleting them
 */
void
ReadingSet::clear()
{
	m_readings.clear();
}

/**
 * Construct a reading from a JSON document
 *
 * The data can be in the "value" property as single numeric value
 * or in the JSON "reading" with different values and types
 *
 * @param json	The JSON document that contains the reading
 */
JSONReading::JSONReading(const Value& json)
{
	if (json.HasMember("id"))
	{
		m_id = json["id"].GetUint();
		m_has_id = true;
	}
	else
	{
		m_has_id = false;
	}
	m_asset = json["asset_code"].GetString();
	stringToTimestamp(json["user_ts"].GetString(), &m_userTimestamp);
	if (json.HasMember("ts"))
	{
		stringToTimestamp(json["ts"].GetString(), &m_timestamp);
	}
	else
	{
		m_timestamp = m_userTimestamp;
	}
	m_uuid = json["read_key"].GetString();

	// We have a single value here which is a number
	if (json.HasMember("value") && json["value"].IsNumber())
	{
		const Value &m = json["value"];

		if (m.IsInt() ||
		    m.IsUint() ||
		    m.IsInt64() ||
		    m.IsUint64())
		{
			DatapointValue* value;
			if (m.IsInt() ||
			    m.IsUint() )
			{
				value = new DatapointValue((long) m.GetInt());
			}
			else
			{
				value = new DatapointValue((long) m.GetInt64());
			}
			this->addDatapoint(new Datapoint("value",*value));
			delete value;

		}
		else if (m.IsDouble())
		{
			DatapointValue value(m.GetDouble());
			this->addDatapoint(new Datapoint("value",
							 value));
		}
		else
		{
			string errMsg = "Cannot parse the numeric type";
			errMsg += " of reading element '";
			errMsg.append("value");
			errMsg += "'";

			throw new ReadingSetException(errMsg.c_str());
		}
	}
	else
	{
		if (json["reading"].IsObject())
		{
			// Add 'reading' values
			for (auto &m : json["reading"].GetObject()) {
				switch (m.value.GetType()) {
					// String
					case (kStringType): {
						DatapointValue value(m.value.GetString());
						this->addDatapoint(new Datapoint(m.name.GetString(),
										 value));
						break;
					}

						// Number
					case (kNumberType): {
						if (m.value.IsInt() ||
						    m.value.IsUint() ||
						    m.value.IsInt64() ||
						    m.value.IsUint64()) {

							DatapointValue *value;
							if (m.value.IsInt() ||
							    m.value.IsUint()) {
								value = new DatapointValue((long) m.value.GetInt());
							} else {
								value = new DatapointValue((long) m.value.GetInt64());
							}
							this->addDatapoint(new Datapoint(m.name.GetString(),
											 *value));
							delete value;
							break;
						} else if (m.value.IsDouble()) {
							DatapointValue value(m.value.GetDouble());
							this->addDatapoint(new Datapoint(m.name.GetString(),
											 value));
							break;
						} else {
							string errMsg = "Cannot parse the numeric type";
							errMsg += " of reading element '";
							errMsg.append(m.name.GetString());
							errMsg += "'";

							throw new ReadingSetException(errMsg.c_str());
							break;
						}
					}

					default: {
						string errMsg = "Cannot handle unsupported type '" + m.value.GetType();
						errMsg += "' of reading element '";
						errMsg.append(m.name.GetString());
						errMsg += "'";

						throw new ReadingSetException(errMsg.c_str());

						break;
					}
				}
			}
		}
		else
		{
			// The reading should be an object at this stage, it is and invalid one if not
			// the asset name ASSET_NAME_INVALID_READING will be created in the PI-Server containing the
			// invalid asset_name/values.
			if (json["reading"].IsString())
			{
				string tmp_reading1 = json["reading"].GetString();

				// Escape specific character for to be properly manage as JSON
				for (const string &item : JSON_characters_to_be_escaped)
				{

					escapeCharacter(tmp_reading1, item);
				}

				Logger::getLogger()->error(
					"Invalid reading: Asset name |%s| reading value |%s| converted value |%s|",
					m_asset.c_str(),
					json["reading"].GetString(),
					tmp_reading1.c_str());

				DatapointValue value(tmp_reading1);
				this->addDatapoint(new Datapoint(m_asset, value));

			} else if (json["reading"].IsInt() ||
				   json["reading"].IsUint() ||
				   json["reading"].IsInt64() ||
				   json["reading"].IsUint64()) {

				DatapointValue *value;

				if (json["reading"].IsInt() ||
				    json["reading"].IsUint()) {
					value = new DatapointValue((long) json["reading"].GetInt());
				} else {
					value = new DatapointValue((long) json["reading"].GetInt64());
				}
				this->addDatapoint(new Datapoint(m_asset, *value));
				delete value;

			} else if (json["reading"].IsDouble())
			{
				DatapointValue value(json["reading"].GetDouble());
				this->addDatapoint(new Datapoint(m_asset, value));

			}

			m_asset = string(ASSET_NAME_INVALID_READING) + string("_") + m_asset.c_str();
		}
	}
}

/**
 * Escapes a character in a string to be properly handled as JSON
 *
 */
void JSONReading::escapeCharacter(string& stringToEvaluate, string pattern)
{
	string escaped = "\\" + pattern;

	boost::replace_all(stringToEvaluate, pattern, escaped);
}
<commit_msg>FOGL-2779 Fix for array data<commit_after>/*
 * FogLAMP storage service client
 *
 * Copyright (c) 2018 Dianomic Systems
 *
 * Released under the Apache 2.0 Licence
 *
 * Author: Mark Riddoch, Massimiliano Pinto
 */
#include <reading_set.h>
#include <string>
#include <rapidjson/document.h>
#include <sstream>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <logger.h>

#include <boost/algorithm/string/replace.hpp>

#define ASSET_NAME_INVALID_READING "error_invalid_reading"

static const char* kTypeNames[] =
    { "Null", "False", "True", "Object", "Array", "String", "Number" };

using namespace std;
using namespace rapidjson;

// List of characters to be escaped in JSON
const vector<string> JSON_characters_to_be_escaped = {
	"\\",
	"\""
};

/**
 * Construct an empty reading set
 */
ReadingSet::ReadingSet() : m_count(0)
{
}

/**
 * Construct a reading set from a vector<Reading *> pointer
 * NOTE: readings are copied into m_readings
 *
 * @param readings	The  vector<Reading *> pointer
 *			of readings to be copied
 *			into m_readings vector
 */
ReadingSet::ReadingSet(vector<Reading *>* readings)
{
	m_count = readings->size();
	for (auto it = readings->begin(); it != readings->end(); ++it)
	{
		m_readings.push_back(*it);
	}
}

/**
 * Construct a reading set from a JSON document returned from
 * the FogLAMP storage service query or notification.
 *
 * @param json	The JSON document (as string) with readings data
 */
ReadingSet::ReadingSet(const std::string& json)
{
	unsigned long rows = 0;
	Document doc;
	doc.Parse(json.c_str());
	if (doc.HasParseError())
	{
		throw new ReadingSetException("Unable to parse results json document");
	}
	// Check we have "count" and "rows"
	bool docHasRows =  doc.HasMember("rows"); // Query
	bool docHasReadings =  doc.HasMember("readings"); // Notification

	// Check we have "rows" or "readings"
	if (!docHasRows && !docHasReadings)
	{
		throw new ReadingSetException("Missing readings or rows array");
	}

	// Check we have "count" and "rows"
	if (doc.HasMember("count") && docHasRows)
	{
		m_count = doc["count"].GetUint();
		// No readings
		if (!m_count)
		{
			m_last_id = 0;
			return;
		}
	}
	else
	{
		// These fields might be updated later
		m_count = 0;
		m_last_id = 0;
	}

	// Get "rows" or "readings" data
	const Value& readings = docHasRows ? doc["rows"] : doc["readings"];
	if (readings.IsArray())
	{
		unsigned long id = 0;
		// Process every rows and create the result set
		for (auto& reading : readings.GetArray())
		{
			if (!reading.IsObject())
			{
				throw new ReadingSetException("Expected reading to be an object");
			}
			JSONReading *value = new JSONReading(reading);
			m_readings.push_back(value);

			// Get the Reading Id
			id = value->getId();

			// We don't have count informations with "readings"
			if (docHasReadings)
			{
				rows++;
			}

		}
		// Set the last id
		m_last_id = id;

		// Set count informations with "readings"
		if (docHasReadings)
		{
			m_count = rows;
		}
	}
	else
	{
		throw new ReadingSetException("Expected array of rows in result set");
	}
}

/**
 * Destructor for a result set
 */
ReadingSet::~ReadingSet()
{
	/* Delete the readings */
	for (auto it = m_readings.cbegin(); it != m_readings.cend(); it++)
	{
		delete *it;
	}
}

/**
 * Append the readings in a second reading set to this reading set.
 * The readings are removed from the original reading set
 */
void
ReadingSet::append(ReadingSet *readings)
{
	append(readings->getAllReadings());
	readings->clear();
}

/**
 * Append the readings in a second reading set to this reading set.
 * The readings are removed from the original reading set
 */
void
ReadingSet::append(ReadingSet& readings)
{
	append(readings.getAllReadings());
	readings.clear();
}

/**
 * Append a set of readings to this reading set.
 */
void
ReadingSet::append(const vector<Reading *>& readings)
{
	for (auto it = readings.cbegin(); it != readings.cend(); it++)
	{
		m_readings.push_back(*it);
		m_count++;
	}
}

/**
 * Remove all readings from the reading set and delete the memory
 * After this call the reading set exists but contains no readings.
 */
void
ReadingSet::removeAll()
{
	for (auto it = m_readings.cbegin(); it != m_readings.cend(); it++)
	{
		delete *it;
	}
	m_readings.clear();
}

/**
 * Remove the readings from the vector without deleting them
 */
void
ReadingSet::clear()
{
	m_readings.clear();
}

/**
 * Construct a reading from a JSON document
 *
 * The data can be in the "value" property as single numeric value
 * or in the JSON "reading" with different values and types
 *
 * @param json	The JSON document that contains the reading
 */
JSONReading::JSONReading(const Value& json)
{
	if (json.HasMember("id"))
	{
		m_id = json["id"].GetUint();
		m_has_id = true;
	}
	else
	{
		m_has_id = false;
	}
	if (json.HasMember("asset_code"))
	{
		m_asset = json["asset_code"].GetString();
	}
	else
	{
		string errMsg = "Malformed JSON reading, missing asset_code '";
		errMsg.append("value");
		errMsg += "'";
		throw new ReadingSetException(errMsg.c_str());
	}
	if (json.HasMember("user_ts"))
	{
		stringToTimestamp(json["user_ts"].GetString(), &m_userTimestamp);
	}
	else
	{
		string errMsg = "Malformed JSON reading, missing user timestamp '";
		errMsg.append("value");
		errMsg += "'";
		throw new ReadingSetException(errMsg.c_str());
	}
	if (json.HasMember("ts"))
	{
		stringToTimestamp(json["ts"].GetString(), &m_timestamp);
	}
	else
	{
		m_timestamp = m_userTimestamp;
	}
	if (json.HasMember("read_key"))
	{
		m_uuid = json["read_key"].GetString();
	}

	// We have a single value here which is a number
	if (json.HasMember("value") && json["value"].IsNumber())
	{
		const Value &m = json["value"];

		if (m.IsInt() ||
		    m.IsUint() ||
		    m.IsInt64() ||
		    m.IsUint64())
		{
			DatapointValue* value;
			if (m.IsInt() ||
			    m.IsUint() )
			{
				value = new DatapointValue((long) m.GetInt());
			}
			else
			{
				value = new DatapointValue((long) m.GetInt64());
			}
			this->addDatapoint(new Datapoint("value",*value));
			delete value;

		}
		else if (m.IsDouble())
		{
			DatapointValue value(m.GetDouble());
			this->addDatapoint(new Datapoint("value",
							 value));
		}
		else
		{
			string errMsg = "Cannot parse the numeric type";
			errMsg += " of reading element '";
			errMsg.append("value");
			errMsg += "'";

			throw new ReadingSetException(errMsg.c_str());
		}
	}
	else if (json.HasMember("reading"))
	{
		if (json["reading"].IsObject())
		{
			// Add 'reading' values
			for (auto &m : json["reading"].GetObject()) {
				switch (m.value.GetType()) {
					// String
					case (kStringType): {
						DatapointValue value(m.value.GetString());
						this->addDatapoint(new Datapoint(m.name.GetString(),
										 value));
						break;
					}

						// Number
					case (kNumberType): {
						if (m.value.IsInt() ||
						    m.value.IsUint() ||
						    m.value.IsInt64() ||
						    m.value.IsUint64()) {

							DatapointValue *value;
							if (m.value.IsInt() ||
							    m.value.IsUint()) {
								value = new DatapointValue((long) m.value.GetInt());
							} else {
								value = new DatapointValue((long) m.value.GetInt64());
							}
							this->addDatapoint(new Datapoint(m.name.GetString(),
											 *value));
							delete value;
							break;
						} else if (m.value.IsDouble()) {
							DatapointValue value(m.value.GetDouble());
							this->addDatapoint(new Datapoint(m.name.GetString(),
											 value));
							break;
						} else {
							string errMsg = "Cannot parse the numeric type";
							errMsg += " of reading element '";
							errMsg.append(m.name.GetString());
							errMsg += "'";

							throw new ReadingSetException(errMsg.c_str());
							break;
						}
					}

					case kArrayType:
					    {
						    vector<double> arrayValues;
						    for (auto& v : m.value.GetArray())
						    {
							    if (v.IsDouble())
							    {
								    arrayValues.push_back(v.GetDouble());
							    }
							    else if (v.IsInt() || v.IsUint())
							    {
								    double i = (double)v.GetInt();
								    arrayValues.push_back(i);
							    }
							    else if (v.IsInt64() || v.IsUint64())
							    {
								    double i = (double)v.GetInt64();
								    arrayValues.push_back(i);
							    }
						    }
						    DatapointValue value(arrayValues);
						    this->addDatapoint(new Datapoint(m.name.GetString(),
											 value));
						    break;

					    }

					default: {
						string errMsg = "Cannot handle unsupported type '";
					        errMsg += kTypeNames[m.value.GetType()];
						errMsg += "' of reading element '";
						errMsg.append(m.name.GetString());
						errMsg += "'";

						throw new ReadingSetException(errMsg.c_str());

						break;
					}
				}
			}
		}
		else
		{
			// The reading should be an object at this stage, it is and invalid one if not
			// the asset name ASSET_NAME_INVALID_READING will be created in the PI-Server containing the
			// invalid asset_name/values.
			if (json["reading"].IsString())
			{
				string tmp_reading1 = json["reading"].GetString();

				// Escape specific character for to be properly manage as JSON
				for (const string &item : JSON_characters_to_be_escaped)
				{

					escapeCharacter(tmp_reading1, item);
				}

				Logger::getLogger()->error(
					"Invalid reading: Asset name |%s| reading value |%s| converted value |%s|",
					m_asset.c_str(),
					json["reading"].GetString(),
					tmp_reading1.c_str());

				DatapointValue value(tmp_reading1);
				this->addDatapoint(new Datapoint(m_asset, value));

			} else if (json["reading"].IsInt() ||
				   json["reading"].IsUint() ||
				   json["reading"].IsInt64() ||
				   json["reading"].IsUint64()) {

				DatapointValue *value;

				if (json["reading"].IsInt() ||
				    json["reading"].IsUint()) {
					value = new DatapointValue((long) json["reading"].GetInt());
				} else {
					value = new DatapointValue((long) json["reading"].GetInt64());
				}
				this->addDatapoint(new Datapoint(m_asset, *value));
				delete value;

			} else if (json["reading"].IsDouble())
			{
				DatapointValue value(json["reading"].GetDouble());
				this->addDatapoint(new Datapoint(m_asset, value));

			}

			m_asset = string(ASSET_NAME_INVALID_READING) + string("_") + m_asset.c_str();
		}
	}
	else
	{
		Logger::getLogger()->error("Missing reading property for JSON reading, %s", m_asset.c_str());
	}
}

/**
 * Escapes a character in a string to be properly handled as JSON
 *
 */
void JSONReading::escapeCharacter(string& stringToEvaluate, string pattern)
{
	string escaped = "\\" + pattern;

	boost::replace_all(stringToEvaluate, pattern, escaped);
}
<|endoftext|>


<commit_before>#ifdef WIN32
#define CPL_DISABLE_DLL
#endif
#include "ogrsf_frmts.h"

int main(int argc,char * argv[])
{
  OGRSFDriverRegistrar::Open(argv[1], FALSE);
  return 0;
}
<commit_msg>ENH: change dummy code in cmake to test if gdal has ogr<commit_after>#ifdef WIN32
#define CPL_DISABLE_DLL
#endif
#include "ogr_api.h"

int main(int argc,char * argv[])
{
  // OGRSFDriverRegistrar::Open(argv[1], FALSE);

  // return 0;

  OGRDataSourceH	hDS;
  OGRSFDriverH        *pahDriver;

  OGRRegisterAll();

  hDS = OGROpen(argv[1], FALSE, pahDriver );
  if( hDS == NULL )
    {
    return -1;
    }

  OGRReleaseDataSource( hDS );

  return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <opencv2/core/core.hpp>

int sepia(cv::Mat& image);<commit_msg>Attempt to commit.<commit_after>#pragma once

#include <opencv2/core/core.hpp>

cv::Mat sepia(cv::Mat& image);<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsgcontextplugin_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <QtGui/qguiapplication.h>
#include <QtCore/private/qfactoryloader_p.h>
#include <QtCore/qlibraryinfo.h>

QT_BEGIN_NAMESPACE

QSGContextPlugin::QSGContextPlugin(QObject *parent)
    : QObject(parent)
{
}

QSGContextPlugin::~QSGContextPlugin()
{
}

#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
    (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
#endif

struct QSGAdaptionPluginData
{
    QSGAdaptionPluginData()
        : tried(false)
        , factory(0)
    {
    }

    ~QSGAdaptionPluginData()
    {
    }

    bool tried;
    QSGContextFactoryInterface *factory;
    QString deviceName;
};

Q_GLOBAL_STATIC(QSGAdaptionPluginData, qsg_adaptation_data)

QSGAdaptionPluginData *contextFactory()
{
    QSGAdaptionPluginData *plugin = qsg_adaptation_data();
    if (!plugin->tried) {

        plugin->tried = true;
        const QStringList args = QGuiApplication::arguments();
        QString device;
        for (int index = 0; index < args.count(); ++index) {
            if (args.at(index).startsWith(QLatin1String("--device="))) {
                device = args.at(index).mid(9);
                break;
            }
        }
        if (device.isEmpty())
            device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));

#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
        if (!device.isEmpty()) {
            plugin->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(device));
            plugin->deviceName = device;
#ifndef QT_NO_DEBUG
            if (!plugin->factory) {
                qWarning("Could not create scene graph context for device '%s'"
                         " - check that plugins are installed correctly in %s",
                         qPrintable(device),
                         qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
            }
#endif
        }

#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
    }
    return plugin;
}

/*!
    \fn QSGContext *QSGContext::createDefaultContext()

    Creates a default scene graph context for the current hardware.
    This may load a device-specific plugin.
*/
QSGContext *QSGContext::createDefaultContext()
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->create(plugin->deviceName);
    return new QSGContext();
}

/*!
    \fn QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image)

    Calls into the scene graph adaptation if available and creates a texture
    factory. The primary purpose of this function is to reimplement hardware
    specific asynchronous texture frameskip-less uploads that can happen on
    the image providers thread.
 */

QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &image)
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->createTextureFactoryFromImage(image);
    return 0;
}

/*!
    \fn QQuickWindowManager *createWindowManager()

    Calls into the scene graph adaptation if available and creates a hardware
    specific window manager.
 */

QQuickWindowManager *QSGContext::createWindowManager()
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->createWindowManager();
    return 0;
}

QT_END_NAMESPACE
<commit_msg>Remove usage of deprecated plugin loader functionality.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsgcontextplugin_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <QtGui/qguiapplication.h>
#include <QtCore/private/qfactoryloader_p.h>
#include <QtCore/qlibraryinfo.h>

QT_BEGIN_NAMESPACE

QSGContextPlugin::QSGContextPlugin(QObject *parent)
    : QObject(parent)
{
}

QSGContextPlugin::~QSGContextPlugin()
{
}

#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
    (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
#endif

struct QSGAdaptionPluginData
{
    QSGAdaptionPluginData()
        : tried(false)
        , factory(0)
    {
    }

    ~QSGAdaptionPluginData()
    {
    }

    bool tried;
    QSGContextFactoryInterface *factory;
    QString deviceName;
};

Q_GLOBAL_STATIC(QSGAdaptionPluginData, qsg_adaptation_data)

QSGAdaptionPluginData *contextFactory()
{
    QSGAdaptionPluginData *plugin = qsg_adaptation_data();
    if (!plugin->tried) {

        plugin->tried = true;
        const QStringList args = QGuiApplication::arguments();
        QString device;
        for (int index = 0; index < args.count(); ++index) {
            if (args.at(index).startsWith(QLatin1String("--device="))) {
                device = args.at(index).mid(9);
                break;
            }
        }
        if (device.isEmpty())
            device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));

#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
        if (!device.isEmpty()) {
            const int index = loader()->indexOf(device);
            if (index != -1)
                plugin->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(index));
            plugin->deviceName = device;
#ifndef QT_NO_DEBUG
            if (!plugin->factory) {
                qWarning("Could not create scene graph context for device '%s'"
                         " - check that plugins are installed correctly in %s",
                         qPrintable(device),
                         qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
            }
#endif
        }

#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
    }
    return plugin;
}

/*!
    \fn QSGContext *QSGContext::createDefaultContext()

    Creates a default scene graph context for the current hardware.
    This may load a device-specific plugin.
*/
QSGContext *QSGContext::createDefaultContext()
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->create(plugin->deviceName);
    return new QSGContext();
}

/*!
    \fn QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image)

    Calls into the scene graph adaptation if available and creates a texture
    factory. The primary purpose of this function is to reimplement hardware
    specific asynchronous texture frameskip-less uploads that can happen on
    the image providers thread.
 */

QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &image)
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->createTextureFactoryFromImage(image);
    return 0;
}

/*!
    \fn QQuickWindowManager *createWindowManager()

    Calls into the scene graph adaptation if available and creates a hardware
    specific window manager.
 */

QQuickWindowManager *QSGContext::createWindowManager()
{
    QSGAdaptionPluginData *plugin = contextFactory();
    if (plugin->factory)
        return plugin->factory->createWindowManager();
    return 0;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/**
 * @file ctvector.cpp
 *
 * Simple vector classes. Classes ctvector_fp and ctvector_int are
 * designed to be wrappers around double* and int* arrays,
 * respectively.  They provide a few convenient methods that function
 * like those of std::vector<T>, but unlike the STL classes explicitly
 * allow accessing a pointer to the underlying data array.
 */

#include <math.h>
#include "ctvector.h"
#include <algorithm>
using namespace std;
using namespace ct;

    ostream& operator<<(ostream& s, const ctvector_int& v) {
        int n = v.size();
        s << "<";
        for (int i = 0; i < n; i++) {
            s << v[i];
            if (i < n-1) s << ", ";
        }
        s << ">";
        return s;
    }

    ostream& operator<<(ostream& s, const ctvector_fp& v) {
        int n = v.size();
        s << "<";
        for (int i = 0; i < n; i++) {
            s << v[i];
            if (i < n-1) s << ", ";
        }
        s << ">";
        return s;
    }

namespace ct {

    ctvector_fp::ctvector_fp(size_t n) : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n);
    }

    ctvector_fp::ctvector_fp(size_t n, value_type v0)
        : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n, v0);
    }

    ctvector_fp::ctvector_fp(const ctvector_fp& x) {
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        else {
            _data = 0;
        }
        _size = x._size;
        _alloc = x._alloc;
    }

    ctvector_fp ctvector_fp::operator=(const ctvector_fp& x) {
        if (this == &x) return *this;
        delete[] _data;
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        else {
            _data = 0;
        }
        _size = x._size;
        _alloc = x._alloc;
        return *this;
    }

    ctvector_fp::~ctvector_fp() {
        delete[] _data;
        _data = 0;
    }

    void ctvector_fp::resize(size_t n) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        size_t datalen = (n > _size ? _size : n);
        copy(_data, _data + datalen, newdata);
        delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_fp::resize(size_t n, value_type v0) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        fill(newdata, newdata + new_alloc, v0);
        size_t datalen = (n > _size ? _size : n);
        copy(_data, _data + datalen, newdata);
        delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_fp::push_back(value_type x) {
        size_t loc = _size;
        if (_size == _alloc) {
            resize(2*_alloc);
        }
        _data[loc] = x;
        _size = loc + 1;
    }

    void ctvector_fp::clear() { fill(_data, _data + _size, 0.0); resize(0); }

    //-------------------------------------//
    //             ctvector_int            //
    //-------------------------------------//

    ctvector_int::ctvector_int(size_t n) : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n);
    }

    ctvector_int::ctvector_int(size_t n, value_type v0)
        : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n, v0);
    }

    ctvector_int::ctvector_int(const ctvector_int& x) {
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        _size = x._size;
        _alloc = x._alloc;
    }

    ctvector_int ctvector_int::operator=(const ctvector_int& x) {
        if (this == &x) return *this;
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        _size = x._size;
        _alloc = x._alloc;
        return *this;
    }

    ctvector_int::~ctvector_int() {
        if (_alloc > 0) delete[] _data;
        _data = 0;
    }

    void ctvector_int::resize(size_t n) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        size_t datalen = (n > _size ? _size : n);
        copy(_data, _data + datalen, newdata);
        if (_alloc > 0) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_int::resize(size_t n, value_type v0) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        fill(newdata, newdata + new_alloc, v0);
        size_t datalen = (n > _size ? _size : n);
        copy(_data, _data + datalen, newdata);
        if (_alloc > 0) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_int::push_back(value_type x) {
        size_t loc = _size;
        if (_size == _alloc) {
            resize(2*_alloc);
        }
        _data[loc] = x;
        _size = loc + 1;
    }

    void ctvector_int::clear() { fill(_data, _data + _size, 0); resize(0); }
}

<commit_msg>Check for null before deleting or copying. Not strictly necessary, but good form.<commit_after>/**
 * @file ctvector.cpp
 *
 * Simple vector classes. Classes ctvector_fp and ctvector_int are
 * designed to be wrappers around double* and int* arrays,
 * respectively.  They provide a few convenient methods that function
 * like those of std::vector<T>, but unlike the STL classes explicitly
 * allow accessing a pointer to the underlying data array.
 */

#include <math.h>
#include "ctvector.h"
#include <algorithm>
using namespace std;
using namespace ct;

    ostream& operator<<(ostream& s, const ctvector_int& v) {
        int n = v.size();
        s << "<";
        for (int i = 0; i < n; i++) {
            s << v[i];
            if (i < n-1) s << ", ";
        }
        s << ">";
        return s;
    }

    ostream& operator<<(ostream& s, const ctvector_fp& v) {
        int n = v.size();
        s << "<";
        for (int i = 0; i < n; i++) {
            s << v[i];
            if (i < n-1) s << ", ";
        }
        s << ">";
        return s;
    }

namespace ct {

    ctvector_fp::ctvector_fp(size_t n) : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n);
    }

    ctvector_fp::ctvector_fp(size_t n, value_type v0)
        : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n, v0);
    }

    ctvector_fp::ctvector_fp(const ctvector_fp& x) {
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        else {
            _data = 0;
        }
        _size = x._size;
        _alloc = x._alloc;
    }

    ctvector_fp ctvector_fp::operator=(const ctvector_fp& x) {
        if (this == &x) return *this;
        if (_data) delete[] _data;
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        else {
            _data = 0;
        }
        _size = x._size;
        _alloc = x._alloc;
        return *this;
    }

    ctvector_fp::~ctvector_fp() {
        if (_data) delete[] _data;
        _data = 0;
    }

    void ctvector_fp::resize(size_t n) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        size_t datalen = (n > _size ? _size : n);
	if (_data) {
	  copy(_data, _data + datalen, newdata);
	}
        if (_data) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_fp::resize(size_t n, value_type v0) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        fill(newdata, newdata + new_alloc, v0);
        size_t datalen = (n > _size ? _size : n);
	if (_data) {
	  copy(_data, _data + datalen, newdata);
	}
        if (_data) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_fp::push_back(value_type x) {
        size_t loc = _size;
        if (_size == _alloc) {
            resize(2*_alloc);
        }
        _data[loc] = x;
        _size = loc + 1;
    }

    void ctvector_fp::clear() { fill(_data, _data + _size, 0.0); resize(0); }

    //-------------------------------------//
    //             ctvector_int            //
    //-------------------------------------//

    ctvector_int::ctvector_int(size_t n) : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n);
    }

    ctvector_int::ctvector_int(size_t n, value_type v0)
        : _size(0), _alloc(0), _data(0) {
        if (n > 0) resize(n, v0);
    }

    ctvector_int::ctvector_int(const ctvector_int& x) {
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        _size = x._size;
        _alloc = x._alloc;
    }

    ctvector_int ctvector_int::operator=(const ctvector_int& x) {
        if (this == &x) return *this;
        if (x._alloc > 0) {
            _data = new value_type[x._alloc];
            copy(x._data, x._data + x._alloc, _data);
        }
        _size = x._size;
        _alloc = x._alloc;
        return *this;
    }

    ctvector_int::~ctvector_int() {
        if (_alloc > 0) delete[] _data;
        _data = 0;
    }

    void ctvector_int::resize(size_t n) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        size_t datalen = (n > _size ? _size : n);
	if (_data) {
	  copy(_data, _data + datalen, newdata);
	}
        if (_alloc > 0) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_int::resize(size_t n, value_type v0) {
        size_t new_alloc = n+1;
        value_type* newdata = new value_type[new_alloc];
        fill(newdata, newdata + new_alloc, v0);
        size_t datalen = (n > _size ? _size : n);
	if (_data) {
	  copy(_data, _data + datalen, newdata);
	}
        if (_alloc > 0) delete[] _data;
        _data = newdata;
        _alloc = new_alloc;
        _size = n;
    }

    void ctvector_int::push_back(value_type x) {
        size_t loc = _size;
        if (_size == _alloc) {
            resize(2*_alloc);
        }
        _data[loc] = x;
        _size = loc + 1;
    }

    void ctvector_int::clear() { fill(_data, _data + _size, 0); resize(0); }
}

<|endoftext|>


<commit_before>#include "basecpu.h"
#include "errors.h"
#include "utils.h"

BaseCPU::BaseCPU(const System &sys): sys(sys), running(false) {
}

void BaseCPU::stop() {
    running = false;
}

bool BaseCPU::startup() {
    bool started = false;
    if (!running) {
        running = true;
        started = true;
        reset();
        while(running) { tick(); }
    }
    return started;
}

bool BaseCPU::isRunning() {
    return running;
}

int BaseCPU::readMemory(SizeType offset, SizeType len, void *data) const {
    return sys.readMemory(offset, len, data);
}

int BaseCPU::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return sys.writeMemory(offset, len, data);
}

int BaseCPU::readPort(PortType port, SizeType len, void *data) const {
    return sys.readPort(port, len, data);
}

int BaseCPU::writePort(PortType port, SizeType len, const void *data) const {
    return sys.writePort(port, len, data);
}

void Interruptable::signalInterrupt(Interrupt interrupt) {
    interruptQueue.push(interrupt);
}

SizeType Interruptable::interruptQueueLength() {
    return interruptQueue.size();
}

bool Interruptable::serviceNextInterrupt() {
    bool ret = false;
    if(!interruptQueue.empty()) {
        serviceInterrupt(interruptQueue.front());
        interruptQueue.pop();
        ret = true;
    }
    return ret;
}

GenericCPU::GenericCPU(const System &sys, const InstructionSet &set, Interrupt badInstruction, Interrupt badOperand) :
    BaseCPU(sys), set(set), badInstruction(badInstruction), badOperand(badOperand) {
}

void GenericCPU::tick() {
    // FIXME: Should service the entire interrupt queue (not just the one)
    if(!(interruptsEnabled() && serviceNextInterrupt())) {
        nextInstruction();
    }
}

bool GenericCPU::readBytes(ByteString &buffer, const void * const base, SizeType length) {
    buffer.reserve(length);
    return readMemory((SizeType)base, length, buffer.data()) == ERR_SUCCESS;
}

bool GenericCPU::readNextByte(ByteString &buffer, const void * const base) {
    bool ret = false;
    byte next;
    SizeType nextAddr = ((SizeType)base) + buffer.size();

    if(readMemory(nextAddr, 1, &next) != ERR_SUCCESS) {
        ret = false;
    } else {
        buffer.push_back(next);
        ret = true;
    }
    return ret;
}

int GenericCPU::readInstruction(const void * const instructionBase, const Instruction **out) {
    ByteString opcode;
    bool memoryRc;
    int decodeRc;

    do {
        memoryRc = readNextByte(opcode, instructionBase);
        if(memoryRc) {
            decodeRc = set.decode(opcode, out);
        }
    } while(
        memoryRc && (decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE)
    );

    if(!memoryRc) {
        return ERR_CONFLICT;
    }

    if(decodeRc != ERR_SUCCESS) {
        return ERR_BADRANGE;
    } else {
        return ERR_SUCCESS;
    }
}

bool GenericCPU::readInstructionOperands(
    const void * const instructionBase,
    const Instruction &instruction,
    ByteString &operands
) {
    const void * const operandBase = advancePtr(instructionBase, instruction.opcode.size());
    return readBytes(operands, operandBase, instruction.length);
}

bool GenericCPU::loadNextInstruction(const Instruction **instruction, ByteString &operands) {
    bool instructionLoaded = false;
    const void * const instructionBase = getInstructionPointer();
    int instructionRc = readInstruction(instructionBase, instruction);
    if(instructionRc == ERR_SUCCESS) {
        bool operandRc = readInstructionOperands(instructionBase, **instruction, operands);
        if(!operandRc) {
            signalInterrupt(badOperand);
        } else {
            instructionLoaded = true;
        }
    } else if(instructionRc == ERR_CONFLICT) {
        signalInterrupt(badOperand);
    } else if(instructionRc == ERR_BADRANGE) {
        signalInterrupt(badInstruction);
    }

    return instructionLoaded;
}

void GenericCPU::nextInstruction() {
    const Instruction *instruction;
    ByteString operands;

    if(loadNextInstruction(&instruction, operands)) {
        SizeType totalInstuctionLength = instruction->opcode.size() + instruction->length;
        void *oldInstructionPointer = getInstructionPointer();
        setInstructionPointer(advancePtr(oldInstructionPointer, totalInstuctionLength));
        instruction->execute(*this, operands);
    } else { /* Interrupts should handle this case */ }
}<commit_msg>Fix bad comment<commit_after>#include "basecpu.h"
#include "errors.h"
#include "utils.h"

BaseCPU::BaseCPU(const System &sys): sys(sys), running(false) {
}

void BaseCPU::stop() {
    running = false;
}

bool BaseCPU::startup() {
    bool started = false;
    if (!running) {
        running = true;
        started = true;
        reset();
        while(running) { tick(); }
    }
    return started;
}

bool BaseCPU::isRunning() {
    return running;
}

int BaseCPU::readMemory(SizeType offset, SizeType len, void *data) const {
    return sys.readMemory(offset, len, data);
}

int BaseCPU::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return sys.writeMemory(offset, len, data);
}

int BaseCPU::readPort(PortType port, SizeType len, void *data) const {
    return sys.readPort(port, len, data);
}

int BaseCPU::writePort(PortType port, SizeType len, const void *data) const {
    return sys.writePort(port, len, data);
}

void Interruptable::signalInterrupt(Interrupt interrupt) {
    interruptQueue.push(interrupt);
}

SizeType Interruptable::interruptQueueLength() {
    return interruptQueue.size();
}

bool Interruptable::serviceNextInterrupt() {
    bool ret = false;
    if(!interruptQueue.empty()) {
        serviceInterrupt(interruptQueue.front());
        interruptQueue.pop();
        ret = true;
    }
    return ret;
}

GenericCPU::GenericCPU(const System &sys, const InstructionSet &set, Interrupt badInstruction, Interrupt badOperand) :
    BaseCPU(sys), set(set), badInstruction(badInstruction), badOperand(badOperand) {
}

void GenericCPU::tick() {
    /*
    This looks like it only services a single interrupt but remember that this
    loop also executes the handler.  Interrupts should be disabled prior to
    jumping into handler code.
    */
    if(!(interruptsEnabled() && serviceNextInterrupt())) {
        nextInstruction();
    }
}

bool GenericCPU::readBytes(ByteString &buffer, const void * const base, SizeType length) {
    buffer.reserve(length);
    return readMemory((SizeType)base, length, buffer.data()) == ERR_SUCCESS;
}

bool GenericCPU::readNextByte(ByteString &buffer, const void * const base) {
    bool ret = false;
    byte next;
    SizeType nextAddr = ((SizeType)base) + buffer.size();

    if(readMemory(nextAddr, 1, &next) != ERR_SUCCESS) {
        ret = false;
    } else {
        buffer.push_back(next);
        ret = true;
    }
    return ret;
}

int GenericCPU::readInstruction(const void * const instructionBase, const Instruction **out) {
    ByteString opcode;
    bool memoryRc;
    int decodeRc;

    do {
        memoryRc = readNextByte(opcode, instructionBase);
        if(memoryRc) {
            decodeRc = set.decode(opcode, out);
        }
    } while(
        memoryRc && (decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE)
    );

    if(!memoryRc) {
        return ERR_CONFLICT;
    }

    if(decodeRc != ERR_SUCCESS) {
        return ERR_BADRANGE;
    } else {
        return ERR_SUCCESS;
    }
}

bool GenericCPU::readInstructionOperands(
    const void * const instructionBase,
    const Instruction &instruction,
    ByteString &operands
) {
    const void * const operandBase = advancePtr(instructionBase, instruction.opcode.size());
    return readBytes(operands, operandBase, instruction.length);
}

bool GenericCPU::loadNextInstruction(const Instruction **instruction, ByteString &operands) {
    bool instructionLoaded = false;
    const void * const instructionBase = getInstructionPointer();
    int instructionRc = readInstruction(instructionBase, instruction);
    if(instructionRc == ERR_SUCCESS) {
        bool operandRc = readInstructionOperands(instructionBase, **instruction, operands);
        if(!operandRc) {
            signalInterrupt(badOperand);
        } else {
            instructionLoaded = true;
        }
    } else if(instructionRc == ERR_CONFLICT) {
        signalInterrupt(badOperand);
    } else if(instructionRc == ERR_BADRANGE) {
        signalInterrupt(badInstruction);
    }

    return instructionLoaded;
}

void GenericCPU::nextInstruction() {
    const Instruction *instruction;
    ByteString operands;

    if(loadNextInstruction(&instruction, operands)) {
        SizeType totalInstuctionLength = instruction->opcode.size() + instruction->length;
        void *oldInstructionPointer = getInstructionPointer();
        setInstructionPointer(advancePtr(oldInstructionPointer, totalInstuctionLength));
        instruction->execute(*this, operands);
    } else { /* Interrupts should handle this case */ }
}<|endoftext|>


<commit_before>#include "llvm/Target/TargetOptions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace llvm {
  void initializeTestPassPass(PassRegistry &);
}

namespace {

void initLLVM() {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();

  PassRegistry *Registry = PassRegistry::getPassRegistry();
  initializeCore(*Registry);
  initializeCodeGen(*Registry);
}

/// Create a TargetMachine. We need a target that doesn't have IPRA enabled by
/// default. That turns out to be all targets at the moment, so just use X86.
std::unique_ptr<TargetMachine> createTargetMachine(bool EnableIPRA) {
  Triple TargetTriple("x86_64--");
  std::string Error;
  const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
  if (!T)
    return nullptr;

  TargetOptions Options;
  Options.EnableIPRA = EnableIPRA;
  return std::unique_ptr<TargetMachine>(T->createTargetMachine(
      "X86", "", "", Options, None, None, CodeGenOpt::Aggressive));
}

typedef std::function<void(bool)> TargetOptionsTest;

static void targetOptionsTest(bool EnableIPRA) {
  LLVMContext Context;
  std::unique_ptr<TargetMachine> TM = createTargetMachine(EnableIPRA);
  // This test is designed for the X86 backend; stop if it is not available.
  if (!TM)
    return;
  legacy::PassManager PM;
  LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*TM);

  TargetPassConfig &TPC = *LLVMTM.createPassConfig(PM);
  (void)TPC;

  ASSERT_TRUE(TM->Options.EnableIPRA == EnableIPRA);
}

} // End of anonymous namespace.

TEST(TargetOptionsTest, IPRASetToOff) {
  targetOptionsTest(false);
}

TEST(TargetOptionsTest, IPRASetToOn) {
  targetOptionsTest(true);
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  initLLVM();
  return RUN_ALL_TESTS();
}
<commit_msg>Fix memory leak in r354692<commit_after>#include "llvm/Target/TargetOptions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace llvm {
  void initializeTestPassPass(PassRegistry &);
}

namespace {

void initLLVM() {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();

  PassRegistry *Registry = PassRegistry::getPassRegistry();
  initializeCore(*Registry);
  initializeCodeGen(*Registry);
}

/// Create a TargetMachine. We need a target that doesn't have IPRA enabled by
/// default. That turns out to be all targets at the moment, so just use X86.
std::unique_ptr<TargetMachine> createTargetMachine(bool EnableIPRA) {
  Triple TargetTriple("x86_64--");
  std::string Error;
  const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
  if (!T)
    return nullptr;

  TargetOptions Options;
  Options.EnableIPRA = EnableIPRA;
  return std::unique_ptr<TargetMachine>(T->createTargetMachine(
      "X86", "", "", Options, None, None, CodeGenOpt::Aggressive));
}

typedef std::function<void(bool)> TargetOptionsTest;

static void targetOptionsTest(bool EnableIPRA) {
  LLVMContext Context;
  std::unique_ptr<TargetMachine> TM = createTargetMachine(EnableIPRA);
  // This test is designed for the X86 backend; stop if it is not available.
  if (!TM)
    return;
  legacy::PassManager PM;
  LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());

  TargetPassConfig &TPC = *LLVMTM->createPassConfig(PM);
  (void)TPC;

  ASSERT_TRUE(TM->Options.EnableIPRA == EnableIPRA);
}

} // End of anonymous namespace.

TEST(TargetOptionsTest, IPRASetToOff) {
  targetOptionsTest(false);
}

TEST(TargetOptionsTest, IPRASetToOn) {
  targetOptionsTest(true);
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  initLLVM();
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Copyright 2010 Google
// 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 "base/util.h"
#include "base/stringpiece.h"

namespace operations_research {

// Walltimer

#if !defined(_MSC_VER)
namespace {
static inline int64 TimevalToUsec(const timeval &tv) {
  return static_cast<int64>(1000000) * tv.tv_sec + tv.tv_usec;
}
}  // namespace
#endif

WallTimer::WallTimer() :
    start_usec_(0LL), sum_usec_(0LL), has_started_(false) {}

void WallTimer::Start() {  // Just save when we started
#if defined(_MSC_VER)
  start_usec_ = clock();
#elif defined(__GNUC__)
  struct timeval tv;
  gettimeofday(&tv, NULL);
  start_usec_ = TimevalToUsec(tv);
#endif
  has_started_ = true;
}

void WallTimer::Stop() {   // Update total time, 1st time it's called
  if ( has_started_ ) {           // so two Stop()s is safe
#if defined(_MSC_VER)
    sum_usec_ += clock() - start_usec_;
#elif defined(__GNUC__)
    struct timeval tv;
    gettimeofday(&tv, NULL);
    sum_usec_ += TimevalToUsec(tv) - start_usec_;
#endif
    has_started_ = false;
  }
}

bool WallTimer::Reset() {  // As if we had hit Stop() first
  start_usec_ = 0;
  sum_usec_ = 0;
  has_started_ = false;
  return true;
}

void WallTimer::Restart() {
  Reset(); Start();
}

bool WallTimer::IsRunning() const {
  return has_started_;
}

int64 WallTimer::GetInMs() const {
#if defined(_MSC_VER)
  int64 local_sum_usec = sum_usec_;
  if ( has_started_ ) {           // need to include current time too
    local_sum_usec += clock() - start_usec_;
  }
  return local_sum_usec;
#elif defined(__GNUC__)
  static const int64 kMilliSecInMicroSec = 1000LL;
  int64 local_sum_usec = sum_usec_;
  if ( has_started_ ) {           // need to include current time too
    struct timeval tv;
    gettimeofday(&tv, NULL);
    local_sum_usec += TimevalToUsec(tv) - start_usec_;
  }
  return local_sum_usec / kMilliSecInMicroSec;
#endif
}

// GetUsedMemory

#if defined(__APPLE__) && defined(__GNUC__)
#include <mach/mach_init.h>
#include <mach/task.h>

int64 GetMemoryUsage () {
  task_t task = MACH_PORT_NULL;
  struct task_basic_info t_info;
  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

  if (KERN_SUCCESS != task_info(mach_task_self(),
                                TASK_BASIC_INFO,
                                (task_info_t)&t_info,
                                &t_info_count)) {
    return -1;
  }
  int64 resident_memory = t_info.resident_size;
  //  int64 virtual_memory = t_info.virtual_size;
  return resident_memory;
}
#else
int64 GetMemoryUsage() {
  return 0;
}
#endif

}  // namespace operations_research
<commit_msg>Display real memory usage on Windows, must be tested<commit_after>// Copyright 2010 Google
// 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 "base/util.h"
#include "base/stringpiece.h"

namespace operations_research {

// Walltimer

#if !defined(_MSC_VER)
namespace {
static inline int64 TimevalToUsec(const timeval &tv) {
  return static_cast<int64>(1000000) * tv.tv_sec + tv.tv_usec;
}
}  // namespace
#endif

WallTimer::WallTimer() :
    start_usec_(0LL), sum_usec_(0LL), has_started_(false) {}

void WallTimer::Start() {  // Just save when we started
#if defined(_MSC_VER)
  start_usec_ = clock();
#elif defined(__GNUC__)
  struct timeval tv;
  gettimeofday(&tv, NULL);
  start_usec_ = TimevalToUsec(tv);
#endif
  has_started_ = true;
}

void WallTimer::Stop() {   // Update total time, 1st time it's called
  if ( has_started_ ) {           // so two Stop()s is safe
#if defined(_MSC_VER)
    sum_usec_ += clock() - start_usec_;
#elif defined(__GNUC__)
    struct timeval tv;
    gettimeofday(&tv, NULL);
    sum_usec_ += TimevalToUsec(tv) - start_usec_;
#endif
    has_started_ = false;
  }
}

bool WallTimer::Reset() {  // As if we had hit Stop() first
  start_usec_ = 0;
  sum_usec_ = 0;
  has_started_ = false;
  return true;
}

void WallTimer::Restart() {
  Reset(); Start();
}

bool WallTimer::IsRunning() const {
  return has_started_;
}

int64 WallTimer::GetInMs() const {
#if defined(_MSC_VER)
  int64 local_sum_usec = sum_usec_;
  if ( has_started_ ) {           // need to include current time too
    local_sum_usec += clock() - start_usec_;
  }
  return local_sum_usec;
#elif defined(__GNUC__)
  static const int64 kMilliSecInMicroSec = 1000LL;
  int64 local_sum_usec = sum_usec_;
  if ( has_started_ ) {           // need to include current time too
    struct timeval tv;
    gettimeofday(&tv, NULL);
    local_sum_usec += TimevalToUsec(tv) - start_usec_;
  }
  return local_sum_usec / kMilliSecInMicroSec;
#endif
}

// GetUsedMemory

#if defined(__APPLE__) && defined(__GNUC__)
#include <mach/mach_init.h>
#include <mach/task.h>

int64 GetMemoryUsage () {
  task_t task = MACH_PORT_NULL;
  struct task_basic_info t_info;
  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

  if (KERN_SUCCESS != task_info(mach_task_self(),
                                TASK_BASIC_INFO,
                                (task_info_t)&t_info,
                                &t_info_count)) {
    return -1;
  }
  int64 resident_memory = t_info.resident_size;
  //  int64 virtual_memory = t_info.virtual_size;
  return resident_memory;
}
#elif defined(__GNUC__)   // LINUX
int64 GetMemoryUsage() {
  return 0;
}
#elif DEFINED(_MSC_VER)  // WINDOWS
#include <windows.h>
#include <stdio.h>
#include <psapi.h>

int64 GetMemoryInfo() {
  HANDLE hProcess;
  PROCESS_MEMORY_COUNTERS pmc;
  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                         FALSE,
                         GetCurrentProcess());
  int64 memory = 0;
  if (hProcess) {
    if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
      memory = pmc.WorkingSetSize;
    }
    Closehandle(hProcess);
  }
  return memory;
}
#else  // Unknown, returning 0.
int64 GetMemoryUsage() {
  return 0;
}
#endif

}  // namespace operations_research
<|endoftext|>


<commit_before>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 The Eigenbase Project
// Copyright (C) 2005-2005 Disruptive Tech
// Copyright (C) 2005-2005 LucidEra, Inc.
// Portions Copyright (C) 1999-2005 John V. Sichi
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/test/TestBase.h"
#include "fennel/common/FennelResource.h"

#include <boost/test/test_tools.hpp>

using namespace fennel;

class ResourceTest : virtual public TestBase
{
public:

    explicit ResourceTest()
    {
        FENNEL_UNIT_TEST_CASE(ResourceTest,testEnUsLocale);
    }

    void testEnUsLocale();
};

void ResourceTest::testEnUsLocale()
{
    Locale locale("en","US");
    std::string actual =
        FennelResource::instance(locale).sysCallFailed("swizzle");
    std::string expected = "System call failed:  swizzle";
    BOOST_CHECK_EQUAL(expected,actual);
}

FENNEL_UNIT_TEST_SUITE(ResourceTest);

// End ResourceTest.cpp

<commit_msg>FENNEL: update ResourceTest to validate thread sync fix from change 3930<commit_after>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 The Eigenbase Project
// Copyright (C) 2005-2005 Disruptive Tech
// Copyright (C) 2005-2005 LucidEra, Inc.
// Portions Copyright (C) 1999-2005 John V. Sichi
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/test/TestBase.h"
#include "fennel/common/FennelResource.h"
#include "fennel/synch/Thread.h"

#include <boost/test/test_tools.hpp>
#include <boost/thread/barrier.hpp>

#include <vector>

using namespace fennel;

class ResourceTest : virtual public TestBase
{
public:

    explicit ResourceTest()
    {
        FENNEL_UNIT_TEST_CASE(ResourceTest, testEnUsLocale);
        FENNEL_UNIT_TEST_CASE(ResourceTest, testConcurrency);
    }

    void testEnUsLocale();
    void testConcurrency();
};

void ResourceTest::testEnUsLocale()
{
    Locale locale("en","US");
    std::string actual =
        FennelResource::instance(locale).sysCallFailed("swizzle");
    std::string expected = "System call failed:  swizzle";
    BOOST_CHECK_EQUAL(expected,actual);
}

class ResourceThread : public Thread
{
private:
    boost::barrier &barrier;

    int count;
    int completed;

    std::vector<std::string> variants;

public:
    explicit ResourceThread(
        std::string desc, boost::barrier &barrier, int count)
        : Thread(desc), barrier(barrier), count(count), completed(0)
    {
        //
        for(int i = 0; i < count; i++) {
            std::stringstream ss;
            ss << "var_" << (i + 1);
            variants.push_back(ss.str());
        }
    }

    virtual ~ResourceThread()
    {
    }

    int getCompleted()
    {
        return completed;
    }

    virtual void run()
    {
        try {
            barrier.wait();

            for(int i = 0; i < count; i++) {
                std::string &variant = variants[i];

                Locale locale("en", "US", variant);

                FennelResource::instance(locale).sysCallFailed(variant);

                completed++;
            }
        } catch(...) {
            completed = -1;
        }
    }
};

#define CONC_ITER (1000)

// Test thread sync bug fix (change 3930).  Note that the bug only seems
// to occur if two threads are attempting to create a ResourceBundle for
// the same Locale at the same time.
void ResourceTest::testConcurrency()
{
    boost::barrier barrier(2);

    ResourceThread thread1("resThread1", barrier, CONC_ITER);
    ResourceThread thread2("resThread2", barrier, CONC_ITER);

    thread1.start();
    thread2.start();

    thread1.join();
    thread2.join();

    BOOST_CHECK_EQUAL(thread1.getCompleted(), CONC_ITER);
    BOOST_CHECK_EQUAL(thread2.getCompleted(), CONC_ITER);
}

FENNEL_UNIT_TEST_SUITE(ResourceTest);

// End ResourceTest.cpp

<|endoftext|>


<commit_before>/*
 * jpegtran.c
 *
 * This file was part of the Independent JPEG Group's software:
 * Copyright (C) 1995-2010, Thomas G. Lane, Guido Vollbeding.
 * libjpeg-turbo Modifications:
 * Copyright (C) 2010, 2014, D. R. Commander.
 * mozjpeg Modifications:
 * Copyright (C) 2014, Mozilla Corporation.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains a command-line user interface for JPEG transcoding.
 * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
 * lossless transcoding between different JPEG file formats.  It also
 * provides some lossless and sort-of-lossless transformations of JPEG data.
 */

/* Modified by Felix Hanau. */

#define JPEG_INTERNAL_OPTIONS   /* cjpeg.c, djpeg.c need to see xxx_SUPPORTED */

#include "mozjpeg/jinclude.h"
#include "mozjpeg/jpeglib.h"

#define INPUT_BUF_SIZE  4096

static void jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
{
    jpeg_saved_marker_ptr marker;
    for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
        if (dstinfo->write_JFIF_header &&
            marker->marker == JPEG_APP0 &&
            marker->data_length >= 5 &&
            GETJOCTET(marker->data[0]) == 0x4A &&
            GETJOCTET(marker->data[1]) == 0x46 &&
            GETJOCTET(marker->data[2]) == 0x49 &&
            GETJOCTET(marker->data[3]) == 0x46 &&
            GETJOCTET(marker->data[4]) == 0)
            continue;                 /* reject duplicate JFIF */
        if (dstinfo->write_Adobe_marker &&
            marker->marker == JPEG_APP0+14 &&
            marker->data_length >= 5 &&
            GETJOCTET(marker->data[0]) == 0x41 &&
            GETJOCTET(marker->data[1]) == 0x64 &&
            GETJOCTET(marker->data[2]) == 0x6F &&
            GETJOCTET(marker->data[3]) == 0x62 &&
            GETJOCTET(marker->data[4]) == 0x65)
            continue;                 /* reject duplicate Adobe */
        jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length);
    }
}

static void parse_switches (j_compress_ptr cinfo, bool progressive, bool arithmetic, bool for_real)
{
    cinfo->err->trace_level = 0;
    if (progressive == false){
        jpeg_c_set_int_param(cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST);
        if(arithmetic == false){
            cinfo->optimize_coding = TRUE;
        }
    }
    if (arithmetic){
        cinfo->arith_code = TRUE;
        cinfo->optimize_coding = FALSE;
    }
    if (for_real) {
    if (cinfo->num_scans != 0)     /* process -progressive */
      jpeg_simple_progression(cinfo);
  }
  return;
}

int mozjpegtran (bool arithmetic, bool progressive, bool copyoption, const char * Input, const char * Output)
{
    struct jpeg_decompress_struct srcinfo;
    struct jpeg_compress_struct dstinfo;
    struct jpeg_error_mgr jsrcerr, jdsterr;
    FILE * fp;
    unsigned char *inbuffer = NULL;
    unsigned long insize = 0;
    unsigned char *outbuffer = NULL;
    unsigned long outsize = 0;
    const char * progname = "ECT (JPEG)";
    /* Initialize the JPEG decompression object with default error handling. */
    srcinfo.err = jpeg_std_error(&jsrcerr);
    jpeg_create_decompress(&srcinfo);
    /* Initialize the JPEG compression object with default error handling. */
    dstinfo.err = jpeg_std_error(&jdsterr);
    jpeg_create_compress(&dstinfo);

    /* Scan command line to find file names.
       It is convenient to use just one switch-parsing routine, but the switch
       values read here are mostly ignored; we will rescan the switches after
       opening the input file.  Also note that most of the switches affect the
       destination JPEG object, so we parse into that and then copy over what
       needs to affects the source too.
     */

    parse_switches(&dstinfo, progressive, arithmetic, FALSE);
    jsrcerr.trace_level = jdsterr.trace_level;
    srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;

    /* Open the input file. */
    if ((fp = fopen(Input, "rb")) == NULL) {
        fprintf(stderr, "%s: can't open %s for reading\n", progname, Input);
        return 2;
    }

#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
    size_t nbytes;
    do {
        inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE);
        if (inbuffer == NULL) {
            fprintf(stderr, "%s: memory allocation failure\n", progname);
            exit(1);
      }
        nbytes = JFREAD(fp, &inbuffer[insize], INPUT_BUF_SIZE);
        if (nbytes < INPUT_BUF_SIZE && ferror(fp)) {
            fprintf(stderr, "%s: can't read from %s\n", progname, Input);
        }
        insize += (unsigned long)nbytes;
    } while (nbytes == INPUT_BUF_SIZE);
    jpeg_mem_src(&srcinfo, inbuffer, insize);
#else
    jpeg_stdio_src(&srcinfo, fp);
#endif

    /* Enable saving of extra markers that we want to copy */
    if (copyoption == false) {
        jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF);
        for (int m = 0; m < 16; m++)
            jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF);
    }

    /* Read file header */
    jpeg_read_header(&srcinfo, TRUE);

    /* Any space needed by a transform option must be requested before
       jpeg_read_coefficients so that memory allocation will be done right.
     */

    /* Read source file as DCT coefficients */
    jvirt_barray_ptr * src_coef_arrays = jpeg_read_coefficients(&srcinfo);

    /* Initialize destination compression parameters from source values */
    jpeg_copy_critical_parameters(&srcinfo, &dstinfo);

    /* Adjust destination parameters if required by transform options;
     also find out which set of coefficient arrays will hold the output.
    */
    jvirt_barray_ptr * dst_coef_arrays = src_coef_arrays;

    fclose(fp);

    /* Open the output file. */
    if ((fp = fopen(Output, "wb")) == NULL) {
        fprintf(stderr, "%s: can't open %s for writing\n", progname, Output);
        return 2;
    }

    /* Adjust default compression parameters by re-parsing the options */
    parse_switches(&dstinfo, progressive, arithmetic, TRUE);

    /* Specify data destination for compression */
#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
    jpeg_mem_dest(&dstinfo, &outbuffer, &outsize);
#else
    jpeg_stdio_dest(&dstinfo, fp);
#endif

    /* Start compressor (note no image data is actually written here) */
    jpeg_write_coefficients(&dstinfo, dst_coef_arrays);

    /* Copy to the output file any extra markers that we want to preserve */
    jcopy_markers_execute(&srcinfo, &dstinfo);

    /* Finish compression and release memory */
    jpeg_finish_compress(&dstinfo);

    unsigned char *buffer = outbuffer;
    unsigned long size = outsize;
    int x=0;
    if (progressive){
    if (insize <= size) {
        size = insize;
        buffer = inbuffer;
        x = 1;
    }
    }
    else{
        if (insize < size) {
            size = insize;
            buffer = inbuffer;
            x = 1;
        }
    }

    size_t nbytes2 = JFWRITE(fp, buffer, size);
    if (nbytes2 < size && ferror(fp)) {
        fprintf(stderr, "%s: can't write to %s\n", progname, Output);
    }
    jpeg_destroy_compress(&dstinfo);
    jpeg_finish_decompress(&srcinfo);
    jpeg_destroy_decompress(&srcinfo);
    fclose(fp);
    free(inbuffer);
    free(outbuffer);
    return x;
}
<commit_msg>JPEG: Only write file when it is smaller<commit_after>/*
 * jpegtran.c
 *
 * This file was part of the Independent JPEG Group's software:
 * Copyright (C) 1995-2010, Thomas G. Lane, Guido Vollbeding.
 * libjpeg-turbo Modifications:
 * Copyright (C) 2010, 2014, D. R. Commander.
 * mozjpeg Modifications:
 * Copyright (C) 2014, Mozilla Corporation.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains a command-line user interface for JPEG transcoding.
 * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
 * lossless transcoding between different JPEG file formats.  It also
 * provides some lossless and sort-of-lossless transformations of JPEG data.
 */

/* Modified by Felix Hanau. */

#define JPEG_INTERNAL_OPTIONS   /* cjpeg.c, djpeg.c need to see xxx_SUPPORTED */

#include "mozjpeg/jinclude.h"
#include "mozjpeg/jpeglib.h"

#define INPUT_BUF_SIZE  4096

static void jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
{
    jpeg_saved_marker_ptr marker;
    for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
        if (dstinfo->write_JFIF_header &&
            marker->marker == JPEG_APP0 &&
            marker->data_length >= 5 &&
            GETJOCTET(marker->data[0]) == 0x4A &&
            GETJOCTET(marker->data[1]) == 0x46 &&
            GETJOCTET(marker->data[2]) == 0x49 &&
            GETJOCTET(marker->data[3]) == 0x46 &&
            GETJOCTET(marker->data[4]) == 0)
            continue;                 /* reject duplicate JFIF */
        if (dstinfo->write_Adobe_marker &&
            marker->marker == JPEG_APP0+14 &&
            marker->data_length >= 5 &&
            GETJOCTET(marker->data[0]) == 0x41 &&
            GETJOCTET(marker->data[1]) == 0x64 &&
            GETJOCTET(marker->data[2]) == 0x6F &&
            GETJOCTET(marker->data[3]) == 0x62 &&
            GETJOCTET(marker->data[4]) == 0x65)
            continue;                 /* reject duplicate Adobe */
        jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length);
    }
}

static void parse_switches (j_compress_ptr cinfo, bool progressive, bool arithmetic, bool for_real)
{
    cinfo->err->trace_level = 0;
    if (!progressive){
        jpeg_c_set_int_param(cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST);
        cinfo->optimize_coding = TRUE;
    }
    if (arithmetic){
        cinfo->arith_code = TRUE;
        cinfo->optimize_coding = FALSE;
    }
    if (for_real && cinfo->num_scans != 0 && progressive) { /* process -progressive */
        jpeg_simple_progression(cinfo);
    }
  return;
}

int mozjpegtran (bool arithmetic, bool progressive, bool copyoption, const char * Infile, const char * Outfile)
{
    struct jpeg_decompress_struct srcinfo;
    struct jpeg_compress_struct dstinfo;
    struct jpeg_error_mgr jsrcerr, jdsterr;
    FILE * fp;
    unsigned char *inbuffer = NULL;
    unsigned long insize = 0;
    unsigned char *outbuffer = NULL;
    unsigned long outsize = 0;
    const char * progname = "ECT (JPEG)";
    /* Initialize the JPEG decompression object with default error handling. */
    srcinfo.err = jpeg_std_error(&jsrcerr);
    jpeg_create_decompress(&srcinfo);
    /* Initialize the JPEG compression object with default error handling. */
    dstinfo.err = jpeg_std_error(&jdsterr);
    jpeg_create_compress(&dstinfo);

    /* Scan command line to find file names.
       It is convenient to use just one switch-parsing routine, but the switch
       values read here are mostly ignored; we will rescan the switches after
       opening the input file.  Also note that most of the switches affect the
       destination JPEG object, so we parse into that and then copy over what
       needs to affects the source too.
     */

    parse_switches(&dstinfo, progressive, arithmetic, false);
    jsrcerr.trace_level = jdsterr.trace_level;
    srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;

    /* Open the input file. */
    if ((fp = fopen(Infile, "rb")) == NULL) {
        fprintf(stderr, "%s: can't open %s for reading\n", progname, Infile);
        return 2;
    }

    size_t nbytes;
    do {
        inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE);
        if (inbuffer == NULL) {
            fprintf(stderr, "%s: memory allocation failure\n", progname);
            exit(1);
      }
        nbytes = JFREAD(fp, &inbuffer[insize], INPUT_BUF_SIZE);
        if (nbytes < INPUT_BUF_SIZE && ferror(fp)) {
            fprintf(stderr, "%s: can't read from %s\n", progname, Infile);
        }
        insize += (unsigned long)nbytes;
    } while (nbytes == INPUT_BUF_SIZE);
    jpeg_mem_src(&srcinfo, inbuffer, insize);

    /* Enable saving of extra markers that we want to copy */
    if (!copyoption) {
        jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF);
        for (int m = 0; m < 16; m++)
            jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF);
    }

    /* Read file header */
    jpeg_read_header(&srcinfo, TRUE);

    /* Any space needed by a transform option must be requested before
       jpeg_read_coefficients so that memory allocation will be done right.
     */

    /* Read source file as DCT coefficients */
    jvirt_barray_ptr * src_coef_arrays = jpeg_read_coefficients(&srcinfo);

    /* Initialize destination compression parameters from source values */
    jpeg_copy_critical_parameters(&srcinfo, &dstinfo);

    /* Adjust destination parameters if required by transform options;
     also find out which set of coefficient arrays will hold the output.
    */
    jvirt_barray_ptr * dst_coef_arrays = src_coef_arrays;

    fclose(fp);

    /* Adjust default compression parameters by re-parsing the options */
    parse_switches(&dstinfo, progressive, arithmetic, true);

    /* Specify data destination for compression */
    jpeg_mem_dest(&dstinfo, &outbuffer, &outsize);

    /* Start compressor (note no image data is actually written here) */
    jpeg_write_coefficients(&dstinfo, dst_coef_arrays);

    /* Copy to the output file any extra markers that we want to preserve */
    jcopy_markers_execute(&srcinfo, &dstinfo);

    /* Finish compression and release memory */
    jpeg_finish_compress(&dstinfo);

    unsigned char *buffer = outbuffer;
    int x = 0;

    if (insize < outsize || (progressive && insize == outsize)){
        x = 1;
    }

    /* Better file than before */
    else{
        /* Open the output file. */
        if ((fp = fopen(Outfile, "wb")) == NULL) {
            fprintf(stderr, "%s: can't open %s for writing\n", progname, Outfile);
            free(inbuffer);
            return 2;
        }

        /* Write new file. */
        size_t nbytes2 = JFWRITE(fp, buffer, outsize);
        if (nbytes2 < outsize && ferror(fp)) {
            fprintf(stderr, "%s: can't write to %s\n", progname, Outfile);
        }
    }
    jpeg_destroy_compress(&dstinfo);
    jpeg_finish_decompress(&srcinfo);
    jpeg_destroy_decompress(&srcinfo);
    fclose(fp);
    free(inbuffer);
    free(outbuffer);
    return x;
}
<|endoftext|>