<commit_before>#pragma once

namespace ODLib
{
    /// <summary>
    /// Singleton template class.
    /// </summary>
    /// <typeparam name="T">The type of the singleton.</typeparam>
    template<typename T>
    class Singleton
    {
    public:

        /// <summary>
        /// Construct the class.
        /// </summary>
        /// <returns>The instance of the class.</returns>
        template<typename... Args>
        static T* Construct(Args&& ...args)
        {
            std::call_once(m_constructFlag, [&]()
            {
                m_instance = new T(std::forward<Args>(args)...);
                std::atexit(Release);
            });

            return m_instance;
        }

        /// <summary>
        /// Get the instance of the singleton, construct it if needed.
        /// </summary>
        /// <returns>The instance of the class.</returns>
        static T* GetInstance()
        {
            if (IsReleased() == true)
            {
                return Construct();
            }

            return m_instance;
        }

        /// <summary>
        /// Check if the singleton is released.
        /// </summary>
        /// <returns>true if it is released, false otherwise.</returns>
        static const bool IsReleased()
        {
            return m_instance == nullptr;
        }

        /// <summary>
        /// Release the singleton.
        /// </summary>
        static void Release()
        {
            if (IsReleased() == false)
            {
                std::call_once(m_releaseFlag, [&]()
                {
                    delete m_instance;
                    m_instance = nullptr;
                });
            }
        }

    protected:

        Singleton() = default;
        virtual ~Singleton() = default;

    private:

        Singleton(Singleton const&) = delete;
        Singleton& operator=(Singleton const&) = delete;

        static T* m_instance;

        static std::once_flag m_constructFlag;

        static std::once_flag m_releaseFlag;
    };

    template<typename T>
    T* Singleton<T>::m_instance = nullptr;

    template<typename T>
    std::once_flag Singleton<T>::m_constructFlag;

    template<typename T>
    std::once_flag Singleton<T>::m_releaseFlag;
}<commit_msg>Don't allow move for "Singleton" class<commit_after>#pragma once

namespace ODLib
{
    /// <summary>
    /// Singleton template class.
    /// </summary>
    /// <typeparam name="T">The type of the singleton.</typeparam>
    template<typename T>
    class Singleton
    {
    public:

        /// <summary>
        /// Construct the class.
        /// </summary>
        /// <returns>The instance of the class.</returns>
        template<typename... Args>
        static T* Construct(Args&& ...args)
        {
            std::call_once(m_constructFlag, [&]()
            {
                m_instance = new T(std::forward<Args>(args)...);
                std::atexit(Release);
            });

            return m_instance;
        }

        /// <summary>
        /// Get the instance of the singleton, construct it if needed.
        /// </summary>
        /// <returns>The instance of the class.</returns>
        static T* GetInstance()
        {
            if (IsReleased() == true)
            {
                return Construct();
            }

            return m_instance;
        }

        /// <summary>
        /// Check if the singleton is released.
        /// </summary>
        /// <returns>true if it is released, false otherwise.</returns>
        static const bool IsReleased()
        {
            return m_instance == nullptr;
        }

        /// <summary>
        /// Release the singleton.
        /// </summary>
        static void Release()
        {
            if (IsReleased() == false)
            {
                std::call_once(m_releaseFlag, [&]()
                {
                    delete m_instance;
                    m_instance = nullptr;
                });
            }
        }

    protected:

        Singleton() = default;
        virtual ~Singleton() = default;

    private:

        Singleton(const Singleton&) = delete;
        Singleton(Singleton&&) = delete;
        Singleton& operator=(const Singleton&) = delete;
        Singleton& operator=(Singleton&&) = delete;

        static T* m_instance;

        static std::once_flag m_constructFlag;

        static std::once_flag m_releaseFlag;
    };

    template<typename T>
    T* Singleton<T>::m_instance = nullptr;

    template<typename T>
    std::once_flag Singleton<T>::m_constructFlag;

    template<typename T>
    std::once_flag Singleton<T>::m_releaseFlag;
}<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013 Daniel Mansfield

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <cstdlib>
#include <ctime>

#include "atlas.hpp"
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include "inventory.hpp"
#include "creature.hpp"
#include "dialogue.hpp"
#include "area.hpp"
#include "battle.hpp"

// New character menu
Creature dialogue_newchar();

// Character information menu, displays the items the player has, their
// current stats etc.
void dialogue_menu(Creature& player);

int main(void)
{
	std::vector<Creature> creatureAtlas;
	std::vector<Item> itemAtlas;
	std::vector<Weapon> weaponAtlas;
	std::vector<Armour> armourAtlas;
	std::vector<Area> areaAtlas;

	Creature player;

	// Build the atlases
	buildatlas_creature(creatureAtlas);
	buildatlas_item(itemAtlas);
	buildatlas_weapon(weaponAtlas);
	buildatlas_armour(armourAtlas);
	buildatlas_area(areaAtlas, itemAtlas, weaponAtlas, armourAtlas, creatureAtlas);

	// Seed the random number generator with the system time, so the
	// random numbers produced by rand() will be different each time
	srand(time(NULL));

	// Main game menu dialogue
	int result = Dialogue(
		"Welcome!",
		{"New Game"}).activate();

	switch(result)
	{
		case 1: player = dialogue_newchar(); break;
		default: return 0; break;
	}

	// Set the current area to be the first area in the atlas, essentially
	// placing the player there upon game start
	Area* currentArea = &(areaAtlas[0]);

	// Play the game until a function breaks the loop and closes it
	while(1)
	{
		// If the player has died then inform them as such and close
		// the program
		if(player.health <= 0)
		{
			std::cout << "\t----YOU DIED----\n    Game Over\n";
			return 0;
		}

		// If the area the player is in has any creatures inside it,
		// then begin a battle with the last creature in the list
		// before moving on the next one. This makes the creature
		// list act like a stack
		if(currentArea->creatures.size() > 0)
		{
		    for(int i = currentArea->creatures.size() - 1; i >= 0; --i)
		    {
			    Battle(&player, currentArea->creatures[i]).run();
			    // Remove the creature from the area. This is fine to do
			    // because if the player wins the creature will not respawn,
			    // and if the creature wins the player isn't around to see it
			    // (This does break the 'non-mutable' feature of the atlases,
			    // but doing so saves a lot of memory, as we don't need to keep
			    // two versions of each area)
			    currentArea->creatures.pop_back();
		    }
        }

		// Activate the current area's dialogue
		result = currentArea->dialogue.activate();

		// These could be moved inside of the area code using an event
		// style system, but that allows for much less flexibility with
		// what happens in each area. Since we're defining the areas in
		// code anyway, sticking with this isn't too much of a problem,
		// and it keeps things easy to understand
		if(currentArea == &(areaAtlas[0]))
		{
			switch(result)
			{
				// Open the menu
				case 0:
					dialogue_menu(player);
					break;
				case 1:
				// Move to area 1
					currentArea = &(areaAtlas[1]);
					break;
				case 2:
				// Search the area
					currentArea->search(player);
					break;
				default:
					break;
			}
		}
		else if(currentArea == &(areaAtlas[1]))
		{
			switch(result)
			{
				// Open the menu
				case 0:
					dialogue_menu(player);
					break;
				// Move to area 0
				case 1:
					currentArea = &(areaAtlas[0]);
					break;
				// Search the area
				case 2:
					currentArea->search(player);
					break;
				default:
					break;
			}
		}
	}

	return 0;
}

// Create a new character
Creature dialogue_newchar()
{
	// Ask for a name and class
	// Name does not use a dialogue since dialogues only request options,
	// not string input. Could be generalised into its own TextInput
	// class, but not really necessary
	std::cout << "Choose your name" << std::endl;
	std::string name;
	std::cin >> name;

	int result = Dialogue(
		"Choose your class",
		{"Fighter", "Rogue"}).activate();

	switch(result)
	{
		// Fighter class favours health and strength
		case 1:
			return Creature(name, 35, 20, 10, 5, 10.0, 1, "Fighter");
			break;

		// Rogue class favours dexterity and hit rate
		case 2:
			return Creature(name, 30, 5, 10, 20, 15.0, 1, "Fighter");
			break;

		// Default case that should never happen, but it's good to be safe
		default:
			return Creature(name, 30, 10, 10, 10, 10.0, 1, "Adventurer");
		break;
	}
}

