<commit_before>#include "lexer.hpp"

#include <cctype>
#include <algorithm>
#include <vector>

namespace klang {

Token::Token()
  : type_(TokenType::UNKNOWN), str_(), line_(-1)
{}

Token::Token(TokenType type, const std::string& str, int line)
  : type_(type), str_(str), line_(line)
{}

TokenType Token::type() const { return type_; }
std::string Token::str() const { return str_; }
int Token::line() const { return line_; }

bool alphabet(char c) {
  return std::isalpha(c);
}

bool alphabet_or_bar(char c) {
  return (c == '_' || alphabet(c));
}

bool nonzero_digit(char c) {
  return (c >= '1' && c <= '9');
}

bool decimal_digit(char c) {
  return std::isdigit(c);
}

bool identifier(const std::string& str) {
  if (str.empty() || !alphabet_or_bar(str.front())) {
    return false;
  }
  for (char c : str) {
    if (!alphabet_or_bar(c) && !decimal_digit(c)) {
      return false;
    }
  }
  return true;
}

bool decimal_integer(const std::string& str) {
  if (str == "0") return true;
  if (str.empty() || !nonzero_digit(str.front())) {
    return false;
  }
  for (char c : str) {
    if (!decimal_digit(c)) {
      return false;
    }
  }
  return true;
}

bool symbol(const std::string& str) {
  using std::begin;
  using std::end;
  static std::vector<std::string> const symbol_list = {
    "~", "+", "-", "*", "/", "%",
    ":=", ":+=", ":-=", ":*=", ":/=", ":%=",
    "=", "=/", "<", ">", "<=", ">=",
    ";", "(", ")", "{", "}", "->",
    "and", "or", "not", "int", "def", "var",
    "if", "else", "while", "for", "break", "continue", "return"
  };
  return (std::find(begin(symbol_list), end(symbol_list), str) != end(symbol_list));
}

bool ignore(const std::string& str) {
  return (str == " " || str == "\n");
}

TokenType match_type(std::string const& str) {
  if (symbol(str)) return TokenType::SYMBOL;
  if (identifier(str)) return TokenType::IDENTIFIER;
  if (decimal_integer(str)) return TokenType::NUMBER;
  if (ignore(str)) return TokenType::IGNORE;
  return TokenType::UNKNOWN;
}

TokenVector tokenize(std::istream& is) {
  std::string str, code;
  while (std::getline(is, str)) {
    code += str + '\n';
  }
  TokenVector tokens;
  str.clear();
  TokenType prev = TokenType::UNKNOWN;
  int line = 0;
  for (char c : code) {
    if (c == '\n') ++line;
    TokenType next = match_type(str + c);
    if (prev != TokenType::UNKNOWN && next == TokenType::UNKNOWN) {
      if (prev != TokenType::IGNORE) {
        tokens.push_back(Token(prev, str, line));
      }
      str = c;
      prev = match_type(str);
    } else {
      str += c;
      prev = next;
    }
  }
  return tokens;
}

}  // namespace klang
<commit_msg>Add COMMENT and STRING<commit_after>#include "lexer.hpp"

#include <cctype>
#include <algorithm>
#include <vector>

namespace klang {

Token::Token()
  : type_(TokenType::UNKNOWN), str_(), line_(-1)
{}

Token::Token(TokenType type, const std::string& str, int line)
  : type_(type), str_(str), line_(line)
{}

TokenType Token::type() const { return type_; }
std::string Token::str() const { return str_; }
int Token::line() const { return line_; }

bool alphabet(char c) {
  return std::isalpha(c);
}

bool alphabet_or_bar(char c) {
  return (c == '_' || alphabet(c));
}

bool nonzero_digit(char c) {
  return (c >= '1' && c <= '9');
}

bool decimal_digit(char c) {
  return std::isdigit(c);
}

bool identifier(const std::string& str) {
  if (str.empty() || !alphabet_or_bar(str.front())) {
    return false;
  }
  for (char c : str) {
    if (!alphabet_or_bar(c) && !decimal_digit(c)) {
      return false;
    }
  }
  return true;
}

bool decimal_integer(const std::string& str) {
  if (str == "0") return true;
  if (str.empty() || !nonzero_digit(str.front())) {
    return false;
  }
  for (char c : str) {
    if (!decimal_digit(c)) {
      return false;
    }
  }
  return true;
}

bool symbol(const std::string& str) {
  using std::begin;
  using std::end;
  static std::vector<std::string> const symbol_list = {
    "~", "+", "-", "*", "/", "%",
    ":=", ":+=", ":-=", ":*=", ":/=", ":%=",
    "=", "=/", "<", ">", "<=", ">=",
    ";", "(", ")", "{", "}", "->", "~}",
    "and", "or", "not", "int", "def", "var",
    "if", "else", "while", "for", "break", "continue", "return"
  };
  return (std::find(begin(symbol_list), end(symbol_list), str) != end(symbol_list));
}

bool ignore(const std::string& str) {
  return (str == " " || str == "\n");
}

bool singleline_comment(const std::string& str) {
  bool inside = (str.back() == '\n' || str.find("\n") == std::string::npos);
  return (str.compare(0, 2, "~~") == 0 && inside);
}

bool multiline_comment(const std::string& str) {
  using std::begin;
  using std::end;
  if (str.compare(0, 2, "{~") == 0) {
	int nest = 0;
	for (auto it = begin(str); it + 1 != end(str); ++it) {
	  std::string tk(it, it+2);
	  if (tk == "{~") {
		++nest;
	  } else if(tk == "~}") {
		--nest;
	  }
	}
	bool closed = (nest == 0 && str.compare(str.size()-2, 2, "~}") == 0);
	return (nest > 0 || closed);
  }
  return false;
}

bool comment(const std::string& str) {
  return (singleline_comment(str) || multiline_comment(str));
}

bool string_token(const std::string& str) {
  using std::begin;
  using std::end;
  if (str.front() == '"') {
	bool escaped = false;
	for(auto it = begin(str) + 1; it != end(str); ++it) {
	  if (*it == '\\') {
		escaped = true;
	  } else if (*it == '"' && (!escaped)) {
		return it + 1 == end(str);
	  } else {
		escaped = false;
	  }
	}
  }
  return false;
}

TokenType match_type(std::string const& str) {
  if (comment(str)) return TokenType::IGNORE;
  if (symbol(str)) return TokenType::SYMBOL;
  if (identifier(str)) return TokenType::IDENTIFIER;
  if (decimal_integer(str)) return TokenType::NUMBER;
  if (string_token(str)) return TokenType::STRING;
  if (ignore(str)) return TokenType::IGNORE;
  return TokenType::UNKNOWN;
}

TokenVector tokenize(std::istream& is) {
  std::string str, code;
  while (std::getline(is, str)) {
    code += str + '\n';
  }
  TokenVector tokens;
  str.clear();
  TokenType prev = TokenType::UNKNOWN;
  int line = 0;
  for (char c : code) {
    if (c == '\n') ++line;
    TokenType next = match_type(str + c);
    if (prev != TokenType::UNKNOWN && next == TokenType::UNKNOWN) {
      if (prev != TokenType::IGNORE) {
        tokens.push_back(Token(prev, str, line));
      }
      str = c;
      prev = match_type(str);
    } else {
      str += c;
      prev = next;
    }
  }
  return tokens;
}

}  // namespace klang
<|endoftext|>