void dialogue_menu(Creature& player)
{
	// Output the menu
	int result = Dialogue(
		"Menu\n====",
		{"Items", "Equipment", "Character"}).activate();

	switch(result)
	{
		// Print the items that the player owns
		case 1:
			std::cout << "Items\n=====\n";
			player.inventory.print();
			std::cout << "----------------\n";
			break;
		// Print the equipment that the player is wearing (if they are
		// wearing anything) and then ask if they want to equip a weapon
		// or some armour
		case 2:
		{
			std::cout << "Equipment\n=========\n";
			std::cout << "Head: "
				<< (player.equippedArmour[Armour::Slot::HEAD] != nullptr ?
					player.equippedArmour[Armour::Slot::HEAD]->name : "Nothing")
				<< std::endl;
			std::cout << "Torso: "
				<< (player.equippedArmour[Armour::Slot::TORSO] != nullptr ?
					player.equippedArmour[Armour::Slot::TORSO]->name : "Nothing")
				<< std::endl;
			std::cout << "Legs: "
				<< (player.equippedArmour[Armour::Slot::LEGS] != nullptr ?
					player.equippedArmour[Armour::Slot::LEGS]->name : "Nothing")
				<< std::endl;
			std::cout << "Weapon: "
				<< (player.equippedWeapon != nullptr ?
					player.equippedWeapon->name : "Nothing")
				<< std::endl;

			int result2 = Dialogue(
				"",
				{"Equip Armour", "Equip Weapon", "Close"}).activate();

			// Equipping armour
			if(result2 == 1)
			{
				int userInput = 0;

				// Cannot equip armour if they do not have any
				// Print a list of the armour and retrieve the amount
				// of armour in one go
				int numItems = player.inventory.print_armour(true);
				if(numItems == 0) break;

				while(!userInput)
				{
					// Choose a piece of armour to equip
					std::cout << "Equip which item?" << std::endl;
					std::cin >> userInput;
					// Equipment is numbered but is stored in a list,
					// so the number must be converted into a list element
					if(userInput >= 1 && userInput <= numItems)
					{
						int i = 1;

						for(auto it : player.inventory.armour)
						{
							if(i++ == userInput)
							{
								// Equip the armour if it is found
								player.equipArmour(it.first);
								break;
							}
						}
					}
				}
			}
			// Equip a weapon, using the same algorithms as for armour
			else if(result2 == 2)
			{
				int userInput = 0;
				int numItems = player.inventory.print_weapons(true);

				if(numItems == 0) break;

				while(!userInput)
				{
					std::cout << "Equip which item?" << std::endl;
					std::cin >> userInput;
					if(userInput >= 1 && userInput <= numItems)
					{
						int i = 1;

						for(auto it : player.inventory.weapons)
						{
							if(i++ == userInput)
							{
								player.equipWeapon(it.first);
								break;
							}
						}
					}
				}
			}
			std::cout << "----------------\n";
			break;
		}
		// Output the character information, including name, class (if
		// they have one), stats, level, and experience
		case 3:
			std::cout << "Character\n=========\n";
			std::cout << player.name;
			if(player.className != "") std::cout << " the " << player.className;
			std::cout << std::endl;

			std::cout << "HP: " << player.health << " / " << player.maxHealth << std::endl;
			std::cout << "Str: " << player.str << std::endl;
			std::cout << "End: " << player.end << std::endl;
			std::cout << "Dex: " << player.dex << std::endl;
			std::cout << "Lvl: " << player.level << " (" << player.exp;
			std::cout <<  " / " << player.expToLevel(player.level+1) << ")" << std::endl;
			std::cout << "----------------\n";
			break;
		default:
			break;
	}

	return;
}
<commit_msg>Simplified area menu handling by moving the menu<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013 Daniel Mansfield

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <cstdlib>
#include <ctime>

#include "atlas.hpp"
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include "inventory.hpp"
#include "creature.hpp"
#include "dialogue.hpp"
#include "area.hpp"
#include "battle.hpp"

// New character menu
Creature dialogue_newchar();

// Character information menu, displays the items the player has, their
// current stats etc.
void dialogue_menu(Creature& player);

int main(void)
{
	std::vector<Creature> creatureAtlas;
	std::vector<Item> itemAtlas;
	std::vector<Weapon> weaponAtlas;
	std::vector<Armour> armourAtlas;
	std::vector<Area> areaAtlas;

	Creature player;

	// Build the atlases
	buildatlas_creature(creatureAtlas);
	buildatlas_item(itemAtlas);
	buildatlas_weapon(weaponAtlas);
	buildatlas_armour(armourAtlas);
	buildatlas_area(areaAtlas, itemAtlas, weaponAtlas, armourAtlas, creatureAtlas);

	// Seed the random number generator with the system time, so the
	// random numbers produced by rand() will be different each time
	srand(time(NULL));

	// Main game menu dialogue
	int result = Dialogue(
		"Welcome!",
		{"New Game"}).activate();

	switch(result)
	{
		case 1: player = dialogue_newchar(); break;
		default: return 0; break;
	}

	// Set the current area to be the first area in the atlas, essentially
	// placing the player there upon game start
	Area* currentArea = &(areaAtlas[0]);

	// Play the game until a function breaks the loop and closes it
	while(1)
	{
		// If the player has died then inform them as such and close
		// the program
		if(player.health <= 0)
		{
			std::cout << "\t----YOU DIED----\n    Game Over\n";
			return 0;
		}

		// If the area the player is in has any creatures inside it,
		// then begin a battle with the last creature in the list
		// before moving on the next one. This makes the creature
		// list act like a stack
		if(currentArea->creatures.size() > 0)
		{
		    for(int i = currentArea->creatures.size() - 1; i >= 0; --i)
		    {
			    Battle(&player, currentArea->creatures[i]).run();
			    // Remove the creature from the area. This is fine to do
			    // because if the player wins the creature will not respawn,
			    // and if the creature wins the player isn't around to see it
			    // (This does break the 'non-mutable' feature of the atlases,
			    // but doing so saves a lot of memory, as we don't need to keep
			    // two versions of each area)
			    currentArea->creatures.pop_back();
		    }
        }

		// Activate the current area's dialogue
		result = currentArea->dialogue.activate();

		// These could be moved inside of the area code using an event
		// style system, but that allows for much less flexibility with
		// what happens in each area. Since we're defining the areas in
		// code anyway, sticking with this isn't too much of a problem,
		// and it keeps things easy to understand
		if(result == 0)
		{
			// Open the menu
			dialogue_menu(player);
			continue;
		}
		if(currentArea == &(areaAtlas[0]))
		{
			switch(result)
			{
				case 1:
				// Move to area 1
					currentArea = &(areaAtlas[1]);
					break;
				case 2:
				// Search the area
					currentArea->search(player);
					break;
				default:
					break;
			}
		}
		else if(currentArea == &(areaAtlas[1]))
		{
			switch(result)
			{
				// Move to area 0
				case 1:
					currentArea = &(areaAtlas[0]);
					break;
				// Search the area
				case 2:
					currentArea->search(player);
					break;
				default:
					break;
			}
		}
	}

	return 0;
}

// Create a new character
Creature dialogue_newchar()
{
	// Ask for a name and class
	// Name does not use a dialogue since dialogues only request options,
	// not string input. Could be generalised into its own TextInput
	// class, but not really necessary
	std::cout << "Choose your name" << std::endl;
	std::string name;
	std::cin >> name;

	int result = Dialogue(
		"Choose your class",
		{"Fighter", "Rogue"}).activate();

	switch(result)
	{
		// Fighter class favours health and strength
		case 1:
			return Creature(name, 35, 20, 10, 5, 10.0, 1, "Fighter");
			break;

		// Rogue class favours dexterity and hit rate
		case 2:
			return Creature(name, 30, 5, 10, 20, 15.0, 1, "Fighter");
			break;

		// Default case that should never happen, but it's good to be safe
		default:
			return Creature(name, 30, 10, 10, 10, 10.0, 1, "Adventurer");
		break;
	}
}

void dialogue_menu(Creature& player)
{
	// Output the menu
	int result = Dialogue(
		"Menu\n====",
		{"Items", "Equipment", "Character"}).activate();

	switch(result)
	{
		// Print the items that the player owns
		case 1:
			std::cout << "Items\n=====\n";
			player.inventory.print();
			std::cout << "----------------\n";
			break;
		// Print the equipment that the player is wearing (if they are
		// wearing anything) and then ask if they want to equip a weapon
		// or some armour
		case 2:
		{
			std::cout << "Equipment\n=========\n";
			std::cout << "Head: "
				<< (player.equippedArmour[Armour::Slot::HEAD] != nullptr ?
					player.equippedArmour[Armour::Slot::HEAD]->name : "Nothing")
				<< std::endl;
			std::cout << "Torso: "
				<< (player.equippedArmour[Armour::Slot::TORSO] != nullptr ?
					player.equippedArmour[Armour::Slot::TORSO]->name : "Nothing")
				<< std::endl;
			std::cout << "Legs: "
				<< (player.equippedArmour[Armour::Slot::LEGS] != nullptr ?
					player.equippedArmour[Armour::Slot::LEGS]->name : "Nothing")
				<< std::endl;
			std::cout << "Weapon: "
				<< (player.equippedWeapon != nullptr ?
					player.equippedWeapon->name : "Nothing")
				<< std::endl;

			int result2 = Dialogue(
				"",
				{"Equip Armour", "Equip Weapon", "Close"}).activate();

			// Equipping armour
			if(result2 == 1)
			{
				int userInput = 0;

				// Cannot equip armour if they do not have any
				// Print a list of the armour and retrieve the amount
				// of armour in one go
				int numItems = player.inventory.print_armour(true);
				if(numItems == 0) break;

				while(!userInput)
				{
					// Choose a piece of armour to equip
					std::cout << "Equip which item?" << std::endl;
					std::cin >> userInput;
					// Equipment is numbered but is stored in a list,
					// so the number must be converted into a list element
					if(userInput >= 1 && userInput <= numItems)
					{
						int i = 1;

						for(auto it : player.inventory.armour)
						{
							if(i++ == userInput)
							{
								// Equip the armour if it is found
								player.equipArmour(it.first);
								break;
							}
						}
					}
				}
			}
			// Equip a weapon, using the same algorithms as for armour
			else if(result2 == 2)
			{
				int userInput = 0;
				int numItems = player.inventory.print_weapons(true);

				if(numItems == 0) break;

				while(!userInput)
				{
					std::cout << "Equip which item?" << std::endl;
					std::cin >> userInput;
					if(userInput >= 1 && userInput <= numItems)
					{
						int i = 1;

						for(auto it : player.inventory.weapons)
						{
							if(i++ == userInput)
							{
								player.equipWeapon(it.first);
								break;
							}
						}
					}
				}
			}
			std::cout << "----------------\n";
			break;
		}
		// Output the character information, including name, class (if
		// they have one), stats, level, and experience
		case 3:
			std::cout << "Character\n=========\n";
			std::cout << player.name;
			if(player.className != "") std::cout << " the " << player.className;
			std::cout << std::endl;

			std::cout << "HP: " << player.health << " / " << player.maxHealth << std::endl;
			std::cout << "Str: " << player.str << std::endl;
			std::cout << "End: " << player.end << std::endl;
			std::cout << "Dex: " << player.dex << std::endl;
			std::cout << "Lvl: " << player.level << " (" << player.exp;
			std::cout <<  " / " << player.expToLevel(player.level+1) << ")" << std::endl;
			std::cout << "----------------\n";
			break;
		default:
			break;
	}

	return;
}
<|endoftext|>


<commit_before>#include <stdexcept>
#include <limits>
#include <algorithm>
#include <array>
#include <memory>
#include <iomanip>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

#include "curleasy.h"

const std::string version("0.1.0");
const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");

const std::string file_checksum(const std::string &path);

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch()
        {
            std::cout << "Statting target " << name() << "...";
            std::string path;
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                auto elems = split(name(), '/');
                for (size_t i = 0, k = elems.size(); i < k; ++i)
                {
                    const std::string &s(elems[i]);
                    if (s.size() && s != ".")
                    {
                        path.append((i > 0 ? "/" : "") + s);
                        // i indicates a directory.
                        if (i < k - 1)
                        {
                            auto status = mkdir(path.c_str(), S_IRWXU);
                            if (status == -1)
                            {
                                std::error_code err(errno, std::generic_category());
                                if (err != std::errc::file_exists)
                                {
                                    std::cout << "error making dir: "
                                        << path << ": "
                                        << err.message() << std::endl;
                                }
                            }
                        }
                    }
                }
                fs.open(path, std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << path << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }
        Status status()
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();
            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch()
        {
            std::string s;
            std::string url(patch_dir + name());
            CurlEasy curl(url);
            curl.write_to(s);
            curl.perform();
            std::ofstream ofs(name());

            if (ofs.good())
            {
                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */

    return calcsum.str();
}

namespace Options
{
    bool version(const std::string &val)
    {
        return val == "version";
    }
    bool update_path(const std::string &val)
    {
        return val == "update path";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = tolower(c);
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

class EfuLauncher
{
    public:
        explicit EfuLauncher(const std::string path,
                const std::string update_check):
            m_path(path),
            m_update_check(update_check),
            m_has_update(false)
    {}

        bool has_update()
        {
            if (m_has_update)
            {
                return m_has_update;
            }

            std::string fetch;
            CurlEasy curl(m_update_check.c_str());
            curl.write_to(fetch);
            curl.perform();

            std::vector<std::string> lines(split(fetch, '\n'));
            fetch.clear();
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto keyvals(split(*beg, '='));
                if (keyvals.size() != 2)
                {
                    std::cerr << "Malformed option: " + *beg +
                        ", aborting launcher update check." << std::endl;
                    return m_has_update = false;
                }
                if (Options::version(keyvals[0]))
                {
                    const std::string version_test(keyvals[1]);
                    m_has_update = version_test != version;
                }
                else if (Options::update_path(keyvals[0]))
                {
                    m_update_path = keyvals[1];
                }

            }
            return m_has_update;
        }

        bool get_update()
        {
            if (!m_has_update || m_update_path.empty())
            {
                return m_has_update = false;
            }
            return !(m_has_update = false);
        }

        void stat_targets()
        {
            std::string fetch;
            CurlEasy curl(listing);
            curl.write_to(fetch);
            curl.perform();

            auto lines(split(fetch, '\n'));
            std::vector<Target> new_targets, old_targets;
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto data(split(*beg, '@'));
                Target t(data[0], data[data.size() - 1]);
                auto status = t.status();
                if (status == Target::Status::Nonexistent)
                {
                    new_targets.push_back(std::move(t));
                }
                else if (status == Target::Status::Outdated)
                {
                    old_targets.push_back(std::move(t));
                }
            }
            if (new_targets.size())
            {
                std::cout << "New targets: " << new_targets.size() << std::endl;
                for (auto &t : new_targets)
                {
                    std::cout << "- " << t.name() << std::endl;
                }
            }
            else
            {
                std::cout << "No new targets." << std::endl;
            }

            if (old_targets.size())
            {
                std::cout << "Outdated targets: " << old_targets.size() << std::endl;
                for (auto &t : old_targets)
                {
                    std::cout << "- " << t.name() << std::endl;
                }
            }
            else
            {
                std::cout << "No targets out of date." << std::endl;
            }

#ifndef DEBUG
            for (auto &t : new_targets)
            {
                t.fetch();
            }
            for (auto &t : old_targets)
            {
                t.fetch();
            }
#endif
        }

    private:
        const std::string path() const { return m_path; }

        const std::string m_path;
        const std::string m_update_check;
        std::string m_update_path;
        bool m_has_update;
};

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;

    EfuLauncher l(argv[0],
            "https://raw.github.com/commonquail/efulauncher/"\
            "master/versioncheck");
    if (l.has_update())
    {
        std::cout << "A new version of the launcher is available."\
            " Would you like to download it (y/n)?" << std::endl;
        bool download(confirm());
        if (!download)
        {
            std::cout << "It is strongly recommended to always use"\
                " the latest launcher. Would you like to download it (y/n)?"
                << std::endl;
            download = confirm();
        }
        if (download)
        {
            // Download.
            std::cout << "Downloading new launcher..." << std::endl;
            if (l.get_update())
            {
                std::cout << "Done. Please extract and run the new launcher." << std::endl;
            }
            return 0;
        }
    }

    l.stat_targets();

    return 0;
}
<commit_msg>Move directory creation to free function.<commit_after>#include <stdexcept>
#include <limits>
#include <algorithm>
#include <array>
#include <memory>
#include <iomanip>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

#include "curleasy.h"

const std::string version("0.1.0");
const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");

const std::string file_checksum(const std::string &path);

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

void make_dir(const std::string &path)
{
    auto elems = split(path, '/');
    std::string descend;
    for (size_t i = 0, k = elems.size() - 1; i < k; ++i)
    {
        const std::string &s(elems[i]);
        if (s.size() && s != ".")
        {
            descend.append((i > 0 ? "/" : "") + s);
            auto status = mkdir(descend.c_str(), S_IRWXU);
            if (status == -1)
            {
                std::error_code err(errno, std::generic_category());
                if (err != std::errc::file_exists)
                {
                    std::cout << "error making dir: "
                        << descend << ": "
                        << err.message() << std::endl;
                }
            }
        }
    }
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch()
        {
            std::cout << "Statting target " << name() << "...";
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                make_dir(name());
                fs.open(name(), std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << name() << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }
        Status status()
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();
            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch()
        {
            std::string s;
            std::string url(patch_dir + name());
            CurlEasy curl(url);
            curl.write_to(s);
            curl.perform();
            std::ofstream ofs(name());

            if (ofs.good())
            {
                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */

    return calcsum.str();
}

namespace Options
{
    bool version(const std::string &val)
    {
        return val == "version";
    }
    bool update_path(const std::string &val)
    {
        return val == "update path";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = tolower(c);
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

class EfuLauncher
{
    public:
        explicit EfuLauncher(const std::string path,
                const std::string update_check):
            m_path(path),
            m_update_check(update_check),
            m_has_update(false)
    {}

        bool has_update()
        {
            if (m_has_update)
            {
                return m_has_update;
            }

            std::string fetch;
            CurlEasy curl(m_update_check.c_str());
            curl.write_to(fetch);
            curl.perform();

            std::vector<std::string> lines(split(fetch, '\n'));
            fetch.clear();
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto keyvals(split(*beg, '='));
                if (keyvals.size() != 2)
                {
                    std::cerr << "Malformed option: " + *beg +
                        ", aborting launcher update check." << std::endl;
                    return m_has_update = false;
                }
                if (Options::version(keyvals[0]))
                {
                    const std::string version_test(keyvals[1]);
                    m_has_update = version_test != version;
                }
                else if (Options::update_path(keyvals[0]))
                {
                    m_update_path = keyvals[1];
                }

            }
            return m_has_update;
        }

        bool get_update()
        {
            if (!m_has_update || m_update_path.empty())
            {
                return m_has_update = false;
            }
            return !(m_has_update = false);
        }

        void stat_targets()
        {
            std::string fetch;
            CurlEasy curl(listing);
            curl.write_to(fetch);
            curl.perform();

            auto lines(split(fetch, '\n'));
            std::vector<Target> new_targets, old_targets;
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto data(split(*beg, '@'));
                Target t(data[0], data[data.size() - 1]);
                auto status = t.status();
                if (status == Target::Status::Nonexistent)
                {
                    new_targets.push_back(std::move(t));
                }
                else if (status == Target::Status::Outdated)
                {
                    old_targets.push_back(std::move(t));
                }
            }
            if (new_targets.size())
            {
                std::cout << "New targets: " << new_targets.size() << std::endl;
                for (auto &t : new_targets)
                {
                    std::cout << "- " << t.name() << std::endl;
                }
            }
            else
            {
                std::cout << "No new targets." << std::endl;
            }

            if (old_targets.size())
            {
                std::cout << "Outdated targets: " << old_targets.size() << std::endl;
                for (auto &t : old_targets)
                {
                    std::cout << "- " << t.name() << std::endl;
                }
            }
            else
            {
                std::cout << "No targets out of date." << std::endl;
            }

#ifndef DEBUG
            for (auto &t : new_targets)
            {
                t.fetch();
            }
            for (auto &t : old_targets)
            {
                t.fetch();
            }
#endif
        }

    private:
        const std::string path() const { return m_path; }

        const std::string m_path;
        const std::string m_update_check;
        std::string m_update_path;
        bool m_has_update;
};

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;

    EfuLauncher l(argv[0],
            "https://raw.github.com/commonquail/efulauncher/"\
            "master/versioncheck");
    if (l.has_update())
    {
        std::cout << "A new version of the launcher is available."\
            " Would you like to download it (y/n)?" << std::endl;
        bool download(confirm());
        if (!download)
        {
            std::cout << "It is strongly recommended to always use"\
                " the latest launcher. Would you like to download it (y/n)?"
                << std::endl;
            download = confirm();
        }
        if (download)
        {
            // Download.
            std::cout << "Downloading new launcher..." << std::endl;
            if (l.get_update())
            {
                std::cout << "Done. Please extract and run the new launcher." << std::endl;
            }
            return 0;
        }
    }

    l.stat_targets();

    return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>

#include <vector>
#include <fstream>
#include <sstream>
#include <experimental/optional>

#include "windows.h"
#include "Objbase.h"
#include "Shlobj.h"

using namespace std;
using namespace std::experimental;

TCHAR select_directory_path[MAX_PATH];

// TODO: A lot of error detection and handling is missing.

class COM {
public:
  COM() {
  if (CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED) != S_OK)
    throw runtime_error("Failed to initialize COM.");
  }
  ~COM() {
    CoUninitialize();
  }
};

class file_search {
public:
  WIN32_FIND_DATA find_data;
  HANDLE handle;

  file_search(string search_path) : find_data({}) {
    handle = FindFirstFile(search_path.c_str(), &find_data);
  }

  ~file_search() {
    if (handle != nullptr) FindClose(handle);
  }

  bool find_next() {
    return FindNextFile(handle, &find_data);
  }

  inline const char* found_filename() { return find_data.cFileName; };
};

optional<string> select_directory() {
  BROWSEINFO browseinfo {};
  browseinfo.pszDisplayName = select_directory_path;
  browseinfo.lpszTitle = "Please select directory containing the bin files.";
  browseinfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
  PIDLIST_ABSOLUTE idlist = SHBrowseForFolder(&browseinfo);
  if (idlist == nullptr) {
    return {};
  }
  else {
    if (!SHGetPathFromIDList(idlist, select_directory_path)) {
      CoTaskMemFree(idlist);
      throw runtime_error("SHGetPathFromIDList failed.");
    };
    CoTaskMemFree(idlist);
    return string(select_directory_path);
  }
}

vector<string> find_bin_files(string directory) {
  vector<string> result;

  file_search fs(directory + "\\*.bin");
  if (GetLastError() != ERROR_FILE_NOT_FOUND) {
    result.emplace_back(fs.found_filename());
    while (fs.find_next()) {
      result.emplace_back(fs.found_filename());
    }
  }

  return result;
}

string generate_cuesheet(vector<string> files) {
  stringstream ss;

  if (files.size() > 0) {
    ss << "FILE \"" << files.at(0) << "\" BINARY\n";
    ss << "  TRACK 01 MODE2/2352\n";
    ss << "    INDEX 01 00:00:00\n";
    for(size_t track = 1; track < files.size(); ++track) {
      ss << "FILE \"" << files.at(track) << "\" BINARY\n";
      ss << "  TRACK ";
      if (track < 10) ss << '0';
      ss << track << " AUDIO\n";
      ss << "   INDEX 00 00:00:00\n";
      ss << "   INDEX 01 00:02:00\n";
    };
  }

  return ss.str();
}

string generate_cuesheet_filename(vector<string> files) {
  return "Cuesheet.cue";
}

bool file_exists(string filename) {
  file_search fs(filename);
  auto error_code = GetLastError();

  if (error_code == ERROR_FILE_NOT_FOUND) return false;
  if (error_code == ERROR_NO_MORE_FILES) return true;
  throw error_code;
}

int main(int argc, const char* argv[]) {
  try {
    COM com;

    auto dir = select_directory();
    if (dir) {
      auto files = find_bin_files(*dir);
      if (files.empty()) throw runtime_error("No bin files found in the selected directory.");
      auto cuesheet = generate_cuesheet(files);
      string filename = generate_cuesheet_filename(files);
      string full_filename = *dir + '\\' + filename;

      bool write_file = true;
      if (file_exists(full_filename) &&
        (MessageBox(nullptr, "A cuesheet file already exists. Do you want to overwrite it?", "File exists", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO)) {
          write_file = false;
        }

      if (write_file) {
        ofstream file(full_filename.c_str(), ios::out);
        file << cuesheet.c_str();
      }
    }
  }
  catch (const exception& e) {
    MessageBox(nullptr, e.what(), "Error", MB_OK | MB_ICONERROR);
    return EXIT_FAILURE;
  }
  catch (DWORD error_code) {
    LPSTR buffer = nullptr;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
      error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&buffer), 0, nullptr);
    MessageBox(nullptr, buffer, "Error", MB_OK | MB_ICONERROR);
    LocalFree(buffer);
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<commit_msg>Add save dialog to select cuesheet filename<commit_after>#include <cstdlib>

#include <vector>
#include <fstream>
#include <sstream>
#include <experimental/optional>

#include "windows.h"
#include "Objbase.h"
#include "Shlobj.h"

using namespace std;
using namespace std::experimental;

TCHAR select_directory_path[MAX_PATH];

// TODO: A lot of error detection and handling is missing.

class COM {
public:
  COM() {
  if (CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED) != S_OK)
    throw runtime_error("Failed to initialize COM.");
  }
  ~COM() {
    CoUninitialize();
  }
};

class file_search {
public:
  WIN32_FIND_DATA find_data;
  HANDLE handle;

  file_search(string search_path) : find_data({}) {
    handle = FindFirstFile(search_path.c_str(), &find_data);
  }

  ~file_search() {
    if (handle != nullptr) FindClose(handle);
  }

  bool find_next() {
    return FindNextFile(handle, &find_data);
  }

  inline const char* found_filename() { return find_data.cFileName; };
};

optional<string> select_directory() {
  BROWSEINFO browseinfo {};
  browseinfo.pszDisplayName = select_directory_path;
  browseinfo.lpszTitle = "Please select directory containing the bin files.";
  browseinfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
  PIDLIST_ABSOLUTE idlist = SHBrowseForFolder(&browseinfo);
  if (idlist == nullptr) {
    return {};
  }
  else {
    if (!SHGetPathFromIDList(idlist, select_directory_path)) {
      CoTaskMemFree(idlist);
      throw runtime_error("SHGetPathFromIDList failed.");
    };
    CoTaskMemFree(idlist);
    return string(select_directory_path);
  }
}

vector<string> find_bin_files(string directory) {
  vector<string> result;

  file_search fs(directory + "\\*.bin");
  if (GetLastError() != ERROR_FILE_NOT_FOUND) {
    result.emplace_back(fs.found_filename());
    while (fs.find_next()) {
      result.emplace_back(fs.found_filename());
    }
  }

  return result;
}

string generate_cuesheet(vector<string> files) {
  stringstream ss;

  if (files.size() > 0) {
    ss << "FILE \"" << files.at(0) << "\" BINARY\n";
    ss << "  TRACK 01 MODE2/2352\n";
    ss << "    INDEX 01 00:00:00\n";
    for(size_t track = 1; track < files.size(); ++track) {
      ss << "FILE \"" << files.at(track) << "\" BINARY\n";
      ss << "  TRACK ";
      if (track < 10) ss << '0';
      ss << track << " AUDIO\n";
      ss << "   INDEX 00 00:00:00\n";
      ss << "   INDEX 01 00:02:00\n";
    };
  }

  return ss.str();
}

optional<string> get_cuesheet_filename(string directory, vector<string> files) {
  TCHAR filename[MAX_PATH];
  filename[0] = 0;
  OPENFILENAME save_dialog {};
  save_dialog.lStructSize = sizeof(save_dialog);
  save_dialog.lpstrFilter = "Cuesheet files (*.cue)\0*.cue\0All files\0*";
  save_dialog.lpstrDefExt = "cue";
  save_dialog.lpstrFile = filename;
  save_dialog.lpstrInitialDir = directory.c_str();
  save_dialog.nMaxFile = MAX_PATH;
  save_dialog.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
  save_dialog.FlagsEx = OFN_EX_NOPLACESBAR;

  if (GetSaveFileName(&save_dialog)) {
    return string(filename);
  }
  else {
    return {};
  }
}

bool file_exists(string filename) {
  file_search fs(filename);
  auto error_code = GetLastError();

  if (error_code == ERROR_FILE_NOT_FOUND) return false;
  if (error_code == ERROR_NO_MORE_FILES) return true;
  throw error_code;
}

int main(int argc, const char* argv[]) {
  try {
    COM com;

    auto dir = select_directory();
    if (dir) {
      auto files = find_bin_files(*dir);
      if (files.empty()) throw runtime_error("No bin files found in the selected directory.");
      auto cuesheet = generate_cuesheet(files);
      auto filename = get_cuesheet_filename(*dir, files);
      if (filename) {
        ofstream file(filename->c_str(), ios::out);
        file << cuesheet.c_str();
      }
    }
  }
  catch (const exception& e) {
    MessageBox(nullptr, e.what(), "Error", MB_OK | MB_ICONERROR);
    return EXIT_FAILURE;
  }
  catch (DWORD error_code) {
    LPSTR buffer = nullptr;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
      error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&buffer), 0, nullptr);
    MessageBox(nullptr, buffer, "Error", MB_OK | MB_ICONERROR);
    LocalFree(buffer);
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "compiler.h"
#include "mswin.h"
#include "glinit.h"
#include "model.h"
#include "cmdline.h"
#include <windowsx.h>
// #include "tinyscheme-config.h"
// #include <scheme-private.h>
// #include <scheme.h>
#include <cstdint>

namespace usr {
  // Program name.
  static const TCHAR * const program_name = TEXT ("Polymorph");
  static const TCHAR * const message =
  TEXT ("And the ratios of their numbers, motions, and ")
  TEXT ("other properties, everywhere God, as far as ")
  TEXT ("necessity allowed or gave consent, has exactly ")
  TEXT ("perfected, and harmonised in due proportion.");
  // TEXT ("\n\nThis screensaver includes TinyScheme, developed by Dimitrios ")
  // TEXT ("Souflis and licensed under the Modified BSD License. ")
  // TEXT ("See \"tinyscheme/COPYING.txt\" for details.");
}

inline std::uint64_t qpc ()
{
  LARGE_INTEGER t;
  ::QueryPerformanceCounter (& t);
  return t.QuadPart;
}

struct window_struct_t
{
  model_t model;
  POINT initial_cursor_position;
  run_mode_t mode;
};

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HGLRC setup_opengl_context (HWND hwnd);

// Called by custom_entry_point (below).
int custom_main (HINSTANCE hInstance)
{
  // Read command line arguments.

  HWND parent = NULL;
  run_mode_t mode = parse_command_line (::GetCommandLine (), & parent);

  if (mode == configure) {
    ::MessageBox (NULL, usr::message, usr::program_name, MB_OK | MB_ICONASTERISK);
    return 0;
  }

  // Placement and window style of the main window.

  RECT rect;
  DWORD style;
  DWORD ex_style  = 0;

  if (mode == embedded) {
    style = WS_CHILD | WS_VISIBLE;
    ::GetClientRect (parent, & rect); // 0, 0, width, height
  }
  else {
    style = WS_POPUP | WS_VISIBLE;
    if (mode == fullscreen) ex_style = WS_EX_TOPMOST;
    rect.left =   ::GetSystemMetrics (SM_XVIRTUALSCREEN);
    rect.top =    ::GetSystemMetrics (SM_YVIRTUALSCREEN);
    rect.right =  ::GetSystemMetrics (SM_CXVIRTUALSCREEN); // actually width, not right
    rect.bottom = ::GetSystemMetrics (SM_CYVIRTUALSCREEN); // actually height, not bottom
  }

  window_struct_t ws ALIGNED16;
  ws.mode = mode;

  // Create a window with an OpenGL rendering context.

  // To obtain a proper OpenGL pixel format, we need to call wglChoosePixelFormatARB, but
  // first we must obtain the address of that function by calling using wglGetProcAddress,
  // which requires that an OpenGL rendering context is current, which requires a device
  // context that supports OpenGL, which requires a window with an OpenGL pixel format.

  // Bootstrap the process with a legacy OpenGL pixel format. According to MSDN,
  // "Once a window's pixel format is set, it cannot be changed", so the window
  // and associated resources are of no further use and are destroyed here.

  // Create the dummy window. See InitWndProc.
  // Note this window does not survive creation.
  WNDCLASS init_wc;
  ::ZeroMemory (& init_wc, sizeof init_wc);
  init_wc.hInstance = hInstance;
  init_wc.lpfnWndProc = & InitWndProc;
  init_wc.lpszClassName = TEXT ("GLinit");
  ATOM init_wc_atom = ::RegisterClass (& init_wc);
  ::CreateWindowEx (0, MAKEINTATOM (init_wc_atom), TEXT (""), 0,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, hInstance, NULL);
  ::UnregisterClass (MAKEINTATOM (init_wc_atom), hInstance);

  // Exit if we failed to get the function pointers.
  if (! wglChoosePixelFormatARB) return -1;

  // Create the main window. See MainWndProc.
  WNDCLASS main_wc;
  ::ZeroMemory (& main_wc, sizeof main_wc);
  main_wc.hInstance = hInstance;
  main_wc.lpfnWndProc = & MainWndProc;
  main_wc.hIcon = ::LoadIcon (hInstance, MAKEINTRESOURCE (257));
  main_wc.lpszClassName = usr::program_name;
  ATOM main_wc_atom = ::RegisterClass (& main_wc);
  HWND hwnd = ::CreateWindowEx (ex_style, MAKEINTATOM (main_wc_atom), usr::program_name, style,
                                rect.left, rect.top, rect.right, rect.bottom,
                                parent, NULL, hInstance, & ws);

  // Exit if we failed to create the window.
  if (! hwnd) return 1;

  // Enter the main loop.
  MSG msg;
  while (::GetMessage (& msg, NULL, 0, 0)) {
    ::TranslateMessage (& msg);
    ::DispatchMessage (& msg);
  }

  ::UnregisterClass (MAKEINTATOM (main_wc_atom), hInstance);
  return msg.wParam;
}

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_NCCREATE) {
    // Set up legacy rendering context to get OpenGL function pointers.
    PIXELFORMATDESCRIPTOR pfd;
    ::ZeroMemory (& pfd, sizeof pfd);
    pfd.nSize = sizeof pfd;
    pfd.dwFlags = PFD_SUPPORT_OPENGL;
    if (HDC hdc = ::GetDC (hwnd)) {
      int pf = ::ChoosePixelFormat (hdc, & pfd);
      ::SetPixelFormat (hdc, pf, & pfd);
      if (HGLRC hglrc = ::wglCreateContext (hdc)) {
        ::wglMakeCurrent (hdc, hglrc);
        // Get the function pointers.
        get_glprocs ();
        ::wglMakeCurrent (NULL, NULL);
        ::wglDeleteContext (hglrc);
      }
      ::ReleaseDC (hwnd, hdc);
    }
    return FALSE; // Abort window creation.
  }
  else {
    return ::DefWindowProc (hwnd, msg, wParam, lParam);
  }
}

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  LRESULT result = 0;
  bool call_def_window_proc = false, close_window = false;

  // Retrieve the window-struct pointer from the window userdata.
  window_struct_t * ws = reinterpret_cast <window_struct_t *> (::GetWindowLongPtr (hwnd, GWLP_USERDATA));

  switch (msg) {
  case WM_CREATE: {
    result = -1; // Abort window creation.

    // Stash the window-struct pointer in the window userdata.
    CREATESTRUCT * cs = reinterpret_cast <CREATESTRUCT *> (lParam);
    ws = reinterpret_cast <window_struct_t *> (cs->lpCreateParams);
    ::SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast <LONG_PTR> (ws));

    // Remember initial mouse-pointer position to detect mouse movement.
    ::GetCursorPos (& ws->initial_cursor_position);

    // Set up OpenGL rendering context.
    HGLRC hglrc = setup_opengl_context (hwnd);
    if (hglrc) {
      ws->model.initialize (qpc (), cs->cx, cs->cy);
      ::PostMessage (hwnd, WM_APP, 0, 0);  // Start the simulation.
      result = 0;                          // Allow window creation to continue.
    }
    break;
  }

  case WM_APP: {
    ws->model.draw_next ();
    ::InvalidateRect (hwnd, NULL, FALSE);
    break;
  }

  case WM_PAINT: {
    PAINTSTRUCT ps;
    ::BeginPaint (hwnd, & ps);
    ::SwapBuffers (ps.hdc);
    ::EndPaint (hwnd, & ps);
    ::PostMessage (hwnd, WM_APP, 0, 0);
    break;
  }

  case WM_SETCURSOR:
    ::SetCursor (ws->mode == fullscreen ? NULL : (::LoadCursor (NULL, IDC_ARROW)));
    break;

  case WM_MOUSEMOVE:
    if (ws->mode == fullscreen) {
      // Compare the current mouse position with the one stored in the window struct.
      POINT current = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
      ::ClientToScreen (hwnd, & current);
      SHORT dx = current.x - ws->initial_cursor_position.x;
      SHORT dy = current.y - ws->initial_cursor_position.y;
      close_window = dx > 10 || dy > 10 || dx * dx + dy * dy  > 100;
    }
    break;

  case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN:
    close_window = ws->mode == fullscreen || ws->mode == special;
    break;

  case WM_ACTIVATE: case WM_ACTIVATEAPP: case WM_NCACTIVATE:
    close_window = ws->mode == fullscreen && LOWORD (wParam) == WA_INACTIVE;
    call_def_window_proc = true;
    break;

  case WM_SYSCOMMAND:
    call_def_window_proc = ! (ws->mode == fullscreen && wParam == SC_SCREENSAVE);
    break;

  case WM_DESTROY:
    ::wglMakeCurrent (NULL, NULL);
    //::wglDeleteContext (ws->hglrc);
    ::PostQuitMessage (0);
    break;

  default:
    call_def_window_proc = true;
    break;
  }

  if (close_window) {
    ::PostMessage (hwnd, WM_CLOSE, 0, 0);
  }

  if (call_def_window_proc) {
    result = ::DefWindowProc (hwnd, msg, wParam, lParam);
  }

  return result;
}