<commit_before>/*
Project: TUC
File: lexer.cpp
Author: Leonardo Banderali
Created: November 8, 2015
Last Modified: November 8, 2015

Description:
    TUC is a simple, experimental compiler designed for learning and experimenting.
    It is not intended to have any useful purpose other than being a way to learn
    how compilers work.

Copyright (C) 2015 Leonardo Banderali

License:

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 "lexer.hpp"

// standard libraries
#include <regex>
//#include <fstream>
#include <utility>

/*
analyze an input file and returns its contents as a list of tokens
*/
std::vector<tuc::Token> tuc::lex_analyze(const std::string& filePath) {
    auto inputFile = std::ifstream{filePath};
    std::stringbuf sb;
    inputFile.get(sb, static_cast<char>(-1)); // read the entire file
    inputFile.close();

    const auto fileText = sb.str();
    auto first = fileText.cbegin();
    auto last = fileText.cend();
    auto currentPosition = first;
    std::vector<tuc::Token> tokenList;
    auto ruleListIndex = 0;
    unsigned int l = 1;
    unsigned int c = 1;

    while (currentPosition < last) {
        Rule rule;
        std::smatch firstMatch;
        std::smatch m;
        for (auto r : u_lexer_grammar[ruleListIndex]) {
            if (std::regex_search(currentPosition, last, m, r.regex()) && (firstMatch.empty() || m.position() < firstMatch.position() )) {
                firstMatch = std::move(m);
                rule = std::move(r);
            }
        }

        if (firstMatch.empty()) {
            break;
        } else {
            for (int i = firstMatch.position() - 1; i >= 0; i--) {
                auto character = *currentPosition;
                if (character == '\n') {
                    l++;
                    c = 1;
                }
                else {
                    c++;
                }
                currentPosition++;
            }
            tokenList.push_back(Token{TextEntity{firstMatch.str(), filePath, currentPosition - first, l, c}, rule});
            for (int i = firstMatch.length() - 1; i >= 0; i--) {
                auto character = *currentPosition;
                if (character == '\n') {
                    l++;
                    c = 1;
                }
                else {
                    c++;
                }
                currentPosition++;
            }
            ruleListIndex = rule.nextRules();
        }
    }

    return tokenList;
}
<commit_msg>Clean up code.<commit_after>/*
Project: TUC
File: lexer.cpp
Author: Leonardo Banderali
Created: November 8, 2015
Last Modified: January 5, 2016

Description:
    TUC is a simple, experimental compiler designed for learning and experimenting.
    It is not intended to have any useful purpose other than being a way to learn
    how compilers work.

Copyright (C) 2016 Leonardo Banderali

License:

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 "lexer.hpp"

// standard libraries
#include <regex>
//#include <fstream>
#include <utility>

/*
analyze an input file and returns its contents as a list of tokens
*/
std::vector<tuc::Token> tuc::lex_analyze(const std::string& filePath) {
    auto inputFile = std::ifstream{filePath};
    std::stringbuf sb;
    inputFile.get(sb, static_cast<char>(-1)); // read the entire file
    inputFile.close();

    const auto fileText = sb.str();
    auto first = fileText.cbegin();
    auto last = fileText.cend();
    auto currentPosition = first;
    std::vector<tuc::Token> tokenList;
    auto ruleListIndex = 0;
    unsigned int l = 1;
    unsigned int c = 1;

    /*
    move itterators forward while keeping track of changes in line and column numbers
    */
    auto move_forward_by = [&](int ammount) {
        for (int i = 0; i < ammount; i++) {
            auto character = *currentPosition;
            if (character == '\n') {
                l++;
                c = 1;
            }
            else {
                c++;
            }
            currentPosition++;
        }
    };

    while (currentPosition < last) {
        Rule rule;
        std::smatch firstMatch;
        std::smatch m;
        for (auto r : u_lexer_grammar[ruleListIndex]) {
            if (std::regex_search(currentPosition, last, m, r.regex()) && (firstMatch.empty() || m.position() < firstMatch.position() )) {
                firstMatch = std::move(m);
                rule = std::move(r);
            }
        }

        if (firstMatch.empty()) {
            break;
        } else {
            move_forward_by(firstMatch.position());
            tokenList.push_back(Token{TextEntity{firstMatch.str(), filePath, currentPosition - first, l, c}, rule});
            move_forward_by(firstMatch.length());
            ruleListIndex = rule.nextRules();
        }
    }

    return tokenList;
}
<|endoftext|>