// Set up a proper pixel format and rendering context for the main window.
HGLRC setup_opengl_context (HWND hwnd)
{
  const int pf_attribs [] = {
    WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
    WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
    WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
    WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
    WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
    WGL_COLOR_BITS_ARB, 32,
    WGL_DEPTH_BITS_ARB, 4,
    WGL_SAMPLE_BUFFERS_ARB, GL_FALSE,
    //WGL_SAMPLES_ARB, 5,
    0, 0,
  };

  const int context_attribs [] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
    WGL_CONTEXT_MINOR_VERSION_ARB, 2,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0, 0,
  };

  HGLRC hglrc = NULL;
  int pf;
  UINT pfcount;
  if (HDC hdc = ::GetDC (hwnd)) {
    if (wglChoosePixelFormatARB (hdc, pf_attribs, NULL, 1, & pf, & pfcount)) {
      if (::SetPixelFormat (hdc, pf, NULL)) {
        hglrc = wglCreateContextAttribsARB (hdc, NULL, context_attribs);
        if (hglrc) {
          ::wglMakeCurrent (hdc, hglrc);
        }
      }
    }
    ::ReleaseDC (hwnd, hdc);
  }
  return hglrc;
}

// Tiny startup.

// No standard handles, window placement, environment variables,
// command-line transformation, global constructors and destructors,
// atexit functions, stack realignment, thread-local storage,
// runtime relocation fixups, 387 floating-point initialization,
// signal handlers or exceptions.