<commit_before>// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/VirtualDirectory.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <algorithm>
#include <cassert>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_parent(std::move(parentDirectory)),
	m_isUprootAllowed(false)
	{
	}

	inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_physicalPath(std::move(physicalPath)),
	m_parent(std::move(parentDirectory)),
	m_isUprootAllowed(false)
	{
	}

	inline void VirtualDirectory::AllowUproot(bool uproot)
	{
		m_isUprootAllowed = uproot;
	}

	inline bool VirtualDirectory::Exists(std::string_view path)
	{
		return GetEntry(path, [](const auto&) {});
	}

	template<typename F>
	void VirtualDirectory::Foreach(F&& callback, bool includeDots)
	{
		if (includeDots)
		{
			Entry ourselves = DirectoryEntry{ shared_from_this() };
			callback(std::string_view("."), ourselves);
			if (VirtualDirectoryPtr parent = m_parent.lock())
			{
				Entry parentEntry = DirectoryEntry{ parent };
				if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
					return;
			}
			else if (!CallbackReturn(callback, std::string_view(".."), ourselves))
					return;
		}

		for (auto&& entry : m_content)
		{
			if (!CallbackReturn(callback, std::string_view(entry.name), std::as_const(entry.entry)))
				return;
		}

		if (m_physicalPath)
		{
			for (auto&& physicalEntry : std::filesystem::directory_iterator(*m_physicalPath))
			{
				std::string filename = physicalEntry.path().filename().generic_u8string();

				// Check if physical file/directory has been overridden by a virtual one
				auto it = std::lower_bound(m_content.begin(), m_content.end(), filename, [](const ContentEntry& entry, std::string_view name)
				{
					return entry.name < name;
				});
				if (it != m_content.end() && it->name == filename)
					continue;

				std::filesystem::file_status status = physicalEntry.status();

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ physicalEntry.path() };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ physicalEntry.path() };
				else
					continue;

				if (!CallbackReturn(callback, std::string_view(filename), entry))
					return;
			}
		}
	}

	template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
	{
		assert(!path.empty());

		VirtualDirectoryPtr currentDir = shared_from_this();
		std::optional<std::filesystem::path> physicalPathBase;
		std::vector<std::string> physicalDirectoryParts;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			if (physicalPathBase)
			{
				// Special case when traversing directory
				if (dirName == ".." && !m_isUprootAllowed)
				{
					// Don't allow to escape virtual directory
					if (!physicalDirectoryParts.empty())
						physicalDirectoryParts.pop_back();
					else
						physicalPathBase.reset();
				}
				else if (dirName != ".")
					physicalDirectoryParts.emplace_back(dirName);

				return true;
			}

			return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
				{
					currentDir = dirEntry->directory;
					return true;
				}
				else if (auto physDirEntry = std::get_if<PhysicalDirectoryEntry>(&entry))
				{
					assert(!physicalPathBase);

					// We're traversing a physical directory
					physicalPathBase = physDirEntry->filePath;
					return true;
				}

				return false;
			});
		},
		[&](std::string_view name)
		{
			if (physicalPathBase)
			{
				std::filesystem::path filePath = *physicalPathBase;
				for (const auto& part : physicalDirectoryParts)
					filePath /= part;

				filePath /= name;

				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}
			else
				return currentDir->GetEntryInternal(name, callback);
		});
	}

	template<typename F>
	bool VirtualDirectory::GetFileContent(std::string_view path, F&& callback)
	{
		return GetEntry(path, [&](const Entry& entry)
		{
			return std::visit([&](auto&& entry)
			{
				using T = std::decay_t<decltype(entry)>;

				using P1 = const void*;
				using P2 = std::size_t;

				if constexpr (std::is_same_v<T, DataPointerEntry>)
				{
					return CallbackReturn(callback, static_cast<P1>(entry.data), SafeCast<P2>(entry.size));
				}
				else if constexpr (std::is_same_v<T, FileContentEntry>)
				{
					return CallbackReturn(callback, static_cast<P1>(entry.data.data()), SafeCast<P2>(entry.data.size()));
				}
				else if constexpr (std::is_same_v<T, PhysicalFileEntry>)
				{
					std::optional<std::vector<UInt8>> source = File::ReadWhole(entry.filePath);
					if (!source.has_value())
						return false;

					return CallbackReturn(callback, static_cast<P1>(source->data()), SafeCast<P2>(source->size()));
				}
				else if constexpr (std::is_same_v<T, DirectoryEntry> || std::is_same_v<T, PhysicalDirectoryEntry>)
				{
					NazaraError("entry is a directory");
					return false;
				}
				else
					static_assert(AlwaysFalse<T>(), "incomplete visitor");
			}, entry);
		});
	}

	inline bool VirtualDirectory::IsUprootAllowed() const
	{
		return m_isUprootAllowed;
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DirectoryEntry{ std::move(directory) });
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalDirectoryEntry{ std::move(directoryPath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), FileContentEntry{ std::move(file) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::filesystem::path filePath) -> PhysicalFileEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), PhysicalFileEntry{ std::move(filePath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, const void* data, std::size_t size) -> DataPointerEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		return dir->StoreInternal(std::string(entryName), DataPointerEntry{ data, size });
	}

	template<typename F> bool VirtualDirectory::GetEntryInternal(std::string_view name, F&& callback)
	{
		if (name == ".")
		{
			Entry entry{ DirectoryEntry{ shared_from_this() } };
			return CallbackReturn(callback, entry);
		}

		if (name == "..")
		{
			VirtualDirectoryPtr parentEntry;
			if (VirtualDirectoryPtr parent = m_parent.lock())
				parentEntry = std::move(parent);
			else if (!m_isUprootAllowed)
				parentEntry = shared_from_this();

			if (parentEntry)
			{
				Entry entry = DirectoryEntry{ std::move(parentEntry) };
				return CallbackReturn(callback, entry);
			}
		}

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});
		if (it == m_content.end() || it->name != name)
		{
			// Virtual file not found, check if it has a physical one
			if (m_physicalPath)
			{
				std::filesystem::path filePath = *m_physicalPath / name;
				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}

			return false;
		}

		return CallbackReturn(callback, it->entry);
	}

	inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
{
		directory = shared_from_this();

		bool allowCreation = true;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
					directory = dirEntry->directory;
				else
					allowCreation = false; //< does exist but is not a directory
			});

			if (dirFound)
				return true;

			// Try to create a new directory
			if (!allowCreation)
				return false;

			auto newDirectory = std::make_shared<VirtualDirectory>(directory);
			directory->StoreDirectory(dirName, newDirectory);

			directory = std::move(newDirectory);
			return true;
		},
		[&](std::string_view name)
		{
			if (name.empty())
				return false;

			entryName = name;
			return true;
		});
	}

	template<typename T>
	T& VirtualDirectory::StoreInternal(std::string name, T value)
	{
		assert(!name.empty());

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});

		ContentEntry* entryPtr;
		if (it == m_content.end() || it->name != name)
			entryPtr = &*m_content.emplace(it);
		else
			entryPtr = &*it;

		entryPtr->entry = std::move(value);
		entryPtr->name = std::move(name);

		return std::get<T>(entryPtr->entry);
	}

	template<typename F, typename... Args>
	bool VirtualDirectory::CallbackReturn(F&& callback, Args&& ...args)
	{
		using Ret = decltype(callback(std::forward<Args>(args)...));
		if constexpr (std::is_void_v<Ret>)
		{
			callback(std::forward<Args>(args)...);
			return true;
		}
		else
		{
			static_assert(std::is_same_v<Ret, bool>, "callback must either return a boolean or nothing");
			return callback(std::forward<Args>(args)...);
		}
	}

	template<typename F1, typename F2>
	bool VirtualDirectory::SplitPath(std::string_view path, F1&& dirCB, F2&& lastCB)
	{
		std::string_view nextPart;
		auto HandlePart = [&](std::string_view part)
		{
			if (part.empty())
				return true; //< "a//b" == "a/b"

			if (!nextPart.empty() && !CallbackReturn(dirCB, nextPart))
				return false;

			nextPart = part;
			return true;
		};

		return SplitStringAny(path, R"(\/:)", HandlePart) && CallbackReturn(lastCB, nextPart);
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Core/VirtualDirectory: Prevent storing . and .. entries<commit_after>// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/VirtualDirectory.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <algorithm>
#include <cassert>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	inline VirtualDirectory::VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_parent(std::move(parentDirectory)),
	m_isUprootAllowed(false)
	{
	}

	inline VirtualDirectory::VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory) :
	m_physicalPath(std::move(physicalPath)),
	m_parent(std::move(parentDirectory)),
	m_isUprootAllowed(false)
	{
	}

	inline void VirtualDirectory::AllowUproot(bool uproot)
	{
		m_isUprootAllowed = uproot;
	}

	inline bool VirtualDirectory::Exists(std::string_view path)
	{
		return GetEntry(path, [](const auto&) {});
	}

	template<typename F>
	void VirtualDirectory::Foreach(F&& callback, bool includeDots)
	{
		if (includeDots)
		{
			Entry ourselves = DirectoryEntry{ shared_from_this() };
			callback(std::string_view("."), ourselves);
			if (VirtualDirectoryPtr parent = m_parent.lock())
			{
				Entry parentEntry = DirectoryEntry{ parent };
				if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
					return;
			}
			else if (!CallbackReturn(callback, std::string_view(".."), ourselves))
					return;
		}

		for (auto&& entry : m_content)
		{
			if (!CallbackReturn(callback, std::string_view(entry.name), std::as_const(entry.entry)))
				return;
		}

		if (m_physicalPath)
		{
			for (auto&& physicalEntry : std::filesystem::directory_iterator(*m_physicalPath))
			{
				std::string filename = physicalEntry.path().filename().generic_u8string();

				// Check if physical file/directory has been overridden by a virtual one
				auto it = std::lower_bound(m_content.begin(), m_content.end(), filename, [](const ContentEntry& entry, std::string_view name)
				{
					return entry.name < name;
				});
				if (it != m_content.end() && it->name == filename)
					continue;

				std::filesystem::file_status status = physicalEntry.status();

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ physicalEntry.path() };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ physicalEntry.path() };
				else
					continue;

				if (!CallbackReturn(callback, std::string_view(filename), entry))
					return;
			}
		}
	}

	template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
	{
		assert(!path.empty());

		VirtualDirectoryPtr currentDir = shared_from_this();
		std::optional<std::filesystem::path> physicalPathBase;
		std::vector<std::string> physicalDirectoryParts;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			if (physicalPathBase)
			{
				// Special case when traversing directory
				if (dirName == ".." && !m_isUprootAllowed)
				{
					// Don't allow to escape virtual directory
					if (!physicalDirectoryParts.empty())
						physicalDirectoryParts.pop_back();
					else
						physicalPathBase.reset();
				}
				else if (dirName != ".")
					physicalDirectoryParts.emplace_back(dirName);

				return true;
			}

			return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
				{
					currentDir = dirEntry->directory;
					return true;
				}
				else if (auto physDirEntry = std::get_if<PhysicalDirectoryEntry>(&entry))
				{
					assert(!physicalPathBase);

					// We're traversing a physical directory
					physicalPathBase = physDirEntry->filePath;
					return true;
				}

				return false;
			});
		},
		[&](std::string_view name)
		{
			if (physicalPathBase)
			{
				std::filesystem::path filePath = *physicalPathBase;
				for (const auto& part : physicalDirectoryParts)
					filePath /= part;

				filePath /= name;

				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}
			else
				return currentDir->GetEntryInternal(name, callback);
		});
	}

	template<typename F>
	bool VirtualDirectory::GetFileContent(std::string_view path, F&& callback)
	{
		return GetEntry(path, [&](const Entry& entry)
		{
			return std::visit([&](auto&& entry)
			{
				using T = std::decay_t<decltype(entry)>;

				using P1 = const void*;
				using P2 = std::size_t;

				if constexpr (std::is_same_v<T, DataPointerEntry>)
				{
					return CallbackReturn(callback, static_cast<P1>(entry.data), SafeCast<P2>(entry.size));
				}
				else if constexpr (std::is_same_v<T, FileContentEntry>)
				{
					return CallbackReturn(callback, static_cast<P1>(entry.data.data()), SafeCast<P2>(entry.data.size()));
				}
				else if constexpr (std::is_same_v<T, PhysicalFileEntry>)
				{
					std::optional<std::vector<UInt8>> source = File::ReadWhole(entry.filePath);
					if (!source.has_value())
						return false;

					return CallbackReturn(callback, static_cast<P1>(source->data()), SafeCast<P2>(source->size()));
				}
				else if constexpr (std::is_same_v<T, DirectoryEntry> || std::is_same_v<T, PhysicalDirectoryEntry>)
				{
					NazaraError("entry is a directory");
					return false;
				}
				else
					static_assert(AlwaysFalse<T>(), "incomplete visitor");
			}, entry);
		});
	}

	inline bool VirtualDirectory::IsUprootAllowed() const
	{
		return m_isUprootAllowed;
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		if (entryName == "." || entryName == "..")
			throw std::runtime_error("invalid entry name");

		return dir->StoreInternal(std::string(entryName), DirectoryEntry{ std::move(directory) });
	}

	inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		if (entryName == "." || entryName == "..")
			throw std::runtime_error("invalid entry name");

		return dir->StoreInternal(std::string(entryName), PhysicalDirectoryEntry{ std::move(directoryPath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		if (entryName == "." || entryName == "..")
			throw std::runtime_error("invalid entry name");

		return dir->StoreInternal(std::string(entryName), FileContentEntry{ std::move(file) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, std::filesystem::path filePath) -> PhysicalFileEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		if (entryName == "." || entryName == "..")
			throw std::runtime_error("invalid entry name");

		return dir->StoreInternal(std::string(entryName), PhysicalFileEntry{ std::move(filePath) });
	}

	inline auto VirtualDirectory::StoreFile(std::string_view path, const void* data, std::size_t size) -> DataPointerEntry&
	{
		assert(!path.empty());

		std::shared_ptr<VirtualDirectory> dir;
		std::string_view entryName;
		if (!CreateOrRetrieveDirectory(path, dir, entryName))
			throw std::runtime_error("invalid path");

		if (entryName == "." || entryName == "..")
			throw std::runtime_error("invalid entry name");

		return dir->StoreInternal(std::string(entryName), DataPointerEntry{ data, size });
	}

	template<typename F> bool VirtualDirectory::GetEntryInternal(std::string_view name, F&& callback)
	{
		if (name == ".")
		{
			Entry entry{ DirectoryEntry{ shared_from_this() } };
			return CallbackReturn(callback, entry);
		}

		if (name == "..")
		{
			VirtualDirectoryPtr parentEntry;
			if (VirtualDirectoryPtr parent = m_parent.lock())
				parentEntry = std::move(parent);
			else if (!m_isUprootAllowed)
				parentEntry = shared_from_this();

			if (parentEntry)
			{
				Entry entry = DirectoryEntry{ std::move(parentEntry) };
				return CallbackReturn(callback, entry);
			}
		}

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});
		if (it == m_content.end() || it->name != name)
		{
			// Virtual file not found, check if it has a physical one
			if (m_physicalPath)
			{
				std::filesystem::path filePath = *m_physicalPath / name;
				std::filesystem::file_status status = std::filesystem::status(filePath); //< FIXME: This will follow symlink, is this the intended behavior? (see symlink_status)

				Entry entry;
				if (std::filesystem::is_regular_file(status))
					entry = PhysicalFileEntry{ std::move(filePath) };
				else if (std::filesystem::is_directory(status))
					entry = PhysicalDirectoryEntry{ std::move(filePath) };
				else
					return false; //< either not known or of a special type

				return CallbackReturn(callback, entry);
			}

			return false;
		}

		return CallbackReturn(callback, it->entry);
	}

	inline bool VirtualDirectory::CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName)
{
		directory = shared_from_this();

		bool allowCreation = true;
		return SplitPath(path, [&](std::string_view dirName)
		{
			assert(!dirName.empty());

			bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
			{
				if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
					directory = dirEntry->directory;
				else
					allowCreation = false; //< does exist but is not a directory
			});

			if (dirFound)
				return true;

			// Try to create a new directory
			if (!allowCreation)
				return false;

			auto newDirectory = std::make_shared<VirtualDirectory>(directory);
			directory->StoreDirectory(dirName, newDirectory);

			directory = std::move(newDirectory);
			return true;
		},
		[&](std::string_view name)
		{
			if (name.empty())
				return false;

			entryName = name;
			return true;
		});
	}

	template<typename T>
	T& VirtualDirectory::StoreInternal(std::string name, T value)
	{
		assert(!name.empty());

		auto it = std::lower_bound(m_content.begin(), m_content.end(), name, [](const ContentEntry& entry, std::string_view name)
		{
			return entry.name < name;
		});

		ContentEntry* entryPtr;
		if (it == m_content.end() || it->name != name)
			entryPtr = &*m_content.emplace(it);
		else
			entryPtr = &*it;

		entryPtr->entry = std::move(value);
		entryPtr->name = std::move(name);

		return std::get<T>(entryPtr->entry);
	}

	template<typename F, typename... Args>
	bool VirtualDirectory::CallbackReturn(F&& callback, Args&& ...args)
	{
		using Ret = decltype(callback(std::forward<Args>(args)...));
		if constexpr (std::is_void_v<Ret>)
		{
			callback(std::forward<Args>(args)...);
			return true;
		}
		else
		{
			static_assert(std::is_same_v<Ret, bool>, "callback must either return a boolean or nothing");
			return callback(std::forward<Args>(args)...);
		}
	}

	template<typename F1, typename F2>
	bool VirtualDirectory::SplitPath(std::string_view path, F1&& dirCB, F2&& lastCB)
	{
		std::string_view nextPart;
		auto HandlePart = [&](std::string_view part)
		{
			if (part.empty())
				return true; //< "a//b" == "a/b"

			if (!nextPart.empty() && !CallbackReturn(dirCB, nextPart))
				return false;

			nextPart = part;
			return true;
		};

		return SplitStringAny(path, R"(\/:)", HandlePart) && CallbackReturn(lastCB, nextPart);
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include "matrix.hh"
#include "function_matrix.hh"
#include "trig.hh"
#include "operators.hh"
#include "transpose.hh"
#include "streaming2.hh"

BOOST_AUTO_TEST_CASE(matrix_test)
{
  using namespace manifolds;
  auto m1 = GetMatrix<2,2>(1,2,3,4);

  BOOST_CHECK_EQUAL(m1.Coeff(0,0), 1);
  BOOST_CHECK_EQUAL(m1.Coeff(0,1), 2);
  BOOST_CHECK_EQUAL(m1.Coeff(1,0), 3);
  BOOST_CHECK_EQUAL(m1.Coeff(1,1), 4);

  auto m2 = m1 + m1;

  BOOST_CHECK_EQUAL(m2.Coeff(0,0), 2);
  BOOST_CHECK_EQUAL(m2.Coeff(0,1), 4);
  BOOST_CHECK_EQUAL(m2.Coeff(1,0), 6);
  BOOST_CHECK_EQUAL(m2.Coeff(1,1), 8);

  auto m3 = m2 * m1;
  BOOST_CHECK_EQUAL(m3.Coeff(0,0), 14);
  BOOST_CHECK_EQUAL(m3.Coeff(0,1), 20);
  BOOST_CHECK_EQUAL(m3.Coeff(1,0), 30);
  BOOST_CHECK_EQUAL(m3.Coeff(1,1), 44);

  auto mf = GetFunctionMatrix(Row(Cos(), -Sin()),
			      Row(Sin(), Cos()));
  BOOST_CHECK_EQUAL(mf(3),
		    (GetMatrix<2,2>(std::cos(3),
			           -std::sin(3),
				    std::sin(3),
				    std::cos(3))));

  auto mf2 = transpose(mf) * mf;
  Stream2(std::cout, mf) << "\n\n";
  Stream2(std::cout, transpose(mf)) << "\n\n";
  Stream2(std::cout, mf2) << "\n\n";

  BOOST_CHECK_EQUAL(mf2(4).Coeff(0,0), 1.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(0,1), 0.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(1,0), 0.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(1,1), 1.0);
}
<commit_msg>A little less output<commit_after>#include <boost/test/unit_test.hpp>
#include "matrix.hh"
#include "function_matrix.hh"
#include "trig.hh"
#include "operators.hh"
#include "transpose.hh"
#include "streaming2.hh"

BOOST_AUTO_TEST_CASE(matrix_test)
{
  using namespace manifolds;
  auto m1 = GetMatrix<2,2>(1,2,3,4);

  BOOST_CHECK_EQUAL(m1.Coeff(0,0), 1);
  BOOST_CHECK_EQUAL(m1.Coeff(0,1), 2);
  BOOST_CHECK_EQUAL(m1.Coeff(1,0), 3);
  BOOST_CHECK_EQUAL(m1.Coeff(1,1), 4);

  auto m2 = m1 + m1;

  BOOST_CHECK_EQUAL(m2.Coeff(0,0), 2);
  BOOST_CHECK_EQUAL(m2.Coeff(0,1), 4);
  BOOST_CHECK_EQUAL(m2.Coeff(1,0), 6);
  BOOST_CHECK_EQUAL(m2.Coeff(1,1), 8);

  auto m3 = m2 * m1;
  BOOST_CHECK_EQUAL(m3.Coeff(0,0), 14);
  BOOST_CHECK_EQUAL(m3.Coeff(0,1), 20);
  BOOST_CHECK_EQUAL(m3.Coeff(1,0), 30);
  BOOST_CHECK_EQUAL(m3.Coeff(1,1), 44);

  auto mf = GetFunctionMatrix(Row(Cos(), -Sin()),
			      Row(Sin(), Cos()));
  BOOST_CHECK_EQUAL(mf(3),
		    (GetMatrix<2,2>(std::cos(3),
			           -std::sin(3),
				    std::sin(3),
				    std::cos(3))));

  auto mf2 = transpose(mf) * mf;

  std::cout << mf2 << "\n\n";
  Stream2(std::cout, mf2) << "\n\n";

  BOOST_CHECK_EQUAL(mf2(4).Coeff(0,0), 1.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(0,1), 0.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(1,0), 0.0);
  BOOST_CHECK_EQUAL(mf2(4).Coeff(1,1), 1.0);
}
<|endoftext|>


<commit_before>/// Copyright (c) 2012, 2013 by Pascal Costanza, Intel Corporation.

#ifndef AOSOA_INDEXED_FOR_EACH_RANGE
#define AOSOA_INDEXED_FOR_EACH_RANGE

#include <cstddef>

#include "soa/table.hpp"
#include "aosoa/table_iterator.hpp"

namespace aosoa {

  template<class C, typename F>
  inline void indexed_for_each_range(C& container, const F& f) {
	const auto size = container.size();
	auto data = container.data();

	typedef soa::table_traits<C> traits;

	if (traits::tabled) {
	  const auto sdb = size/traits::table_size;
	  const auto smb = size%traits::table_size;
	  for (size_t i=0; i<sdb; ++i) f(traits::get_table(data, i), 0, traits::table_size, i*traits::table_size);
	  if (smb) f(traits::get_table(data, sdb), 0, smb, sdb*traits::table_size);
	} else f(traits::get_table(data, 0), 0, size, 0);
  }

  template<classC, size_t B, typename F>
  inline void indexed_for_each_range(const table_iterator<C,B>& begin,
									 const table_iterator<C,B>& end,
									 const F& f) {
	const auto table0 = begin.table;
	const auto index0 = begin.index;
	const auto tablen = end.table;
	const auto indexn = end.index;

	if (table0 < tablen) {
	  f(table0[0], index0, B, -index0);
	  const auto range = tablen-table0;
	  for (ptrdiff_t i=1; i<range; ++i) f(table0[i], 0, B, i*B-index0);
	  f(tablen[0], 0, indexn, range*B-index0);
	} else if (table0 == tablen) {
	  f(table0[0], index0, indexn, -index0);
	}
  }

}

#endif
<commit_msg>fixed typo<commit_after>/// Copyright (c) 2012, 2013 by Pascal Costanza, Intel Corporation.

#ifndef AOSOA_INDEXED_FOR_EACH_RANGE
#define AOSOA_INDEXED_FOR_EACH_RANGE

#include <cstddef>

#include "soa/table.hpp"
#include "aosoa/table_iterator.hpp"

namespace aosoa {

  template<class C, typename F>
  inline void indexed_for_each_range(C& container, const F& f) {
	const auto size = container.size();
	auto data = container.data();

	typedef soa::table_traits<C> traits;

	if (traits::tabled) {
	  const auto sdb = size/traits::table_size;
	  const auto smb = size%traits::table_size;
	  for (size_t i=0; i<sdb; ++i) f(traits::get_table(data, i), 0, traits::table_size, i*traits::table_size);
	  if (smb) f(traits::get_table(data, sdb), 0, smb, sdb*traits::table_size);
	} else f(traits::get_table(data, 0), 0, size, 0);
  }

  template<class C, size_t B, typename F>
  inline void indexed_for_each_range(const table_iterator<C,B>& begin,
									 const table_iterator<C,B>& end,
									 const F& f) {
	const auto table0 = begin.table;
	const auto index0 = begin.index;
	const auto tablen = end.table;
	const auto indexn = end.index;

	if (table0 < tablen) {
	  f(table0[0], index0, B, -index0);
	  const auto range = tablen-table0;
	  for (ptrdiff_t i=1; i<range; ++i) f(table0[i], 0, B, i*B-index0);
	  f(tablen[0], 0, indexn, range*B-index0);
	} else if (table0 == tablen) {
	  f(table0[0], index0, indexn, -index0);
	}
  }

}

#endif
<|endoftext|>


<commit_before>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <iostream>

#include "dbusgateway.h"
#include "log.h"

using namespace pelagicore;

class MockController :
    public ControllerAbstractInterface
{
public:

    virtual bool startApp()
    {
            return true;
    }

    virtual bool shutdown()
    {
        return true;
    }

    virtual bool setEnvironmentVariable(const std::string &variable,
        const std::string &value)
    {
        return true;
    }

    virtual bool hasBeenStarted() const
    {
        return true;
    }

    MOCK_METHOD1(systemCall, bool(const std::string &cmd));

};

class MockSystemcallInterfaceDBusGWTest :
    public SystemcallAbstractInterface
{
public:
    MOCK_METHOD1(makeCall, bool(const std::string &cmd));
    MOCK_METHOD2(makeCall, bool(const std::string &cmd, int &exitCode));
    MOCK_METHOD3(makePopenCall,
                 pid_t(const std::string &command, int *infp, int *outfp));
    MOCK_METHOD3(makePcloseCall, bool(pid_t pid, int infp, int outfp));
};

void close_fd_helper(pid_t pid, int infp, int outfp)
{
    close(infp);
}

class SystemcallInterfaceStub :
    public SystemcallAbstractInterface
{
public:
    FILE *file_descriptor = NULL;
    pid_t m_pid = 999;
    int m_infp = -1;
    int m_outfp = -1;

    SystemcallInterfaceStub() {
        file_descriptor = tmpfile();
        m_infp = fileno(file_descriptor);
    }

    virtual ~SystemcallInterfaceStub() {
        if(file_descriptor != NULL) {
            fclose(file_descriptor);
        }
    };

    virtual bool makeCall(const std::string &cmd)
    {
        return true;
    }

    virtual bool makeCall(const std::string &cmd, int &exitCode)
    {
        exitCode = 0;
        return true;
    }

    pid_t makePopenCall(const std::string &command,
                        int *infp,
                        int *outfp)
    {
        *infp = m_infp;
        *outfp = m_outfp;
        return m_pid;
    }

    bool makePcloseCall(pid_t pid, int infp, int outfp)
    {
        if(pid == m_pid && infp == m_infp && outfp == m_outfp) {
            return true;
        }

        return false;
    }

    std::string fileContent()
    {
        std::string content = "";
        char buf[20];
        rewind(file_descriptor);
        while (fgets(buf, 20, file_descriptor)) {
            content += buf;
        }

        return content;
    }
};

using ::testing::InSequence;
using ::testing::_;
using ::testing::Return;
using ::testing::NiceMock;

class DBusGatewayTest : public ::testing::Test
{
public:
    const std::string m_gatewayDir = "/tmp/dbusgateway-unit-test/gateways";
    const std::string m_containerName = "test";
    NiceMock<MockController> controllerInterface;
    SystemcallInterfaceStub systemcallInterface;
};

/*! Test DBusGateway saves the config when DBusGateway::setConfig()
 * has been called.
 */
TEST_F(DBusGatewayTest, TestSetConfig) {
    DBusGateway gw(controllerInterface,
                   systemcallInterface,
                   DBusGateway::SessionProxy,
                   m_gatewayDir,
                   m_containerName);

    std::string config = "{}";
    bool success = gw.setConfig(config);
    ASSERT_TRUE(success);
}

/*! Test DBusGateway writes the config provided by DBusGateway::setConfig()
 * to a fileno provided by the systemcallInterface when
 * DBusGateway::activate() has been called.
 */
TEST_F(DBusGatewayTest, TestActivateStdInWrite) {
    DBusGateway gw(controllerInterface,
                   systemcallInterface,
                   DBusGateway::SessionProxy,
                   m_gatewayDir,
                   m_containerName);

    std::string config = "{}";

    ASSERT_TRUE(gw.setConfig(config));
    ASSERT_TRUE(gw.activate());
    EXPECT_EQ(config, systemcallInterface.fileContent());
}

/*! Test DBusGateway calls ControllerInterface::makePopencall() when
 * DBusGateway::activate() has been called
 *
 * The DbusGateway::activate() should try to issue a dbus-proxy call
 * and then try to write the config to stdin of this. At the end it
 * should remove the file created by dbus-proxy.
 */
TEST_F(DBusGatewayTest, TestActivateCall) {
    NiceMock<MockSystemcallInterfaceDBusGWTest> systemcallInterfaceMock;
    DBusGateway *gw = new DBusGateway(controllerInterface,
                                      systemcallInterfaceMock,
                                      DBusGateway::SessionProxy,
                                      m_gatewayDir,
                                      m_containerName);

    // create sock file which teardown will remove
    std::string cmd_mkdir = "mkdir -p ";
    cmd_mkdir += m_gatewayDir;
    system(cmd_mkdir.c_str());
    std::string cmd_touch = "touch ";
    cmd_touch += m_gatewayDir;
    cmd_touch += "/sess_test.sock";
    system(cmd_touch.c_str());

    std::string config = "{}";

    ASSERT_TRUE(gw->setConfig(config));

    FILE *tmp = tmpfile();
    int infp = fileno(tmp);

    {
        InSequence sequence;
        EXPECT_CALL(
            systemcallInterfaceMock,
            makePopenCall("dbus-proxy "
                          "/tmp/dbusgateway-unit-test/gateways/sess_test.sock "
                          "session",
                          _, _)
        ).WillOnce(DoAll(::testing::SetArgPointee<1>(infp), Return(999)));

        EXPECT_CALL(
            systemcallInterfaceMock,
            makePcloseCall(_, _, _)
        ).WillOnce(DoAll(::testing::Invoke(close_fd_helper), Return(true)));
    }

    ASSERT_TRUE(gw->activate());
    ASSERT_TRUE(gw->teardown());

    delete gw;
}

<commit_msg>dbusgateway_unittest.cpp: fix failing test<commit_after>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <iostream>

#include "dbusgateway.h"
#include "log.h"

using namespace pelagicore;

class MockController :
    public ControllerAbstractInterface
{
public:

    virtual bool startApp()
    {
            return true;
    }

    virtual bool shutdown()
    {
        return true;
    }

    virtual bool setEnvironmentVariable(const std::string &variable,
        const std::string &value)
    {
        return true;
    }

    virtual bool hasBeenStarted() const
    {
        return true;
    }

    MOCK_METHOD1(systemCall, bool(const std::string &cmd));

};

class MockSystemcallInterfaceDBusGWTest :
    public SystemcallAbstractInterface
{
public:
    MOCK_METHOD1(makeCall, bool(const std::string &cmd));
    MOCK_METHOD2(makeCall, bool(const std::string &cmd, int &exitCode));
    MOCK_METHOD3(makePopenCall,
                 pid_t(const std::string &command, int *infp, int *outfp));
    MOCK_METHOD3(makePcloseCall, bool(pid_t pid, int infp, int outfp));
};

void close_fd_helper(pid_t pid, int infp, int outfp)
{
    close(infp);
}

class SystemcallInterfaceStub :
    public SystemcallAbstractInterface
{
public:
    FILE *file_descriptor = NULL;
    pid_t m_pid = 999;
    int m_infp = -1;
    int m_outfp = -1;
    std::string m_tmpfile;

    SystemcallInterfaceStub() {
        m_tmpfile = tempnam("/tmp/", NULL);
        file_descriptor = fopen(m_tmpfile.c_str(), "w+b");
        m_infp = fileno(file_descriptor);
    }

    virtual ~SystemcallInterfaceStub() {
        if(file_descriptor != NULL) {
            fclose(file_descriptor);
        }
        remove(m_tmpfile.c_str());
    };

    virtual bool makeCall(const std::string &cmd)
    {
        return true;
    }

    virtual bool makeCall(const std::string &cmd, int &exitCode)
    {
        exitCode = 0;
        return true;
    }

    pid_t makePopenCall(const std::string &command,
                        int *infp,
                        int *outfp)
    {
        *infp = m_infp;
        *outfp = m_outfp;
        return m_pid;
    }

    bool makePcloseCall(pid_t pid, int infp, int outfp)
    {
        if(pid == m_pid
            && ( infp == m_infp || infp == -1 )
            && ( outfp == m_outfp || outfp == -1 ))
        {
            return true;
        }

        return false;
    }

    std::string fileContent()
    {
        // Open file for reading. Don't reuse file_descriptor here
        // since it might have been closed previously
        FILE * file_descriptor_read = fopen(m_tmpfile.c_str(), "r");

        std::string content = "";
        char buf[20];
        rewind(file_descriptor);
        while (fgets(buf, 20, file_descriptor)) {
            content += buf;
        }

        fclose(file_descriptor_read);
        return content;
    }
};

using ::testing::InSequence;
using ::testing::_;
using ::testing::Return;
using ::testing::NiceMock;

class DBusGatewayTest : public ::testing::Test
{
public:
    const std::string m_gatewayDir = "/tmp/dbusgateway-unit-test/gateways";
    const std::string m_containerName = "test";
    NiceMock<MockController> controllerInterface;
    SystemcallInterfaceStub systemcallInterface;
};

/*! Test DBusGateway saves the config when DBusGateway::setConfig()
 * has been called.
 */
TEST_F(DBusGatewayTest, TestSetConfig) {
    DBusGateway gw(controllerInterface,
                   systemcallInterface,
                   DBusGateway::SessionProxy,
                   m_gatewayDir,
                   m_containerName);

    std::string config = "{}";
    bool success = gw.setConfig(config);
    ASSERT_TRUE(success);
}

/*! Test DBusGateway writes the config provided by DBusGateway::setConfig()
 * to a fileno provided by the systemcallInterface when
 * DBusGateway::activate() has been called.
 */
TEST_F(DBusGatewayTest, TestActivateStdInWrite) {
    DBusGateway gw(controllerInterface,
                   systemcallInterface,
                   DBusGateway::SessionProxy,
                   m_gatewayDir,
                   m_containerName);

    std::string config = "{}";

    ASSERT_TRUE(gw.setConfig(config));
    ASSERT_TRUE(gw.activate());
    EXPECT_EQ(config, systemcallInterface.fileContent());
}

/*! Test DBusGateway calls ControllerInterface::makePopencall() when
 * DBusGateway::activate() has been called
 *
 * The DbusGateway::activate() should try to issue a dbus-proxy call
 * and then try to write the config to stdin of this. At the end it
 * should remove the file created by dbus-proxy.
 */
TEST_F(DBusGatewayTest, TestActivateCall) {
    NiceMock<MockSystemcallInterfaceDBusGWTest> systemcallInterfaceMock;
    DBusGateway *gw = new DBusGateway(controllerInterface,
                                      systemcallInterfaceMock,
                                      DBusGateway::SessionProxy,
                                      m_gatewayDir,
                                      m_containerName);

    // create sock file which teardown will remove
    std::string cmd_mkdir = "mkdir -p ";
    cmd_mkdir += m_gatewayDir;
    system(cmd_mkdir.c_str());
    std::string cmd_touch = "touch ";
    cmd_touch += m_gatewayDir;
    cmd_touch += "/sess_test.sock";
    system(cmd_touch.c_str());

    std::string config = "{}";

    ASSERT_TRUE(gw->setConfig(config));

    FILE *tmp = tmpfile();
    int infp = fileno(tmp);

    {
        InSequence sequence;
        EXPECT_CALL(
            systemcallInterfaceMock,
            makePopenCall("dbus-proxy "
                          "/tmp/dbusgateway-unit-test/gateways/sess_test.sock "
                          "session",
                          _, _)
        ).WillOnce(DoAll(::testing::SetArgPointee<1>(infp), Return(999)));

        EXPECT_CALL(
            systemcallInterfaceMock,
            makePcloseCall(_, _, _)
        ).WillOnce(DoAll(::testing::Invoke(close_fd_helper), Return(true)));
    }

    ASSERT_TRUE(gw->activate());
    ASSERT_TRUE(gw->teardown());

    delete gw;
}

<|endoftext|>


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

#include "Importer.h"

#include "../volume/AMRVolume.h"

#include "ospcommon/utility/StringManip.h"

namespace ospray {
  namespace sg {

    static void importStructuredVolume(const std::shared_ptr<Node> &world,
                                       const xml::Node &xmlNode)
    {
      using SVFF = StructuredVolumeFromFile;
      auto volume = createNode("volume",
                               "StructuredVolumeFromFile")->nodeAs<SVFF>();

      vec3i dimensions(-1);
      vec3f gridSpacing = volume->child("gridSpacing").valueAs<vec3f>();
      std::string volumeFileName = "";
      std::string voxelType = "";

      for (const auto &child : xmlNode.child) {
        if (child.name == "dimensions")
          dimensions = toVec3i(child.content.c_str());
        else if (child.name == "voxelType")
          voxelType = child.content;
        else if (child.name == "filename")
          volumeFileName = child.content;
        else if (child.name == "samplingRate") {
          // Silently ignore
        } else if (child.name == "gridSpacing") {
          gridSpacing = toVec3f(child.content.c_str());
        } else {
          throw std::runtime_error("unknown old-style osp file "
                                   "component volume::" + child.name);
        }
      }

      volume->fileNameOfCorrespondingXmlDoc = xmlNode.doc->fileName;
      volume->fileName = volumeFileName;

      volume->child("dimensions") = dimensions;
      volume->child("voxelType") = voxelType;
      volume->child("gridSpacing") = gridSpacing;

      world->add(volume);
    }

    static void importRAW2AMRVolume(const std::shared_ptr<Node> &world,
                                    const std::string &originalFileName,
                                    const xml::Node &xmlNode)
    {
      FileName orgFile(originalFileName);

      auto node = sg::createNode("amr", "AMRVolume")->nodeAs<sg::AMRVolume>();
      std::string fileName;
      int brickSize = -1;

      for (const auto &child : xmlNode.child) {
        if (child.name == "brickSize")
          brickSize = std::atoi(child.content.c_str());
        else if (child.name == "fileName")
          fileName = orgFile.path() + child.content;
      }

      if (fileName == "") {
        throw std::runtime_error("no child element 'fileName' specified "
                                 "for AMR volume!");
      } else if (brickSize == -1) {
        throw std::runtime_error("no child element 'brickSize' specified "
                                 "for AMR volume!");
      }

      node->parseRaw2AmrFile(fileName, brickSize);

      world->add(node);
    }

#ifdef OSPRAY_APPS_SG_CHOMBO
    static void importCHOMBOFromOSP(const std::shared_ptr<Node> &world,
                                    const std::string &originalFileName,
                                    const xml::Node &xmlNode)
    {
      FileName orgFile(originalFileName);

      std::string fileName;

      for (const auto &child : xmlNode.child) {
        if (child.name == "fileName")
          fileName = orgFile.path() + child.content;
      }

      if (fileName == "") {
        throw std::runtime_error("no child element 'fileName' specified "
                                 "for AMR volume!");
      }

      importCHOMBO(world, fileName);
    }
#endif

    void loadOSP(const std::shared_ptr<Node> &world,
                 const std::string &fileName)
    {
      std::cout << "#osp:sg: starting to read OSPRay XML file '" << fileName
                << "'" << std::endl;

      auto doc = xml::readXML(fileName);

      std::cout << "#osp:sg: XML file read, starting to parse content..."
                << std::endl;

      if (doc->child.empty())
        throw std::runtime_error("ospray xml input file does not contain any nodes!?");

      for (const auto &node : doc->child) {
        auto nameLower = utility::lowerCase(node.name);
        if (nameLower == "volume" || nameLower == "structuredvolume")
          importStructuredVolume(world, node);
        else if (nameLower == "amr" || nameLower == "amrvolume")
          importRAW2AMRVolume(world, fileName, node);
#ifdef OSPRAY_APPS_SG_CHOMBO
        else if (nameLower == "chombo" || nameLower == "chombovolume")
          importCHOMBOFromOSP(world, fileName, node);
#endif
        else
          std::cout << "#importOSG: unknown xml tag '" << node.name << "'\n";
      }
    }

  } // ::ospray::sg
} // ::ospray
<commit_msg>add ability to specify slices in .osp files<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "Importer.h"

#include "../volume/AMRVolume.h"
// ospcommon
#include "ospcommon/containers/AlignedVector.h"
#include "ospcommon/utility/StringManip.h"

namespace ospray {
  namespace sg {

    static void importStructuredVolume(const std::shared_ptr<Node> &world,
                                       const xml::Node &xmlNode)
    {
      using SVFF = StructuredVolumeFromFile;
      auto volume = createNode("volume",
                               "StructuredVolumeFromFile")->nodeAs<SVFF>();

      vec3i dimensions(-1);
      vec3f gridSpacing = volume->child("gridSpacing").valueAs<vec3f>();
      std::string volumeFileName = "";
      std::string voxelType = "";

      containers::AlignedVector<vec4f> slices;

      for (const auto &child : xmlNode.child) {
        if (child.name == "dimensions")
          dimensions = toVec3i(child.content.c_str());
        else if (child.name == "voxelType")
          voxelType = child.content;
        else if (child.name == "filename")
          volumeFileName = child.content;
        else if (child.name == "slice") {
          auto components = utility::split(child.content, " ");
          if (components.size() != 4) {
            std::cerr << "WARNING: .osp files must have slices defined as 4 "
                      << "floats separated by spaces! Ignoring..." << std::endl;
            continue;
          }

          slices.emplace_back(
            std::atof(components[0].c_str()),
            std::atof(components[1].c_str()),
            std::atof(components[2].c_str()),
            std::atof(components[3].c_str())
          );
        } else if (child.name == "samplingRate") {
          // Silently ignore
        } else if (child.name == "gridSpacing") {
          gridSpacing = toVec3f(child.content.c_str());
        } else {
          throw std::runtime_error("unknown old-style osp file "
                                   "component volume::" + child.name);
        }
      }

      volume->fileNameOfCorrespondingXmlDoc = xmlNode.doc->fileName;
      volume->fileName = volumeFileName;

      volume->child("dimensions") = dimensions;
      volume->child("voxelType") = voxelType;
      volume->child("gridSpacing") = gridSpacing;

      world->add(volume);

      if (!slices.empty()) {
        // scale 4th component of slices by the dimension of the volume
        // (input value is on [0,1]), and add to scene
        for (auto & slice : slices)
          slice.w *= dimensions.x;

        auto slices_node = createNode("slices", "Slices");
        auto slices_data = std::make_shared<DataVector4f>();
        slices_data->v = slices;
        slices_data->setName("planes");

        slices_node->add(slices_data);
        slices_node->setChild("volume", volume);

        // add slices to world
        world->add(slices_node);
      }
    }

    static void importRAW2AMRVolume(const std::shared_ptr<Node> &world,
                                    const std::string &originalFileName,
                                    const xml::Node &xmlNode)
    {
      FileName orgFile(originalFileName);

      auto node = sg::createNode("amr", "AMRVolume")->nodeAs<sg::AMRVolume>();
      std::string fileName;
      int brickSize = -1;

      for (const auto &child : xmlNode.child) {
        if (child.name == "brickSize")
          brickSize = std::atoi(child.content.c_str());
        else if (child.name == "fileName")
          fileName = orgFile.path() + child.content;
      }

      if (fileName == "") {
        throw std::runtime_error("no child element 'fileName' specified "
                                 "for AMR volume!");
      } else if (brickSize == -1) {
        throw std::runtime_error("no child element 'brickSize' specified "
                                 "for AMR volume!");
      }

      node->parseRaw2AmrFile(fileName, brickSize);

      world->add(node);
    }

#ifdef OSPRAY_APPS_SG_CHOMBO
    static void importCHOMBOFromOSP(const std::shared_ptr<Node> &world,
                                    const std::string &originalFileName,
                                    const xml::Node &xmlNode)
    {
      FileName orgFile(originalFileName);

      std::string fileName;

      for (const auto &child : xmlNode.child) {
        if (child.name == "fileName")
          fileName = orgFile.path() + child.content;
      }

      if (fileName == "") {
        throw std::runtime_error("no child element 'fileName' specified "
                                 "for AMR volume!");
      }

      importCHOMBO(world, fileName);
    }
#endif

    void loadOSP(const std::shared_ptr<Node> &world,
                 const std::string &fileName)
    {
      std::cout << "#osp:sg: starting to read OSPRay XML file '" << fileName
                << "'" << std::endl;

      auto doc = xml::readXML(fileName);

      std::cout << "#osp:sg: XML file read, starting to parse content..."
                << std::endl;

      if (doc->child.empty())
        throw std::runtime_error("ospray xml input file does not contain any nodes!?");

      for (const auto &node : doc->child) {
        auto nameLower = utility::lowerCase(node.name);
        if (nameLower == "volume" || nameLower == "structuredvolume")
          importStructuredVolume(world, node);
        else if (nameLower == "amr" || nameLower == "amrvolume")
          importRAW2AMRVolume(world, fileName, node);
#ifdef OSPRAY_APPS_SG_CHOMBO
        else if (nameLower == "chombo" || nameLower == "chombovolume")
          importCHOMBOFromOSP(world, fileName, node);
#endif
        else
          std::cout << "#importOSG: unknown xml tag '" << node.name << "'\n";
      }
    }

  } // ::ospray::sg
} // ::ospray
<|endoftext|>


<commit_before>#include "curltools.h"

#include <iostream>
#include <openssl/ssl.h>

boost::once_flag init_openssl_once_flag = BOOST_ONCE_INIT;

class CurlCleaner
{
    CURL* curl_obj_to_clean;
public:
    CurlCleaner(CURL* Curl_obj_to_clean) : curl_obj_to_clean(Curl_obj_to_clean)
    {}

    ~CurlCleaner() {
        curl_easy_cleanup(curl_obj_to_clean);
    }
};

size_t cURLTools::CurlWrite_CallbackFunc_StdString(void *contents, size_t size,
                                        size_t nmemb, std::deque<char> *s) {
  size_t newLength = size * nmemb;
  size_t oldLength = s->size();
  try {
    s->resize(oldLength + newLength);
  } catch (std::bad_alloc &e) {
    std::stringstream msg;
    msg << "Error allocating memory: " << e.what() << std::endl;
    printf("%s", msg.str().c_str());
    return 0;
  }

  std::copy((char *)contents, (char *)contents + newLength,
            s->begin() + oldLength);
  return size * nmemb;
}

int cURLTools::CurlProgress_CallbackFunc(void *, double TotalToDownload,
                              double NowDownloaded, double /*TotalToUpload*/,
                              double /*NowUploaded*/) {
  std::clog << "Download progress: " <<
               ToString(NowDownloaded) << " / " <<
               ToString(TotalToDownload) << std::endl;
  return CURLE_OK;
}

std::string cURLTools::GetFileFromHTTPS(const std::string &URL, long ConnectionTimeout, bool IncludeProgressBar) {

#if OPENSSL_VERSION_NUMBER < 0x10100000L
  boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
  boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0, static_cast<const ossl_init_settings_st*>(NULL));
#endif

  CURL *curl;
  CURLcode res;

  curl_global_init(CURL_GLOBAL_DEFAULT);

  curl = curl_easy_init();
  std::deque<char> s;
  if (curl) {

    CurlCleaner cleaner(curl);

    curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // verify ssl peer
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // verify ssl hostname
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
                     CurlWrite_CallbackFunc_StdString);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);

    if (IncludeProgressBar) {
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
      curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
                       CurlProgress_CallbackFunc);
    } else {
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
    }
    //        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if (res != CURLE_OK) {
      std::string errorMsg(curl_easy_strerror(res));
      throw std::runtime_error(std::string(errorMsg).c_str());
    } else {
      long http_response_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
      if (http_response_code != 200) {
          throw std::runtime_error("Error retrieving data with https protocol, error code: " + ToString(http_response_code) +
                                   ". Probably the URL is invalid.");
      }
    }

    /* always cleanup */
    // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
    // curl_easy_cleanup(curl);
  }
  std::string fileStr(s.begin(), s.end());
  return fileStr;
}
<commit_msg>Thread-safety fix in curl.<commit_after>#include "curltools.h"

#include <iostream>
#include <openssl/ssl.h>
#include <boost/thread.hpp>

boost::once_flag init_openssl_once_flag = BOOST_ONCE_INIT;
boost::mutex curl_global_init_lock;

class CurlCleaner
{
    CURL* curl_obj_to_clean;
public:
    CurlCleaner(CURL* Curl_obj_to_clean) : curl_obj_to_clean(Curl_obj_to_clean)
    {}

    ~CurlCleaner() {
        curl_easy_cleanup(curl_obj_to_clean);
    }
};

size_t cURLTools::CurlWrite_CallbackFunc_StdString(void *contents, size_t size,
                                        size_t nmemb, std::deque<char> *s) {
  size_t newLength = size * nmemb;
  size_t oldLength = s->size();
  try {
    s->resize(oldLength + newLength);
  } catch (std::bad_alloc &e) {
    std::stringstream msg;
    msg << "Error allocating memory: " << e.what() << std::endl;
    printf("%s", msg.str().c_str());
    return 0;
  }

  std::copy((char *)contents, (char *)contents + newLength,
            s->begin() + oldLength);
  return size * nmemb;
}

int cURLTools::CurlProgress_CallbackFunc(void *, double TotalToDownload,
                              double NowDownloaded, double /*TotalToUpload*/,
                              double /*NowUploaded*/) {
  std::clog << "Download progress: " <<
               ToString(NowDownloaded) << " / " <<
               ToString(TotalToDownload) << std::endl;
  return CURLE_OK;
}