extern "C"
{
  // This symbol is provided by all recent GCC or MSVC linkers.
  extern IMAGE_DOS_HEADER __ImageBase;

  // This must be specified in the link command line, "-Wl,-ecustom_startup".
  extern void custom_startup ()
  {
    HINSTANCE hInstance = reinterpret_cast <HINSTANCE> (& __ImageBase);
    int status = custom_main (hInstance);
    ::ExitProcess (static_cast <UINT> (status));
  }
}
<commit_msg>main.cpp: comment fix<commit_after>#include "compiler.h"
#include "mswin.h"
#include "glinit.h"
#include "model.h"
#include "cmdline.h"
#include <windowsx.h>
// #include "tinyscheme-config.h"
// #include <scheme-private.h>
// #include <scheme.h>
#include <cstdint>

namespace usr {
  // Program name.
  static const TCHAR * const program_name = TEXT ("Polymorph");
  static const TCHAR * const message =
  TEXT ("And the ratios of their numbers, motions, and ")
  TEXT ("other properties, everywhere God, as far as ")
  TEXT ("necessity allowed or gave consent, has exactly ")
  TEXT ("perfected, and harmonised in due proportion.");
  // TEXT ("\n\nThis screensaver includes TinyScheme, developed by Dimitrios ")
  // TEXT ("Souflis and licensed under the Modified BSD License. ")
  // TEXT ("See \"tinyscheme/COPYING.txt\" for details.");
}

inline std::uint64_t qpc ()
{
  LARGE_INTEGER t;
  ::QueryPerformanceCounter (& t);
  return t.QuadPart;
}

struct window_struct_t
{
  model_t model;
  POINT initial_cursor_position;
  run_mode_t mode;
};

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HGLRC setup_opengl_context (HWND hwnd);

// Called by custom_entry_point (below).
int custom_main (HINSTANCE hInstance)
{
  // Read command line arguments.

  HWND parent = NULL;
  run_mode_t mode = parse_command_line (::GetCommandLine (), & parent);

  if (mode == configure) {
    ::MessageBox (NULL, usr::message, usr::program_name, MB_OK | MB_ICONASTERISK);
    return 0;
  }

  // Placement and window style of the main window.

  RECT rect;
  DWORD style;
  DWORD ex_style  = 0;

  if (mode == embedded) {
    style = WS_CHILD | WS_VISIBLE;
    ::GetClientRect (parent, & rect); // 0, 0, width, height
  }
  else {
    style = WS_POPUP | WS_VISIBLE;
    if (mode == fullscreen) ex_style = WS_EX_TOPMOST;
    rect.left =   ::GetSystemMetrics (SM_XVIRTUALSCREEN);
    rect.top =    ::GetSystemMetrics (SM_YVIRTUALSCREEN);
    rect.right =  ::GetSystemMetrics (SM_CXVIRTUALSCREEN); // actually width, not right
    rect.bottom = ::GetSystemMetrics (SM_CYVIRTUALSCREEN); // actually height, not bottom
  }

  window_struct_t ws ALIGNED16;
  ws.mode = mode;

  // Create a window with an OpenGL rendering context.

  // To obtain a proper OpenGL pixel format, we need to call wglChoosePixelFormatARB, but
  // first we must obtain the address of that function by calling using wglGetProcAddress,
  // which requires that an OpenGL rendering context is current, which requires a device
  // context that supports OpenGL, which requires a window with an OpenGL pixel format.

  // Bootstrap the process with a legacy OpenGL pixel format. According to MSDN,
  // "Once a window's pixel format is set, it cannot be changed", so the window
  // and associated resources are of no further use and are destroyed here.

  // Create the dummy window. See InitWndProc.
  // Note this window does not survive creation.
  WNDCLASS init_wc;
  ::ZeroMemory (& init_wc, sizeof init_wc);
  init_wc.hInstance = hInstance;
  init_wc.lpfnWndProc = & InitWndProc;
  init_wc.lpszClassName = TEXT ("GLinit");
  ATOM init_wc_atom = ::RegisterClass (& init_wc);
  ::CreateWindowEx (0, MAKEINTATOM (init_wc_atom), TEXT (""), 0,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, hInstance, NULL);
  ::UnregisterClass (MAKEINTATOM (init_wc_atom), hInstance);

  // Exit if we failed to get the function pointers.
  if (! wglChoosePixelFormatARB) return -1;

  // Create the main window. See MainWndProc.
  WNDCLASS main_wc;
  ::ZeroMemory (& main_wc, sizeof main_wc);
  main_wc.hInstance = hInstance;
  main_wc.lpfnWndProc = & MainWndProc;
  main_wc.hIcon = ::LoadIcon (hInstance, MAKEINTRESOURCE (257));
  main_wc.lpszClassName = usr::program_name;
  ATOM main_wc_atom = ::RegisterClass (& main_wc);
  HWND hwnd = ::CreateWindowEx (ex_style, MAKEINTATOM (main_wc_atom), usr::program_name, style,
                                rect.left, rect.top, rect.right, rect.bottom,
                                parent, NULL, hInstance, & ws);

  // Exit if we failed to create the window.
  if (! hwnd) return 1;

  // Enter the main loop.
  MSG msg;
  while (::GetMessage (& msg, NULL, 0, 0)) {
    ::TranslateMessage (& msg);
    ::DispatchMessage (& msg);
  }

  ::UnregisterClass (MAKEINTATOM (main_wc_atom), hInstance);
  return msg.wParam;
}

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_NCCREATE) {
    // Set up legacy rendering context to get OpenGL function pointers.
    PIXELFORMATDESCRIPTOR pfd;
    ::ZeroMemory (& pfd, sizeof pfd);
    pfd.nSize = sizeof pfd;
    pfd.dwFlags = PFD_SUPPORT_OPENGL;
    if (HDC hdc = ::GetDC (hwnd)) {
      int pf = ::ChoosePixelFormat (hdc, & pfd);
      ::SetPixelFormat (hdc, pf, & pfd);
      if (HGLRC hglrc = ::wglCreateContext (hdc)) {
        ::wglMakeCurrent (hdc, hglrc);
        // Get the function pointers.
        get_glprocs ();
        ::wglMakeCurrent (NULL, NULL);
        ::wglDeleteContext (hglrc);
      }
      ::ReleaseDC (hwnd, hdc);
    }
    return FALSE; // Abort window creation.
  }
  else {
    return ::DefWindowProc (hwnd, msg, wParam, lParam);
  }
}

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  LRESULT result = 0;
  bool call_def_window_proc = false, close_window = false;

  // Retrieve the window-struct pointer from the window userdata.
  window_struct_t * ws = reinterpret_cast <window_struct_t *> (::GetWindowLongPtr (hwnd, GWLP_USERDATA));

  switch (msg) {
  case WM_CREATE: {
    result = -1; // Abort window creation.

    // Stash the window-struct pointer in the window userdata.
    CREATESTRUCT * cs = reinterpret_cast <CREATESTRUCT *> (lParam);
    ws = reinterpret_cast <window_struct_t *> (cs->lpCreateParams);
    ::SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast <LONG_PTR> (ws));

    // Remember initial mouse-pointer position to detect mouse movement.
    ::GetCursorPos (& ws->initial_cursor_position);

    // Set up OpenGL rendering context.
    HGLRC hglrc = setup_opengl_context (hwnd);
    if (hglrc) {
      ws->model.initialize (qpc (), cs->cx, cs->cy);
      ::PostMessage (hwnd, WM_APP, 0, 0);  // Start the simulation.
      result = 0;                          // Allow window creation to continue.
    }
    break;
  }

  case WM_APP: {
    ws->model.draw_next ();
    ::InvalidateRect (hwnd, NULL, FALSE);
    break;
  }

  case WM_PAINT: {
    PAINTSTRUCT ps;
    ::BeginPaint (hwnd, & ps);
    ::SwapBuffers (ps.hdc);
    ::EndPaint (hwnd, & ps);
    ::PostMessage (hwnd, WM_APP, 0, 0);
    break;
  }

  case WM_SETCURSOR:
    ::SetCursor (ws->mode == fullscreen ? NULL : (::LoadCursor (NULL, IDC_ARROW)));
    break;

  case WM_MOUSEMOVE:
    if (ws->mode == fullscreen) {
      // Compare the current mouse position with the one stored in the window struct.
      POINT current = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
      ::ClientToScreen (hwnd, & current);
      SHORT dx = current.x - ws->initial_cursor_position.x;
      SHORT dy = current.y - ws->initial_cursor_position.y;
      close_window = dx > 10 || dy > 10 || dx * dx + dy * dy  > 100;
    }
    break;

  case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN:
    close_window = ws->mode == fullscreen || ws->mode == special;
    break;

  case WM_ACTIVATE: case WM_ACTIVATEAPP: case WM_NCACTIVATE:
    close_window = ws->mode == fullscreen && LOWORD (wParam) == WA_INACTIVE;
    call_def_window_proc = true;
    break;

  case WM_SYSCOMMAND:
    call_def_window_proc = ! (ws->mode == fullscreen && wParam == SC_SCREENSAVE);
    break;

  case WM_DESTROY:
    ::wglMakeCurrent (NULL, NULL);
    //::wglDeleteContext (ws->hglrc);
    ::PostQuitMessage (0);
    break;

  default:
    call_def_window_proc = true;
    break;
  }

  if (close_window) {
    ::PostMessage (hwnd, WM_CLOSE, 0, 0);
  }

  if (call_def_window_proc) {
    result = ::DefWindowProc (hwnd, msg, wParam, lParam);
  }

  return result;
}