std::string cURLTools::GetFileFromHTTPS(const std::string &URL, long ConnectionTimeout, bool IncludeProgressBar) {

#if OPENSSL_VERSION_NUMBER < 0x10100000L
  boost::call_once(init_openssl_once_flag, SSL_library_init);
#else
  boost::call_once(init_openssl_once_flag, OPENSSL_init_ssl, 0, static_cast<const ossl_init_settings_st*>(NULL));
#endif

  CURL *curl;
  CURLcode res;

  {
      boost::lock_guard<boost::mutex> lg(curl_global_init_lock);
      curl_global_init(CURL_GLOBAL_DEFAULT);
  }

  curl = curl_easy_init();
  std::deque<char> s;
  if (curl) {

    CurlCleaner cleaner(curl);

    curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // verify ssl peer
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // verify ssl hostname
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
                     CurlWrite_CallbackFunc_StdString);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);

    if (IncludeProgressBar) {
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
      curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
                       CurlProgress_CallbackFunc);
    } else {
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
    }
    //        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //verbose output
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ConnectionTimeout);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if (res != CURLE_OK) {
      std::string errorMsg(curl_easy_strerror(res));
      throw std::runtime_error(std::string(errorMsg).c_str());
    } else {
      long http_response_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
      if (http_response_code != 200) {
          throw std::runtime_error("Error retrieving data with https protocol, error code: " + ToString(http_response_code) +
                                   ". Probably the URL is invalid.");
      }
    }

    /* always cleanup */
    // This is replaced by a smart cleaning object with the destructor (CurlCleaner)
    // curl_easy_cleanup(curl);
  }
  std::string fileStr(s.begin(), s.end());
  return fileStr;
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   Entry.cpp
    created:    11/6/2011
    author:     Martin Preisler
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE CEGUITests

#include <boost/test/unit_test.hpp>
#include <iostream>

#include "CEGUI/RendererModules/Null/Renderer.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/DefaultResourceProvider.h"
#include "CEGUI/SchemeManager.h"
#include "CEGUI/ImageManager.h"
#include "CEGUI/AnimationManager.h"
#include "CEGUI/Font.h"
#include "CEGUI/WindowManager.h"
#include "CEGUI/ScriptModule.h"
#include "CEGUI/XMLParser.h"
#include "CEGUI/falagard/WidgetLookManager.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __APPLE__
#   include <Carbon/Carbon.h>
#endif

#define CEGUI_SAMPLE_DATAPATH_VAR "CEGUI_SAMPLE_DATAPATH"
// setup default-default path
#ifndef CEGUI_SAMPLE_DATAPATH
    #define CEGUI_SAMPLE_DATAPATH "../datafiles"
#endif

/**
\brief This fixture sets CEGUI up with NullRenderer
*/
class CEGUIInstanceFixture
{
public:
    CEGUIInstanceFixture()
    {
        // BOOST_TEST_MESSAGE is not available here
        std::cout << "Bringing CEGUI up using NullRenderer" << std::endl;
        std::cout << "************************************" << std::endl;
        std::cout << std::endl;

        CEGUI::NullRenderer::bootstrapSystem();
        // we don't need stderr, we will deal with exception reports manually
        CEGUI::Exception::setStdErrEnabled(false);

        // FIXME: it sucks that we have to load a scheme to test but that's
        //        how it is at the moment :-(

        // initialise the required dirs for the DefaultResourceProvider
        CEGUI::DefaultResourceProvider* rp =
            static_cast<CEGUI::DefaultResourceProvider*>
                (CEGUI::System::getSingleton().getResourceProvider());

        const char* dataPathPrefix = getDataPathPrefix();
        char resourcePath[PATH_MAX];

        // set the default resource groups to be used
        CEGUI::ImageManager::setImagesetDefaultResourceGroup("imagesets");
        CEGUI::Font::setDefaultResourceGroup("fonts");
        CEGUI::Scheme::setDefaultResourceGroup("schemes");
        CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
        CEGUI::WindowManager::setDefaultResourceGroup("layouts");
        CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
        CEGUI::AnimationManager::setDefaultResourceGroup("animations");

        // setup default group for validation schemas
        CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
        if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
            parser->setProperty("SchemaDefaultResourceGroup", "schemas");

        // for each resource type, set a resource group directory
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "schemes/");
        rp->setResourceGroupDirectory("schemes", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "imagesets/");
        rp->setResourceGroupDirectory("imagesets", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "fonts/");
        rp->setResourceGroupDirectory("fonts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "layouts/");
        rp->setResourceGroupDirectory("layouts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "looknfeel/");
        rp->setResourceGroupDirectory("looknfeels", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "lua_scripts/");
        rp->setResourceGroupDirectory("lua_scripts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "xml_schemas/");
        rp->setResourceGroupDirectory("schemas", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "animations/");
        rp->setResourceGroupDirectory("animations", resourcePath);

        CEGUI::SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
    }

    ~CEGUIInstanceFixture()
    {
        // BOOST_TEST_MESSAGE is not available here
        std::cout << std::endl;
        std::cout << "Destroying CEGUI instance" << std::endl;

        CEGUI::NullRenderer::destroySystem();
    }

    //----------------------------------------------------------------------------//
    const char* getDataPathPrefix() const
    {
        static char dataPathPrefix[PATH_MAX];

#ifdef __APPLE__
        CFURLRef datafilesURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
                                                        CFSTR("datafiles"),
                                                        0, 0);
        CFURLGetFileSystemRepresentation(datafilesURL, true,
                                         reinterpret_cast<UInt8*>(dataPathPrefix),
                                         PATH_MAX);
        CFRelease(datafilesURL);
#else
        char* envDataPath = 0;

        // get data path from environment var
        envDataPath = getenv(CEGUI_SAMPLE_DATAPATH_VAR);

        // set data path prefix / base directory.  This will
        // be either from an environment variable, or from
        // a compiled in default based on original configure
        // options
        if (envDataPath != 0)
            strcpy(dataPathPrefix, envDataPath);
        else
            strcpy(dataPathPrefix, CEGUI_SAMPLE_DATAPATH);
#endif

        return dataPathPrefix;
    }

};

BOOST_GLOBAL_FIXTURE( CEGUIInstanceFixture );
<commit_msg>Better default CEGUI_SAMPLE_DATAPATH for AutoQA<commit_after>/***********************************************************************
    filename:   Entry.cpp
    created:    11/6/2011
    author:     Martin Preisler
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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.
 ***************************************************************************/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE CEGUITests

#include <boost/test/unit_test.hpp>
#include <iostream>

#include "CEGUI/RendererModules/Null/Renderer.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/DefaultResourceProvider.h"
#include "CEGUI/SchemeManager.h"
#include "CEGUI/ImageManager.h"
#include "CEGUI/AnimationManager.h"
#include "CEGUI/Font.h"
#include "CEGUI/WindowManager.h"
#include "CEGUI/ScriptModule.h"
#include "CEGUI/XMLParser.h"
#include "CEGUI/falagard/WidgetLookManager.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __APPLE__
#   include <Carbon/Carbon.h>
#endif

#define CEGUI_SAMPLE_DATAPATH_VAR "CEGUI_SAMPLE_DATAPATH"
// setup default-default path
#ifndef CEGUI_SAMPLE_DATAPATH
    #define CEGUI_SAMPLE_DATAPATH "../../datafiles"
#endif

/**
\brief This fixture sets CEGUI up with NullRenderer
*/
class CEGUIInstanceFixture
{
public:
    CEGUIInstanceFixture()
    {
        // BOOST_TEST_MESSAGE is not available here
        std::cout << "Bringing CEGUI up using NullRenderer" << std::endl;
        std::cout << "************************************" << std::endl;
        std::cout << std::endl;

        CEGUI::NullRenderer::bootstrapSystem();
        // we don't need stderr, we will deal with exception reports manually
        CEGUI::Exception::setStdErrEnabled(false);

        // FIXME: it sucks that we have to load a scheme to test but that's
        //        how it is at the moment :-(

        // initialise the required dirs for the DefaultResourceProvider
        CEGUI::DefaultResourceProvider* rp =
            static_cast<CEGUI::DefaultResourceProvider*>
                (CEGUI::System::getSingleton().getResourceProvider());

        const char* dataPathPrefix = getDataPathPrefix();
        char resourcePath[PATH_MAX];

        // set the default resource groups to be used
        CEGUI::ImageManager::setImagesetDefaultResourceGroup("imagesets");
        CEGUI::Font::setDefaultResourceGroup("fonts");
        CEGUI::Scheme::setDefaultResourceGroup("schemes");
        CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
        CEGUI::WindowManager::setDefaultResourceGroup("layouts");
        CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
        CEGUI::AnimationManager::setDefaultResourceGroup("animations");

        // setup default group for validation schemas
        CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
        if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
            parser->setProperty("SchemaDefaultResourceGroup", "schemas");

        // for each resource type, set a resource group directory
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "schemes/");
        rp->setResourceGroupDirectory("schemes", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "imagesets/");
        rp->setResourceGroupDirectory("imagesets", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "fonts/");
        rp->setResourceGroupDirectory("fonts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "layouts/");
        rp->setResourceGroupDirectory("layouts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "looknfeel/");
        rp->setResourceGroupDirectory("looknfeels", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "lua_scripts/");
        rp->setResourceGroupDirectory("lua_scripts", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "xml_schemas/");
        rp->setResourceGroupDirectory("schemas", resourcePath);
        sprintf(resourcePath, "%s/%s", dataPathPrefix, "animations/");
        rp->setResourceGroupDirectory("animations", resourcePath);

        CEGUI::SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
    }

    ~CEGUIInstanceFixture()
    {
        // BOOST_TEST_MESSAGE is not available here
        std::cout << std::endl;
        std::cout << "Destroying CEGUI instance" << std::endl;

        CEGUI::NullRenderer::destroySystem();
    }

    //----------------------------------------------------------------------------//
    const char* getDataPathPrefix() const
    {
        static char dataPathPrefix[PATH_MAX];

#ifdef __APPLE__
        CFURLRef datafilesURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
                                                        CFSTR("datafiles"),
                                                        0, 0);
        CFURLGetFileSystemRepresentation(datafilesURL, true,
                                         reinterpret_cast<UInt8*>(dataPathPrefix),
                                         PATH_MAX);
        CFRelease(datafilesURL);
#else
        char* envDataPath = 0;

        // get data path from environment var
        envDataPath = getenv(CEGUI_SAMPLE_DATAPATH_VAR);

        // set data path prefix / base directory.  This will
        // be either from an environment variable, or from
        // a compiled in default based on original configure
        // options
        if (envDataPath != 0)
            strcpy(dataPathPrefix, envDataPath);
        else
            strcpy(dataPathPrefix, CEGUI_SAMPLE_DATAPATH);
#endif

        return dataPathPrefix;
    }

};

BOOST_GLOBAL_FIXTURE( CEGUIInstanceFixture );
<|endoftext|>