// Set up a proper pixel format and rendering context for the main window.
HGLRC setup_opengl_context (HWND hwnd)
{
  const int pf_attribs [] = {
    WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
    WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
    WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
    WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
    WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
    WGL_COLOR_BITS_ARB, 32,
    WGL_DEPTH_BITS_ARB, 4,
    WGL_SAMPLE_BUFFERS_ARB, GL_FALSE,
    //WGL_SAMPLES_ARB, 5,
    0, 0,
  };

  const int context_attribs [] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
    WGL_CONTEXT_MINOR_VERSION_ARB, 2,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0, 0,
  };

  HGLRC hglrc = NULL;
  int pf;
  UINT pfcount;
  if (HDC hdc = ::GetDC (hwnd)) {
    if (wglChoosePixelFormatARB (hdc, pf_attribs, NULL, 1, & pf, & pfcount)) {
      if (::SetPixelFormat (hdc, pf, NULL)) {
        hglrc = wglCreateContextAttribsARB (hdc, NULL, context_attribs);
        if (hglrc) {
          ::wglMakeCurrent (hdc, hglrc);
        }
      }
    }
    ::ReleaseDC (hwnd, hdc);
  }
  return hglrc;
}

// Tiny startup.

// No standard handles, window placement, environment variables,
// command-line transformation, global constructors and destructors,
// atexit functions, stack realignment, thread-local storage,
// runtime relocation fixups, 387 floating-point initialization,
// signal handlers or exceptions.

extern "C"
{
  // This symbol is provided by all recent GCC and MSVC linkers.
  extern IMAGE_DOS_HEADER __ImageBase;

  // This entry point must be specified in the linker command line.
  extern void custom_startup ()
  {
    HINSTANCE hInstance = reinterpret_cast <HINSTANCE> (& __ImageBase);
    int status = custom_main (hInstance);
    ::ExitProcess (static_cast <UINT> (status));
  }
}
<|endoftext|>


<commit_before>#include "S3StreamDefaults.h"
#include <ossim/base/ossimPreferences.h>
#include <ossim/base/ossimEnvironmentUtility.h>

// defaults to a 1 megabyte block size
//
ossim_int64 ossim::S3StreamDefaults::m_readBlocksize = 32768;
ossim_int64 ossim::S3StreamDefaults::m_nReadCacheHeaders = 10000;

void ossim::S3StreamDefaults::loadDefaults()
{
   ossimString s3ReadBlocksize = ossimEnvironmentUtility::instance()->getEnvironmentVariable("OSSIM_PLUGINS_AWS_S3_READBLOCKSIZE");

   ossimString  nReadCacheHeaders = ossimPreferences::instance()->findPreference("OSSIM_PLUGINS_AWS_S3_NREADCACHEHEADERS");

   if(s3ReadBlocksize.empty())
   {
       s3ReadBlocksize = ossimPreferences::instance()->findPreference("ossim.plugins.aws.s3.readBlocksize");
   }
   if(!s3ReadBlocksize.empty())
   {
     ossim_int64 blockSize = s3ReadBlocksize.toInt64();
     if(blockSize > 0)
     {
         ossimString byteType(s3ReadBlocksize.begin()+(s3ReadBlocksize.size()-1), s3ReadBlocksize.end());
         byteType.upcase();
         m_readBlocksize = blockSize;
         if ( byteType == "K")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1024);
         }
         else if ( byteType == "M")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1048576);
         }
         else if ( byteType == "G")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1073741824);
         }
     }
   }
   if(nReadCacheHeaders.empty())
   {
     nReadCacheHeaders = ossimPreferences::instance()->findPreference("ossim.plugins.aws.s3.nReadCacheHeaders");
   }
   if(!nReadCacheHeaders.empty())
   {
      m_nReadCacheHeaders =  nReadCacheHeaders.toInt64();
      if(m_nReadCacheHeaders < 0)
      {
        m_nReadCacheHeaders = 10000;
      }
   }
}
<commit_msg>Added debug to the defaults<commit_after>#include "S3StreamDefaults.h"
#include <ossim/base/ossimPreferences.h>
#include <ossim/base/ossimEnvironmentUtility.h>
#include <ossim/base/ossimTrace.h>

// defaults to a 1 megabyte block size
//
ossim_int64 ossim::S3StreamDefaults::m_readBlocksize = 32768;
ossim_int64 ossim::S3StreamDefaults::m_nReadCacheHeaders = 10000;
static ossimTrace traceDebug("ossimS3StreamDefaults:debug");

void ossim::S3StreamDefaults::loadDefaults()
{
   if(traceDebug())
   {
      ossimNotify(ossimNotifyLevel_DEBUG)
         << "ossim::S3StreamDefaults::loadDefaults() DEBUG: entered.....\n";
   }
   ossimString s3ReadBlocksize = ossimEnvironmentUtility::instance()->getEnvironmentVariable("OSSIM_PLUGINS_AWS_S3_READBLOCKSIZE");

   ossimString  nReadCacheHeaders = ossimPreferences::instance()->findPreference("OSSIM_PLUGINS_AWS_S3_NREADCACHEHEADERS");

   if(s3ReadBlocksize.empty())
   {
       s3ReadBlocksize = ossimPreferences::instance()->findPreference("ossim.plugins.aws.s3.readBlocksize");
   }
   if(!s3ReadBlocksize.empty())
   {
     ossim_int64 blockSize = s3ReadBlocksize.toInt64();
     if(blockSize > 0)
     {
         ossimString byteType(s3ReadBlocksize.begin()+(s3ReadBlocksize.size()-1), s3ReadBlocksize.end());
         byteType.upcase();
         m_readBlocksize = blockSize;
         if ( byteType == "K")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1024);
         }
         else if ( byteType == "M")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1048576);
         }
         else if ( byteType == "G")
         {
            m_readBlocksize *=static_cast<ossim_int64>(1073741824);
         }
     }
   }
   if(nReadCacheHeaders.empty())
   {
     nReadCacheHeaders = ossimPreferences::instance()->findPreference("ossim.plugins.aws.s3.nReadCacheHeaders");
   }
   if(!nReadCacheHeaders.empty())
   {
      m_nReadCacheHeaders =  nReadCacheHeaders.toInt64();
      if(m_nReadCacheHeaders < 0)
      {
        m_nReadCacheHeaders = 10000;
      }
   }
   if(traceDebug())
   {
      ossimNotify(ossimNotifyLevel_DEBUG)
         << "m_readBlocksize: " << m_readBlocksize << "\n";
      ossimNotify(ossimNotifyLevel_DEBUG)
         << "m_nReadCacheHeaders: " << m_nReadCacheHeaders << "\n";
      ossimNotify(ossimNotifyLevel_DEBUG)
         << "ossim::S3StreamDefaults::loadDefaults() DEBUG: leaving.....\n";
   }
}
<|endoftext|>


<commit_before>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking

int server_socket = 0;

void termination_handler (int signum){
  if (server_socket == 0) return;
  close(server_socket);
  server_socket = 0;
}

int main(int argc, char ** argv){
  //setup signal handler
  struct sigaction new_action;
  new_action.sa_handler = termination_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = 0;
  sigaction (SIGINT, &new_action, NULL);
  sigaction (SIGHUP, &new_action, NULL);
  sigaction (SIGTERM, &new_action, NULL);

  server_socket = DDV_Listen(1935);
  if ((argc < 2) || (argv[1] == "nd")){
    if (server_socket > 0){daemon(1, 0);}else{return 1;}
  }
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    if (CONN_fd > 0){
      pid_t myid = fork();
      if (myid == 0){
        break;
      }else{
        printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
      }
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  int ss;
  FLV_Pack * tag;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if (!ready4data || (snd_cnt - snd_window_at >= snd_window_size)){
      if (DDV_ready(CONN_fd)){
        parseChunk();
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname.c_str());
        if (ss <= 0){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        #ifdef DEBUG
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(tag, ss)){//able to read a full packet?
          ts = tag->data[7] * 256*256*256;
          ts += tag->data[4] * 256*256;
          ts += tag->data[5] * 256;
          ts += tag->data[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            tag->data[7] = ts / (256*256*256);
            tag->data[4] = ts / (256*256);
            tag->data[5] = ts / 256;
            tag->data[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            tag->data[7] = ftst / (256*256*256);
            tag->data[4] = ftst / (256*256);
            tag->data[5] = ftst / 256;
            tag->data[6] = ftst % 256;
          }
          SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
          #endif
        }
      }
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  //#ifdef DEBUG
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  //#endif
  return 0;
}//main
<commit_msg>DDVSocket edits<commit_after>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking

int server_socket = 0;

void termination_handler (int signum){
  if (server_socket == 0) return;
  close(server_socket);
  server_socket = 0;
}

int main(int argc, char ** argv){
  //setup signal handler
  struct sigaction new_action;
  new_action.sa_handler = termination_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = 0;
  sigaction (SIGINT, &new_action, NULL);
  sigaction (SIGHUP, &new_action, NULL);
  sigaction (SIGTERM, &new_action, NULL);

  server_socket = DDV_Listen(1935);
  if ((argc < 2) || (argv[1] == "nd")){
    if (server_socket > 0){daemon(1, 0);}else{return 1;}
  }
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    if (CONN_fd > 0){
      pid_t myid = fork();
      if (myid == 0){
        break;
      }else{
        printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
      }
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  int ss;
  FLV_Pack * tag;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if (!ready4data || (snd_cnt - snd_window_at >= snd_window_size)){
      if (DDV_ready(CONN_fd)){
        parseChunk();
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname.c_str());
        if (ss <= 0){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        #ifdef DEBUG
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      //if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(tag, ss)){//able to read a full packet?
          ts = tag->data[7] * 256*256*256;
          ts += tag->data[4] * 256*256;
          ts += tag->data[5] * 256;
          ts += tag->data[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            tag->data[7] = ts / (256*256*256);
            tag->data[4] = ts / (256*256);
            tag->data[5] = ts / 256;
            tag->data[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            tag->data[7] = ftst / (256*256*256);
            tag->data[4] = ftst / (256*256);
            tag->data[5] = ftst / 256;
            tag->data[6] = ftst % 256;
          }
          SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
          #endif
        }
      //}
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  //#ifdef DEBUG
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  //#endif
  return 0;
}//main
<|endoftext|>


<commit_before>#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include <regex.h>
#include <sys/time.h>
#include <termios.h>

// http://stackoverflow.com/questions/1413445/read-a-password-from-stdcin
void setStdinEcho(bool enable = true) {
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    if( !enable )
        tty.c_lflag &= ~ECHO;
    else
        tty.c_lflag |= ECHO;

    (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
}

void readQuestions(std::ifstream& questionFile, std::vector<std::string>& questions) {
  int rv;
  regex_t * exp = new regex_t;
  rv = regcomp(exp, "^//.*", REG_EXTENDED);
  if (rv != 0) {
    std::cout << "regcomp failed with " << rv << std::endl;
  }
  while(questionFile) {
    std::string line;
    std::getline(questionFile, line);
    if (line.length() > 1 && regexec(exp, line.c_str(), 0, NULL, 0) == REG_NOMATCH)
      questions.push_back(line);
  }
  std::sort(questions.begin(), questions.end());
  regfree(exp);
}

unsigned int getRnd(void) {
  int urandom = open("/dev/urandom", O_RDONLY);
  assert(urandom);
  unsigned int rndNumber;
  read(urandom, &rndNumber, sizeof(unsigned int));
  close(urandom);
  return rndNumber;
}

void usage(void) {
    std::cout << "usage: ./question filename" << std::endl;
}

int main(int argc, char ** argv) {
  if (argc != 2) {
      usage();
      return EXIT_FAILURE;
  }

  std::string filename(argv[1]);
  std::vector<std::string> * questions = new std::vector<std::string>;

  std::ifstream questionFile(filename.c_str());
  if (questionFile.good()) {
      readQuestions(questionFile, *questions);
  }
  else {
      std::cerr << "Can't open given file " << filename << std::endl;
      return EXIT_FAILURE;
  }
  questionFile.close();

  std::vector<std::string> * todo = new std::vector<std::string>(*questions);
  std::vector<std::string> * done = new std::vector<std::string>;

  std::string question;
  timeval * starttime = new timeval;
  timeval * endtime = new timeval;
  while(true) {
    int id = getRnd() % todo->size();
    question = (*todo)[id];
    todo->erase(std::find(todo->begin(), todo->end(), question));
    done->push_back(question);

    std::cout << question << std::endl;
    gettimeofday(starttime, NULL);

    if (todo->empty())
      std::swap(todo, done);

    setStdinEcho(false);
    std::cin.get();
    setStdinEcho(true);
    gettimeofday(endtime, NULL);
    double elapsed_time = static_cast<double>(endtime->tv_sec) + static_cast<double>(endtime->tv_usec) * 1E-6;
    elapsed_time -= static_cast<double>(starttime->tv_sec) + static_cast<double>(starttime->tv_usec) * 1E-6;
    std::cout <<  elapsed_time << " seconds for answer!" << std::endl;
  }

  delete starttime;
  delete endtime;
  delete todo;
  delete done;

  return EXIT_SUCCESS;
}
<commit_msg>added completion notification<commit_after>#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include <regex.h>
#include <sys/time.h>
#include <termios.h>

// http://stackoverflow.com/questions/1413445/read-a-password-from-stdcin
void setStdinEcho(bool enable = true) {
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    if( !enable )
        tty.c_lflag &= ~ECHO;
    else
        tty.c_lflag |= ECHO;

    (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
}

void readQuestions(std::ifstream& questionFile, std::vector<std::string>& questions) {
  int rv;
  regex_t * exp = new regex_t;
  rv = regcomp(exp, "^//.*", REG_EXTENDED);
  if (rv != 0) {
    std::cout << "regcomp failed with " << rv << std::endl;
  }
  while(questionFile) {
    std::string line;
    std::getline(questionFile, line);
    if (line.length() > 1 && regexec(exp, line.c_str(), 0, NULL, 0) == REG_NOMATCH)
      questions.push_back(line);
  }
  std::sort(questions.begin(), questions.end());
  regfree(exp);
}

unsigned int getRnd(void) {
  int urandom = open("/dev/urandom", O_RDONLY);
  assert(urandom);
  unsigned int rndNumber;
  read(urandom, &rndNumber, sizeof(unsigned int));
  close(urandom);
  return rndNumber;
}

void usage(void) {
    std::cout << "usage: ./question filename" << std::endl;
}

int main(int argc, char ** argv) {
  if (argc != 2) {
      usage();
      return EXIT_FAILURE;
  }

  std::string filename(argv[1]);
  std::vector<std::string> * questions = new std::vector<std::string>;

  std::ifstream questionFile(filename.c_str());
  if (questionFile.good()) {
      readQuestions(questionFile, *questions);
  }
  else {
      std::cerr << "Can't open given file " << filename << std::endl;
      return EXIT_FAILURE;
  }
  questionFile.close();

  std::vector<std::string> * todo = new std::vector<std::string>(*questions);
  std::vector<std::string> * done = new std::vector<std::string>;

  std::string question;
  timeval * starttime = new timeval;
  timeval * endtime = new timeval;
  while(true) {
    int id = getRnd() % todo->size();
    question = (*todo)[id];
    todo->erase(std::find(todo->begin(), todo->end(), question));
    done->push_back(question);

    std::cout << question << std::endl;
    gettimeofday(starttime, NULL);

        setStdinEcho(false);
    std::cin.get();
    setStdinEcho(true);
    gettimeofday(endtime, NULL);
    double elapsed_time = static_cast<double>(endtime->tv_sec) + static_cast<double>(endtime->tv_usec) * 1E-6;
    elapsed_time -= static_cast<double>(starttime->tv_sec) + static_cast<double>(starttime->tv_usec) * 1E-6;
    std::cout <<  elapsed_time << " seconds for answer!" << std::endl;
    if (todo->empty()) {
        std::swap(todo, done);
        std::cout << "### Complete, starting again. ###" << std::endl;
    }
  }

  delete starttime;
  delete endtime;
  delete todo;
  delete done;

  return EXIT_SUCCESS;
}
<|endoftext|>