<commit_before>/** \file    translate_chainer.cc
 *  \brief   Simple tool for generating a sequence of Web pages for translations.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

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

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

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

#include <iostream>
#include <fstream>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include "Compiler.h"
#include "ExecUtil.h"
#include "MiscUtil.h"
#include "StringUtil.h"
#include "UrlUtil.h"
#include "WebUtil.h"
#include "util.h"

void DumpCgiArgs(const std::multimap<std::string, std::string> &cgi_args) {
    for (const auto &key_and_values : cgi_args)
        std::cout << key_and_values.first << " = " << key_and_values.second << '\n';
}

void ParseEscapedCommaSeparatedList(const std::string &escaped_text, std::vector<std::string> * const list) {
    list->clear();

    std::string unescaped_text;
    bool last_char_was_backslash(false);

    for (const auto ch : escaped_text) {
        if (last_char_was_backslash) {
            last_char_was_backslash = false;
            unescaped_text += ch;
        } else if (ch == '\\')
            last_char_was_backslash = true;
        else if (ch == ',') {
            list->emplace_back(unescaped_text);
            unescaped_text.clear();
        } else
            unescaped_text += ch;
    }

    if (unlikely(last_char_was_backslash))
        Error("weird escaped string ends in backslash \"" + escaped_text + "\"!");

    list->emplace_back(StringUtil::RightTrim(&unescaped_text, '\n'));
}

struct Translation {
    std::string index_, remaining_count_, language_code_, text_, category_, gnd_code_;
};

const std::string NO_GND_CODE("-1");

void ParseGetMissingLine(const std::string &line, Translation * const translation) {
    std::vector<std::string> parts;
    ParseEscapedCommaSeparatedList(line, &parts);
    if (unlikely(parts.size() != 5 and parts.size() != 6))
        Error("expected 5 or 6 parts, found \"" + line + "\"!");

    translation->index_           = parts[0];
    translation->remaining_count_ = parts[1];
    translation->language_code_   = parts[2];
    translation->text_            = parts[3];
    translation->category_        = parts[4];
    translation->gnd_code_        = (parts.size() == 5) ? NO_GND_CODE : parts[5];
}

void ParseTranslationsDbToolOutput(const std::string &output, std::vector<Translation> * const translations) {
    std::vector<std::string> lines;
    StringUtil::Split(output, '\n', &lines);

    for (const auto &line : lines) {
        Translation new_translation;
        ParseGetMissingLine(line, &new_translation);
        translations->emplace_back(new_translation);
    }
}

std::string GetCGIParameterOrDie(const std::multimap<std::string, std::string> &cgi_args,
                                 const std::string &parameter_name)
{
    const auto key_and_value(cgi_args.find(parameter_name));
    if (key_and_value == cgi_args.cend())
        Error("expected a(n) \"" + parameter_name + "\" parameter!");

    return key_and_value->second;
}

std::string GetCGIParameterOrEmptyString(const std::multimap<std::string, std::string> &cgi_args,
                                         const std::string &parameter_name)
{
    const auto key_and_value(cgi_args.find(parameter_name));
    if (key_and_value == cgi_args.cend())
        return "";

    return key_and_value->second;
}

void ParseTranslationsDbToolOutputAndGenerateNewDisplay(const std::string &output, const std::string &language_code,
                                                        const std::string &ixtheo_base_url)
{
    std::vector<Translation> translations;
    ParseTranslationsDbToolOutput(output, &translations);
    if (translations.empty()) {
        std::ifstream done_html("/var/lib/tuelib/translate_chainer/done_translating.html", std::ios::binary);
        std::cout << done_html.rdbuf();
    } else {
        std::map<std::string, std::vector<std::string>> names_to_values_map;
        names_to_values_map.emplace(std::make_pair(std::string("index"),
                                                   std::vector<std::string>{ translations.front().index_ }));
        names_to_values_map.emplace(std::make_pair(std::string("remaining_count"),
                                                   std::vector<std::string>{ translations.front().remaining_count_ }));
        names_to_values_map.emplace(std::make_pair(std::string("target_language_code"),
                                                   std::vector<std::string>{ language_code }));
        names_to_values_map.emplace(std::make_pair(std::string("ixtheo_base_url"),
                                                   std::vector<std::string>{ UrlUtil::UrlDecode(ixtheo_base_url) }));
        names_to_values_map.emplace(std::make_pair(std::string("category"),
                                                   std::vector<std::string>{ translations.front().category_ }));
        if (translations.front().gnd_code_ != NO_GND_CODE)
            names_to_values_map.emplace(std::make_pair(std::string("gnd_code"),
                                                       std::vector<std::string>{ translations.front().gnd_code_ }));

        std::vector<std::string> language_codes, example_texts, url_escaped_example_texts;
        for (const auto &translation : translations) {
            language_codes.emplace_back(translation.language_code_);
            example_texts.emplace_back(translation.text_);
            url_escaped_example_texts.emplace_back(UrlUtil::UrlEncode(translation.text_));
        }
        names_to_values_map.emplace(std::make_pair(std::string("language_code"), language_codes));
        names_to_values_map.emplace(std::make_pair(std::string("example_text"), example_texts));
        names_to_values_map.emplace(std::make_pair(std::string("url_escaped_example_text"),
                                                   url_escaped_example_texts));

        std::ifstream translate_html("/var/lib/tuelib/translate_chainer/translate.html", std::ios::binary);
        MiscUtil::ExpandTemplate(translate_html, std::cout, names_to_values_map);
    }
}

void GetMissing(const std::multimap<std::string, std::string> &cgi_args) {
    const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
    const std::string ixtheo_base_url(GetCGIParameterOrDie(cgi_args, "ixtheo_base_url"));

    const std::string GET_MISSING_COMMAND("/usr/local/bin/translation_db_tool get_missing " + language_code);
    std::string output;
    if (not ExecUtil::ExecSubcommandAndCaptureStdout(GET_MISSING_COMMAND, &output))
        Error("failed to execute \"" + GET_MISSING_COMMAND + "\" or it returned a non-zero exit code!");

    ParseTranslationsDbToolOutputAndGenerateNewDisplay(output, language_code, ixtheo_base_url);
}

void Insert(const std::multimap<std::string, std::string> &cgi_args) {
    const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
    const std::string translation(GetCGIParameterOrDie(cgi_args, "translation"));
    const std::string index(GetCGIParameterOrDie(cgi_args, "index"));
    const std::string gnd_code(GetCGIParameterOrEmptyString(cgi_args, "gnd_code"));

    if (translation.empty())
        return;

    std::string insert_command("/usr/local/bin/translation_db_tool insert '" + index);
    if (not gnd_code.empty())
        insert_command += "' '" + gnd_code;
    insert_command += "' " + language_code + " '" + translation + "'";

    std::string output;
    if (not ExecUtil::ExecSubcommandAndCaptureStdout(insert_command, &output))
        Error("failed to execute \"" + insert_command + "\" or it returned a non-zero exit code!");
}

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    try {
        std::multimap<std::string, std::string> cgi_args;
        WebUtil::GetAllCgiArgs(&cgi_args, argc, argv);

        if (cgi_args.size() == 1) {
            std::cout << "Content-Type: text/html; charset=utf-8\r\n\r\n";
            GetMissing(cgi_args);
        } else if (cgi_args.size() == 5) {
            const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
            const std::string ixtheo_base_url(GetCGIParameterOrDie(cgi_args, "ixtheo_base_url"));
            std::cout << "Status: 302 Found\r\n";
            std::cout << "Location: /cgi-bin/translate_chainer?language_code=" << language_code
                      << "&ixtheo_base_url=" << ixtheo_base_url << "\r\n\r\n";
            Insert(cgi_args);
        } else
            Error("we should be called w/ either 1 or 5 CGI arguments!");
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Work in progress.<commit_after>/** \file    translate_chainer.cc
 *  \brief   Simple tool for generating a sequence of Web pages for translations.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

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

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

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

#include <iostream>
#include <fstream>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include "Compiler.h"
#include "ExecUtil.h"
#include "MiscUtil.h"
#include "StringUtil.h"
#include "UrlUtil.h"
#include "WebUtil.h"
#include "util.h"

void DumpCgiArgs(const std::multimap<std::string, std::string> &cgi_args) {
    for (const auto &key_and_values : cgi_args)
        std::cout << key_and_values.first << " = " << key_and_values.second << '\n';
}

void ParseEscapedCommaSeparatedList(const std::string &escaped_text, std::vector<std::string> * const list) {
    list->clear();

    std::string unescaped_text;
    bool last_char_was_backslash(false);

    for (const auto ch : escaped_text) {
        if (last_char_was_backslash) {
            last_char_was_backslash = false;
            unescaped_text += ch;
        } else if (ch == '\\')
            last_char_was_backslash = true;
        else if (ch == ',') {
            list->emplace_back(unescaped_text);
            unescaped_text.clear();
        } else
            unescaped_text += ch;
    }

    if (unlikely(last_char_was_backslash))
        Error("weird escaped string ends in backslash \"" + escaped_text + "\"!");

    list->emplace_back(StringUtil::RightTrim(&unescaped_text, '\n'));
}

struct Translation {
    std::string index_, remaining_count_, language_code_, text_, category_, gnd_code_;
};

const std::string NO_GND_CODE("-1");

void ParseGetMissingLine(const std::string &line, Translation * const translation) {
    std::vector<std::string> parts;
    ParseEscapedCommaSeparatedList(line, &parts);
    if (unlikely(parts.size() != 5 and parts.size() != 6))
        Error("expected 5 or 6 parts, found \"" + line + "\"!");

    translation->index_           = parts[0];
    translation->remaining_count_ = parts[1];
    translation->language_code_   = parts[2];
    translation->text_            = parts[3];
    translation->category_        = parts[4];
    translation->gnd_code_        = (parts.size() == 5) ? NO_GND_CODE : parts[5];
}

void ParseTranslationsDbToolOutput(const std::string &output, std::vector<Translation> * const translations) {
    std::vector<std::string> lines;
    StringUtil::Split(output, '\n', &lines);

    for (const auto &line : lines) {
        Translation new_translation;
        ParseGetMissingLine(line, &new_translation);
        translations->emplace_back(new_translation);
    }
}

std::string GetCGIParameterOrDie(const std::multimap<std::string, std::string> &cgi_args,
                                 const std::string &parameter_name)
{
    const auto key_and_value(cgi_args.find(parameter_name));
    if (key_and_value == cgi_args.cend())
        Error("expected a(n) \"" + parameter_name + "\" parameter!");

    return key_and_value->second;
}

std::string GetCGIParameterOrEmptyString(const std::multimap<std::string, std::string> &cgi_args,
                                         const std::string &parameter_name)
{
    const auto key_and_value(cgi_args.find(parameter_name));
    if (key_and_value == cgi_args.cend())
        return "";

    return key_and_value->second;
}

void ParseTranslationsDbToolOutputAndGenerateNewDisplay(const std::string &output, const std::string &language_code,
                                                        const std::string &ixtheo_base_url)
{
    std::vector<Translation> translations;
    ParseTranslationsDbToolOutput(output, &translations);
    if (translations.empty()) {
        std::ifstream done_html("/var/lib/tuelib/translate_chainer/done_translating.html", std::ios::binary);
        std::cout << done_html.rdbuf();
    } else {
        std::map<std::string, std::vector<std::string>> names_to_values_map;
        names_to_values_map.emplace(std::make_pair(std::string("index"),
                                                   std::vector<std::string>{ translations.front().index_ }));
        names_to_values_map.emplace(std::make_pair(std::string("remaining_count"),
                                                   std::vector<std::string>{ translations.front().remaining_count_ }));
        names_to_values_map.emplace(std::make_pair(std::string("target_language_code"),
                                                   std::vector<std::string>{ language_code }));
        names_to_values_map.emplace(std::make_pair(std::string("ixtheo_base_url"),
                                                   std::vector<std::string>{ UrlUtil::UrlDecode(ixtheo_base_url) }));
        names_to_values_map.emplace(std::make_pair(std::string("category"),
                                                   std::vector<std::string>{ translations.front().category_ }));
        if (translations.front().gnd_code_ != NO_GND_CODE)
            names_to_values_map.emplace(std::make_pair(std::string("gnd_code"),
                                                       std::vector<std::string>{ translations.front().gnd_code_ }));

        std::vector<std::string> language_codes, example_texts, url_escaped_example_texts;
        for (const auto &translation : translations) {
            language_codes.emplace_back(translation.language_code_);
            example_texts.emplace_back(translation.text_);
            url_escaped_example_texts.emplace_back(UrlUtil::UrlEncode(translation.text_));
        }
        names_to_values_map.emplace(std::make_pair(std::string("language_code"), language_codes));
        names_to_values_map.emplace(std::make_pair(std::string("example_text"), example_texts));
        names_to_values_map.emplace(std::make_pair(std::string("url_escaped_example_text"),
                                                   url_escaped_example_texts));

        std::ifstream translate_html("/var/lib/tuelib/translate_chainer/translate.html", std::ios::binary);
        MiscUtil::ExpandTemplate(translate_html, std::cout, names_to_values_map);
    }
}

void GetMissing(const std::multimap<std::string, std::string> &cgi_args) {
    const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
    const std::string ixtheo_base_url(GetCGIParameterOrDie(cgi_args, "ixtheo_base_url"));

    const std::string GET_MISSING_COMMAND("/usr/local/bin/translation_db_tool get_missing " + language_code);
    std::string output;
    if (not ExecUtil::ExecSubcommandAndCaptureStdout(GET_MISSING_COMMAND, &output))
        Error("failed to execute \"" + GET_MISSING_COMMAND + "\" or it returned a non-zero exit code!");

    ParseTranslationsDbToolOutputAndGenerateNewDisplay(output, language_code, ixtheo_base_url);
}

void Insert(const std::multimap<std::string, std::string> &cgi_args) {
    const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
    const std::string translation(GetCGIParameterOrDie(cgi_args, "translation"));
    const std::string index(GetCGIParameterOrDie(cgi_args, "index"));
    const std::string gnd_code(GetCGIParameterOrEmptyString(cgi_args, "gnd_code"));

    if (translation.empty())
        return;

    std::string insert_command("/usr/local/bin/translation_db_tool insert '" + index);
    if (not gnd_code.empty())
        insert_command += "' '" + gnd_code;
    insert_command += "' " + language_code + " '" + translation + "'";

    std::string output;
    if (not ExecUtil::ExecSubcommandAndCaptureStdout(insert_command, &output))
        Error("failed to execute \"" + insert_command + "\" or it returned a non-zero exit code!");
}

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    try {
        std::multimap<std::string, std::string> cgi_args;
        WebUtil::GetAllCgiArgs(&cgi_args, argc, argv);

        if (cgi_args.size() == 2) {
            std::cout << "Content-Type: text/html; charset=utf-8\r\n\r\n";
            GetMissing(cgi_args);
        } else if (cgi_args.size() == 5) {
            const std::string language_code(GetCGIParameterOrDie(cgi_args, "language_code"));
            const std::string ixtheo_base_url(GetCGIParameterOrDie(cgi_args, "ixtheo_base_url"));
            std::cout << "Status: 302 Found\r\n";
            std::cout << "Location: /cgi-bin/translate_chainer?language_code=" << language_code
                      << "&ixtheo_base_url=" << ixtheo_base_url << "\r\n\r\n";
            Insert(cgi_args);
        } else
            Error("we should be called w/ either 1 or 5 CGI arguments!");
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the Apache License, Version 2.0, please send an email to
 * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
 * by the terms of the Apache License, Version 2.0.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * ***************************************************************************/

#include <collection.h>
#include <ppltasks.h>

#include "Python.h"
#include "Pythonrun.h"
#include "StdListener.h"

#include "pythonuwp.h"

using namespace Platform;
using namespace Platform::Collections;

bool GetPythonDebuggerParams(
    DWORD dwExceptionCode,
    wchar_t* debugCommand);

void OutputDebugTimeString(PCWSTR message);

void InitializePython()
{
    OutputDebugTimeString(L"Starting initialize");
    Py_Initialize();
    OutputDebugTimeString(L"Finished initialize");
}

void FinalizePython()
{
    Py_Finalize();
}

int RunPython(
    std::function<void(String^)> stdOutFunc,
    std::function<void(String^)> stdErrFunc,
    Vector<String^>^ argumentsVector)
{
    int result = -1;

    // _set_invalid_parameter_handler();
    // _CrtSetReportMode()

    if (InitStdListeners())
    {
        SetStdOutCallback(stdOutFunc);
        SetStdErrCallback(stdErrFunc);
    }

    bool GetPythonDebuggerParams(
        DWORD dwExceptionCode,
        wchar_t* debugCommand);

    wchar_t** args = (wchar_t**)malloc(sizeof(wchar_t*)*(argumentsVector->Size));

    for (unsigned int i = 0; i < argumentsVector->Size; i++)
    {
        args[i] = (wchar_t*)argumentsVector->GetAt(i)->Data();
    }

    OutputDebugTimeString(L"Starting Py_Main...");
    result = Py_Main(argumentsVector->Size, args);

    free(args);

    return result;
}

void PingPythonDebugger(
    unsigned int dwExceptionCode,
    ULONG_PTR * pArguments,
    unsigned int nArguments)
{
    concurrency::task<void> raiseDebuggerExceptionTask(concurrency::create_async([=] {
        // Try to get information back from debugger
        __try
        {
            OutputDebugTimeString(L"Starting exception...");
            RaiseException(dwExceptionCode, 0, nArguments, pArguments);
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            OutputDebugTimeString(L"finished exception.");
        }
    }));

    raiseDebuggerExceptionTask.wait();
}

void OutputDebugTimeString(PCWSTR message)
{
    time_t ltime;
    wchar_t timeBuf[256];

    time(&ltime);

    _wctime_s(timeBuf, sizeof(timeBuf) / sizeof(timeBuf[0]), &ltime);

    timeBuf[wcsnlen_s(timeBuf, sizeof(timeBuf) / sizeof(timeBuf[0])) - 1] = 0;

    OutputDebugString(timeBuf);
    OutputDebugString(L": ");
    OutputDebugString(message);
    OutputDebugString(L"\n");
}<commit_msg>Cleanup debug messages about Py_Initialize and debugger exceptions<commit_after>/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the Apache License, Version 2.0, please send an email to
 * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
 * by the terms of the Apache License, Version 2.0.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * ***************************************************************************/

#include <collection.h>
#include <ppltasks.h>

#include "Python.h"
#include "Pythonrun.h"
#include "StdListener.h"

#include "pythonuwp.h"

using namespace Platform;
using namespace Platform::Collections;

bool GetPythonDebuggerParams(
    DWORD dwExceptionCode,
    wchar_t* debugCommand);

void OutputDebugTimeString(PCWSTR message);

void InitializePython()
{
    OutputDebugTimeString(L"Starting Py_Initialize");
    Py_Initialize();
    OutputDebugTimeString(L"Finished Py_Initialize");
}

void FinalizePython()
{
    Py_Finalize();
}

int RunPython(
    std::function<void(String^)> stdOutFunc,
    std::function<void(String^)> stdErrFunc,
    Vector<String^>^ argumentsVector)
{
    int result = -1;

    // _set_invalid_parameter_handler();
    // _CrtSetReportMode()

    if (InitStdListeners())
    {
        SetStdOutCallback(stdOutFunc);
        SetStdErrCallback(stdErrFunc);
    }

    bool GetPythonDebuggerParams(
        DWORD dwExceptionCode,
        wchar_t* debugCommand);

    wchar_t** args = (wchar_t**)malloc(sizeof(wchar_t*)*(argumentsVector->Size));

    for (unsigned int i = 0; i < argumentsVector->Size; i++)
    {
        args[i] = (wchar_t*)argumentsVector->GetAt(i)->Data();
    }

    OutputDebugTimeString(L"Starting Py_Main...");
    result = Py_Main(argumentsVector->Size, args);

    free(args);

    return result;
}

void PingPythonDebugger(
    unsigned int dwExceptionCode,
    ULONG_PTR * pArguments,
    unsigned int nArguments)
{
    concurrency::task<void> raiseDebuggerExceptionTask(concurrency::create_async([=] {
        // Try to get information back from debugger
        __try
        {
            RaiseException(dwExceptionCode, 0, nArguments, pArguments);
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
        }
    }));

    raiseDebuggerExceptionTask.wait();
}

void OutputDebugTimeString(PCWSTR message)
{
    time_t ltime;
    wchar_t timeBuf[256];

    time(&ltime);

    _wctime_s(timeBuf, sizeof(timeBuf) / sizeof(timeBuf[0]), &ltime);

    timeBuf[wcsnlen_s(timeBuf, sizeof(timeBuf) / sizeof(timeBuf[0])) - 1] = 0;

    OutputDebugString(timeBuf);
    OutputDebugString(L": ");
    OutputDebugString(message);
    OutputDebugString(L"\n");
}<|endoftext|>


<commit_before>#include "../config.h"

#include <iostream>
#include "../Socket/Socket.hxx"
#include "../Log/TimestampLog.hxx"
#include <netinet/in.h>
#include <ev.h>

const static unsigned short listen_port = 5000;
const static bool connect_from_client_address = false;

std::auto_ptr<std::ostream> log;

void received_sigint(EV_P_ ev_signal *w, int revents) throw() {
	*log << "Received SIGINT, exiting\n" << std::flush;
	ev_break(EV_A_ EVUNLOOP_ALL);
}
void received_sigterm(EV_P_ ev_signal *w, int revents) throw() {
	*log << "Received SIGTERM, exiting\n" << std::flush;
	ev_break(EV_A_ EVUNLOOP_ALL);
}

static void listening_socket_ready_for_read(EV_P_ ev_io *w, int revents) {
	Socket* socket = reinterpret_cast<Socket*>( w->data );

	std::auto_ptr<SockAddr::SockAddr> client_addr;
	Socket client_socket = socket->accept(&client_addr);
	*log << "Connection established from " << client_addr->string() << "\n" << std::flush;

	std::auto_ptr<SockAddr::SockAddr> server_addr;
	server_addr = client_socket.getsockname();
	*log << "Connection established to   " << server_addr->string() << "\n" << std::flush;

	Socket server_socket = Socket::socket(AF_INET, SOCK_STREAM, 0);

	if( connect_from_client_address ) {
#if HAVE_DECL_IP_TRANSPARENT
		int value = 1;
		server_socket.setsockopt(SOL_IP, IP_TRANSPARENT, &value, sizeof(value)); // TODO: IPPROTO_IPV6
#endif
		server_socket.bind( *client_addr );
		*log << "Bound server socket\n" << std::flush;
	}

	server_socket.connect( *server_addr );
	*log << "Connected server socket\n" << std::flush;
}

int main(int argc, char* argv[]) {
	Socket s_listen = Socket::socket(AF_INET, SOCK_STREAM, 0);

	log.reset( new TimestampLog( std::cerr ) );

#if HAVE_DECL_IP_TRANSPARENT
	{
		int value = 1;
		s_listen.setsockopt(SOL_IP, IP_TRANSPARENT, &value, sizeof(value)); // TODO: IPPROTO_IPV6
	}
#endif

	std::auto_ptr<SockAddr::SockAddr> bind_addr(
		SockAddr::translate("0.0.0.0", listen_port) );

	s_listen.bind(*bind_addr);
	s_listen.listen(10);
	*log << "Listening on " << bind_addr->string() << "\n" << std::flush;

	{
		ev_signal ev_sigint_watcher;
		ev_signal_init( &ev_sigint_watcher, received_sigint, SIGINT);
		ev_signal_start( EV_DEFAULT_ &ev_sigint_watcher);
		ev_signal ev_sigterm_watcher;
		ev_signal_init( &ev_sigterm_watcher, received_sigterm, SIGTERM);
		ev_signal_start( EV_DEFAULT_ &ev_sigterm_watcher);

		ev_io e_listen;
		e_listen.data = &s_listen;
		ev_io_init( &e_listen, listening_socket_ready_for_read, s_listen, EV_READ );
		ev_io_start( EV_DEFAULT_ &e_listen );

		*log << "Setup done, starting event loop\n" << std::flush;
		ev_run(EV_DEFAULT_ 0);
	}

	*log << "Exiting...\n" << std::flush;
	return 0;
}
<commit_msg>Added getopts & parsing wrappers<commit_after>#include "../config.h"

#include <iostream>
#include <fstream>
#include <getopt.h>
#include <netinet/in.h>
#include <ev.h>
#include <sysexits.h>

#include "../Socket/Socket.hxx"
#include "../Log/TimestampLog.hxx"

static const int MAX_CONN_BACKLOG = 32;

std::string logfilename;
std::ofstream logfile;
std::auto_ptr<std::ostream> log;

std::auto_ptr<SockAddr::SockAddr> bind_addr_outgoing;

void received_sigint(EV_P_ ev_signal *w, int revents) throw() {
	*log << "Received SIGINT, exiting\n" << std::flush;
	ev_break(EV_A_ EVUNLOOP_ALL);
}
void received_sigterm(EV_P_ ev_signal *w, int revents) throw() {
	*log << "Received SIGTERM, exiting\n" << std::flush;
	ev_break(EV_A_ EVUNLOOP_ALL);
}

void received_sighup(EV_P_ ev_signal *w, int revents) throw() {
	*log << "Received SIGHUP, closing this logfile\n" << std::flush;
	logfile.close();
	logfile.open(logfilename.c_str(), std::ios_base::app | std::ios_base::out );
	*log << "Received SIGHUP, (re)opening this logfile\n" << std::flush;
}

static void listening_socket_ready_for_read(EV_P_ ev_io *w, int revents) {
	Socket* socket = reinterpret_cast<Socket*>( w->data );

	std::auto_ptr<SockAddr::SockAddr> client_addr;
	Socket client_socket = socket->accept(&client_addr);
	*log << "Connection established from " << client_addr->string() << "\n" << std::flush;

	std::auto_ptr<SockAddr::SockAddr> server_addr;
	server_addr = client_socket.getsockname();
	*log << "Connection established to   " << server_addr->string() << "\n" << std::flush;

	Socket server_socket = Socket::socket(AF_INET, SOCK_STREAM, 0);

	if( bind_addr_outgoing.get() == NULL ) {
		server_socket.bind( *bind_addr_outgoing );
		*log << "Bound server socket to " << bind_addr_outgoing->string()
		     << "\n" << std::flush;
	} else {
#if HAVE_DECL_IP_TRANSPARENT
		int value = 1;
		server_socket.setsockopt(SOL_IP, IP_TRANSPARENT, &value, sizeof(value)); // TODO: IPPROTO_IPV6
#endif
		server_socket.bind( *client_addr );
		*log << "Bound server socket to " << client_addr->string()
		     << "\n" << std::flush;
	}

	server_socket.connect( *server_addr );
	*log << "Connected server socket\n" << std::flush;
}

int main(int argc, char* argv[]) {
	// Defaults
	struct {
		bool fork;
		std::string pid_file;
		std::string bind_addr_listen;
		std::string bind_addr_outgoing;
	} options = {
		/* fork = */ true,
		/* pid_file = */ "",
		/* bind_addr_listen = */ "[0.0.0.0]:[5000]",
		/* bind_addr_outgoing = */ "[0.0.0.0]:[0]"
		};
	log.reset( new TimestampLog( std::cerr ) );

	{ // Parse options
		char optstring[] = "?hVfp:b:B:l:";
		struct option longopts[] = {
			{"help",			no_argument, NULL, '?'},
			{"version",			no_argument, NULL, 'V'},
			{"forgeground",		no_argument, NULL, 'f'},
			{"pid-file",		required_argument, NULL, 'p'},
			{"bind-listen",		required_argument, NULL, 'b'},
			{"bind-outgoing",	required_argument, NULL, 'B'},
			{"log",				required_argument, NULL, 'l'},
			{NULL, 0, 0, 0}
		};
		int longindex;
		int opt;
		while( (opt = getopt_long(argc, argv, optstring, longopts, &longindex)) != -1 ) {
			switch(opt) {
			case '?':
			case 'h':
				std::cerr <<
				//  >---------------------- Standard terminal width ---------------------------------<
					"Options:\n"
					"  -h -? --help                    Displays this help message and exits\n"
					"  -V --version                    Displays the version and exits\n"
					"  --foreground -f                 Don't fork into the background after init\n"
					"  --pid-file -p file              The file to write the PID to, especially\n"
					"                                  usefull when running as a daemon\n"
					"  --bind-listen -b host:port      Bind to the specified address for incomming\n"
					"                                  connections.\n"
					"                                  host and port resolving can be bypassed by\n"
					"                                  placing [] around them\n"
					"  --bind-outgoing -b host:port    Bind to the specified address for outgoing\n"
					"                                  connections.\n"
					"                                  host and port resolving can be bypassed by\n"
					"                                  placing [] around them\n"
					"  --log -l file                   Log to file\n"
					;
				exit(EX_USAGE);
			case 'V':
				std::cout << PACKAGE_STRING << "\n";
				exit(EX_OK);
			case 'f':
				options.fork = false;
				break;
			case 'p':
				options.pid_file = optarg;
				break;
			case 'b':
				options.bind_addr_listen = optarg;
				break;
			case 'B':
				options.bind_addr_outgoing = optarg;
				break;
			case 'l':
				logfilename = optarg;
				logfile.open(logfilename.c_str(), std::ios_base::app | std::ios_base::out );
				log.reset( new TimestampLog( logfile ) );
				break;
			}
		}
	}

	*log << "Parsed options, opening listening socket on "
	     << options.bind_addr_listen << "\n" << std::flush;

	Socket s_listen;
	{ // Open listening socket
		std::string host, port;

		/* Address format is
		 *   - hostname:portname
		 *   - [numeric ip]:portname
		 *   - hostname:[portnumber]
		 *   - [numeric ip]:[portnumber]
		 */
		size_t c = options.bind_addr_listen.rfind(":");
		if( c == std::string::npos ) {
			std::cerr << "Invalid bind string \"" << options.bind_addr_listen << "\": could not find ':'\n";
			exit(EX_DATAERR);
		}
		host = options.bind_addr_listen.substr(0, c);
		port = options.bind_addr_listen.substr(c+1);

		std::auto_ptr< boost::ptr_vector< SockAddr::SockAddr> > bind_sa
			= SockAddr::resolve( host, port, 0, SOCK_STREAM, 0);
		if( bind_sa->size() == 0 ) {
			std::cerr << "Can not bind to \"" << options.bind_addr_listen << "\": Could not resolve\n";
			exit(EX_DATAERR);
		} else if( bind_sa->size() > 1 ) {
			// TODO: allow this
			std::cerr << "Can not bind to \"" << options.bind_addr_listen << "\": Resolves to multiple entries:\n";
			for( typeof(bind_sa->begin()) i = bind_sa->begin(); i != bind_sa->end(); i++ ) {
				std::cerr << "  " << i->string() << "\n";
			}
			exit(EX_DATAERR);
		}
		s_listen = Socket::socket( (*bind_sa)[0].proto_family() , SOCK_STREAM, 0);
		s_listen.set_reuseaddr();
		s_listen.bind((*bind_sa)[0]);
		s_listen.listen(MAX_CONN_BACKLOG);

#if HAVE_DECL_IP_TRANSPARENT
		int value = 1;
		s_listen.setsockopt(SOL_IP, IP_TRANSPARENT, &value, sizeof(value)); // TODO: IPPROTO_IPV6
#endif

		*log << "Listening on " << (*bind_sa)[0].string() << "\n" << std::flush;
	}

	{ // Resolve client address
		std::string host, port;

		/* Address format is
		 *   - hostname:portname
		 *   - [numeric ip]:portname
		 *   - hostname:[portnumber]
		 *   - [numeric ip]:[portnumber]
		 */
		size_t c = options.bind_addr_outgoing.rfind(":");
		if( c == std::string::npos ) {
			std::cerr << "Invalid bind string \"" << options.bind_addr_outgoing << "\": could not find ':'\n";
			exit(EX_DATAERR);
		}
		host = options.bind_addr_outgoing.substr(0, c);
		port = options.bind_addr_outgoing.substr(c+1);

		std::auto_ptr< boost::ptr_vector< SockAddr::SockAddr> > bind_sa
			= SockAddr::resolve( host, port, 0, SOCK_STREAM, 0);
		if( bind_sa->size() == 0 ) {
			std::cerr << "Can not bind to \"" << options.bind_addr_outgoing << "\": Could not resolve\n";
			exit(EX_DATAERR);
		} else if( bind_sa->size() > 1 ) {
			// TODO: allow this
			std::cerr << "Can not bind to \"" << options.bind_addr_outgoing << "\": Resolves to multiple entries:\n";
			for( typeof(bind_sa->begin()) i = bind_sa->begin(); i != bind_sa->end(); i++ ) {
				std::cerr << "  " << i->string() << "\n";
			}
			exit(EX_DATAERR);
		}
		bind_addr_outgoing.reset( bind_sa->release(bind_sa->begin()).release() ); // Transfer ownership; TODO: this should be simpeler that double release()

		*log << "Outgoing connections will connect from "
		     << bind_addr_outgoing->string() << "\n" << std::flush;
	}

	{
		ev_signal ev_sigint_watcher;
		ev_signal_init( &ev_sigint_watcher, received_sigint, SIGINT);
		ev_signal_start( EV_DEFAULT_ &ev_sigint_watcher);
		ev_signal ev_sigterm_watcher;
		ev_signal_init( &ev_sigterm_watcher, received_sigterm, SIGTERM);
		ev_signal_start( EV_DEFAULT_ &ev_sigterm_watcher);

		ev_signal ev_sighup_watcher;
		ev_signal_init( &ev_sighup_watcher, received_sighup, SIGHUP);
		ev_signal_start( EV_DEFAULT_ &ev_sighup_watcher);

		ev_io e_listen;
		e_listen.data = &s_listen;
		ev_io_init( &e_listen, listening_socket_ready_for_read, s_listen, EV_READ );
		ev_io_start( EV_DEFAULT_ &e_listen );

		*log << "Setup done, starting event loop\n" << std::flush;
		ev_run(EV_DEFAULT_ 0);
	}

	*log << "Exiting...\n" << std::flush;
	return 0;
}
<|endoftext|>


<commit_before>const static char CVSId[] =
  "$Id$";

#include "corsika_test.h"
#include <boost/algorithm/string.hpp>

#include <corsika/RawCorsikaFile.h>
#include <string>
#include <vector>
#include <iostream>

using namespace std;
using namespace corsika;

TEST_GROUP(CorsikaTest);

namespace testRawCorsikaFileNS {
  void test_copy(string filename)
  {
    corsika::Corsika::RawFile rawUnthinnedFile;
    rawUnthinnedFile.Open(filename.c_str());

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedFile.GetNextBlock(block);
    rawUnthinnedFile.GetNextBlock(block);
    corsika::Corsika::RawFile rawUnthinnedFile2(rawUnthinnedFile);
    ENSURE_EQUAL(rawUnthinnedFile2.GetNextPosition(), rawUnthinnedFile.GetNextPosition());

    rawUnthinnedFile.GetNextBlock(block);
    rawUnthinnedFile2 = rawUnthinnedFile;
    ENSURE_EQUAL(rawUnthinnedFile2.GetNextPosition(), rawUnthinnedFile.GetNextPosition());
  }

  void test_basic(string filename)
  {
    corsika::Corsika::RawFile rawUnthinnedFile;
    rawUnthinnedFile.Open(filename.c_str());
    rawUnthinnedFile.Close();

    rawUnthinnedFile.Open(filename.c_str());
    ENSURE(rawUnthinnedFile.IsValid());

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedFile.GetNextBlock(block);
    ENSURE(block.IsRunHeader());

    rawUnthinnedFile.GetNextBlock(block);
    ENSURE(block.IsEventHeader());

    //ENSURE(rawUnthinnedFile.DiskBlockBuffer().fPaddingBeginning[0] == corsika::Corsika::NotThinned::kBytesPerBlock);
    //ENSURE(rawUnthinnedFile.DiskBlockBuffer().fPaddingEnd[0] == corsika::Corsika::NotThinned::kBytesPerBlock);

    int i = 0;
    while (rawUnthinnedFile.GetNextBlock(block) && i < 5000) {
      i += 1;
    }
    ENSURE_EQUAL(i, 4723);
  }

  void test_basic_stream(string filename)
  {
    Corsika::Compression c = Corsika::eNone;
    if (boost::algorithm::ends_with(filename, ".bz2")) {
      c = Corsika::eBZip2;
    }
    else if (boost::algorithm::ends_with(filename, ".gz")) {
      c = Corsika::eGZip;
    }

    ifstream f(filename);
    corsika::Corsika::RawFile rawUnthinnedStream(f, c);

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedStream.GetNextBlock(block);
    ENSURE(block.IsRunHeader());

    rawUnthinnedStream.GetNextBlock(block);
    ENSURE(block.IsEventHeader());

    //ENSURE(rawUnthinnedStream.DiskBlockBuffer().fPaddingBeginning[0] == corsika::Corsika::NotThinned::kBytesPerBlock);
    //ENSURE(rawUnthinnedStream.DiskBlockBuffer().fPaddingEnd[0] == corsika::Corsika::NotThinned::kBytesPerBlock);

    int i = 0;
    while (rawUnthinnedStream.GetNextBlock(block) && i < 5000) {
      i += 1;
    }
    ENSURE_EQUAL(i, 4723);
  }

}

using namespace testRawCorsikaFileNS;

TEST(testRawCorsikaFile)
{
  string dir(CORSIKA_TEST_DIR);
  test_copy(dir + string("/DAT000002-32"));
  vector<string> filenames;
  filenames.push_back("/DAT000002-32.bz2");
  filenames.push_back("/DAT000002-32");
  filenames.push_back("/DAT000002-32.gz");

  for (unsigned int i = 0; i != filenames.size(); ++i) {
    std::cout << "testing raw file " << filenames[i] << std::endl;
    test_basic(dir + filenames[i]);
    cout << "testing raw file " << filenames[i] << " from stream..." << endl;
    test_basic_stream(dir + filenames[i]);
  }
  //ENSURE(Verify<CloseTo>(p.GetCoordinates(CTrans), Triple(-1,0,0)));
}

TEST(testBlock)
{
  // This test makes an explicit check on the sizes of corsika blocks
  Corsika::Block<Corsika::NotThinned> not_thin_block;
  Corsika::Block<Corsika::NotThinned>::ParticleData particle;

  // one sub-block has 273 "words" each
  ENSURE_EQUAL(sizeof(float)*273, sizeof(not_thin_block));

  // All the classes in the union must have the same size
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsRunHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsRunTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsEventHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsEventTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsParticleBlock()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsCherenkovBlock()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsLongitudinalBlock()));

  Corsika::Block<Corsika::Thinned> thin_block;
  Corsika::Block<Corsika::Thinned>::ParticleData thin_particle;
  // comparing thinned blocks to their standard counterparts (only particle blocks change in size, the rest are zero-padded)
  ENSURE_EQUAL(sizeof(not_thin_block.AsRunHeader()), sizeof(thin_block.AsRunHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsRunTrailer()), sizeof(thin_block.AsRunTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsEventHeader()), sizeof(thin_block.AsEventHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsEventTrailer()), sizeof(thin_block.AsEventTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsLongitudinalBlock()), sizeof(thin_block.AsLongitudinalBlock()));
  ENSURE_EQUAL(sizeof(thin_block), sizeof(thin_block.AsParticleBlock()));
  ENSURE_EQUAL(sizeof(thin_block), sizeof(thin_block.AsCherenkovBlock()));
}

// Configure (x)emacs for this file ...
// Local Variables:
// mode:c++
// End:
<commit_msg>stupid old compilers<commit_after>const static char CVSId[] =
  "$Id$";

#include "corsika_test.h"
#include <boost/algorithm/string.hpp>

#include <corsika/RawCorsikaFile.h>
#include <string>
#include <vector>
#include <iostream>

using namespace std;
using namespace corsika;

TEST_GROUP(CorsikaTest);

namespace testRawCorsikaFileNS {
  void test_copy(string filename)
  {
    corsika::Corsika::RawFile rawUnthinnedFile;
    rawUnthinnedFile.Open(filename.c_str());

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedFile.GetNextBlock(block);
    rawUnthinnedFile.GetNextBlock(block);
    corsika::Corsika::RawFile rawUnthinnedFile2(rawUnthinnedFile);
    ENSURE_EQUAL(rawUnthinnedFile2.GetNextPosition(), rawUnthinnedFile.GetNextPosition());

    rawUnthinnedFile.GetNextBlock(block);
    rawUnthinnedFile2 = rawUnthinnedFile;
    ENSURE_EQUAL(rawUnthinnedFile2.GetNextPosition(), rawUnthinnedFile.GetNextPosition());
  }

  void test_basic(string filename)
  {
    corsika::Corsika::RawFile rawUnthinnedFile;
    rawUnthinnedFile.Open(filename.c_str());
    rawUnthinnedFile.Close();

    rawUnthinnedFile.Open(filename.c_str());
    ENSURE(rawUnthinnedFile.IsValid());

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedFile.GetNextBlock(block);
    ENSURE(block.IsRunHeader());

    rawUnthinnedFile.GetNextBlock(block);
    ENSURE(block.IsEventHeader());

    //ENSURE(rawUnthinnedFile.DiskBlockBuffer().fPaddingBeginning[0] == corsika::Corsika::NotThinned::kBytesPerBlock);
    //ENSURE(rawUnthinnedFile.DiskBlockBuffer().fPaddingEnd[0] == corsika::Corsika::NotThinned::kBytesPerBlock);

    int i = 0;
    while (rawUnthinnedFile.GetNextBlock(block) && i < 5000) {
      i += 1;
    }
    ENSURE_EQUAL(i, 4723);
  }

  void test_basic_stream(string filename)
  {
    Corsika::Compression c = Corsika::eNone;
    if (boost::algorithm::ends_with(filename, ".bz2")) {
      c = Corsika::eBZip2;
    }
    else if (boost::algorithm::ends_with(filename, ".gz")) {
      c = Corsika::eGZip;
    }

    ifstream f(filename.c_str());
    corsika::Corsika::RawFile rawUnthinnedStream(f, c);

    Corsika::Block<corsika::Corsika::NotThinned> block;
    rawUnthinnedStream.GetNextBlock(block);
    ENSURE(block.IsRunHeader());

    rawUnthinnedStream.GetNextBlock(block);
    ENSURE(block.IsEventHeader());

    //ENSURE(rawUnthinnedStream.DiskBlockBuffer().fPaddingBeginning[0] == corsika::Corsika::NotThinned::kBytesPerBlock);
    //ENSURE(rawUnthinnedStream.DiskBlockBuffer().fPaddingEnd[0] == corsika::Corsika::NotThinned::kBytesPerBlock);

    int i = 0;
    while (rawUnthinnedStream.GetNextBlock(block) && i < 5000) {
      i += 1;
    }
    ENSURE_EQUAL(i, 4723);
  }

}

using namespace testRawCorsikaFileNS;

TEST(testRawCorsikaFile)
{
  string dir(CORSIKA_TEST_DIR);
  test_copy(dir + string("/DAT000002-32"));
  vector<string> filenames;
  filenames.push_back("/DAT000002-32.bz2");
  filenames.push_back("/DAT000002-32");
  filenames.push_back("/DAT000002-32.gz");

  for (unsigned int i = 0; i != filenames.size(); ++i) {
    std::cout << "testing raw file " << filenames[i] << std::endl;
    test_basic(dir + filenames[i]);
    cout << "testing raw file " << filenames[i] << " from stream..." << endl;
    test_basic_stream(dir + filenames[i]);
  }
  //ENSURE(Verify<CloseTo>(p.GetCoordinates(CTrans), Triple(-1,0,0)));
}

TEST(testBlock)
{
  // This test makes an explicit check on the sizes of corsika blocks
  Corsika::Block<Corsika::NotThinned> not_thin_block;
  Corsika::Block<Corsika::NotThinned>::ParticleData particle;

  // one sub-block has 273 "words" each
  ENSURE_EQUAL(sizeof(float)*273, sizeof(not_thin_block));

  // All the classes in the union must have the same size
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsRunHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsRunTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsEventHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsEventTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsParticleBlock()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsCherenkovBlock()));
  ENSURE_EQUAL(sizeof(not_thin_block), sizeof(not_thin_block.AsLongitudinalBlock()));

  Corsika::Block<Corsika::Thinned> thin_block;
  Corsika::Block<Corsika::Thinned>::ParticleData thin_particle;
  // comparing thinned blocks to their standard counterparts (only particle blocks change in size, the rest are zero-padded)
  ENSURE_EQUAL(sizeof(not_thin_block.AsRunHeader()), sizeof(thin_block.AsRunHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsRunTrailer()), sizeof(thin_block.AsRunTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsEventHeader()), sizeof(thin_block.AsEventHeader()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsEventTrailer()), sizeof(thin_block.AsEventTrailer()));
  ENSURE_EQUAL(sizeof(not_thin_block.AsLongitudinalBlock()), sizeof(thin_block.AsLongitudinalBlock()));
  ENSURE_EQUAL(sizeof(thin_block), sizeof(thin_block.AsParticleBlock()));
  ENSURE_EQUAL(sizeof(thin_block), sizeof(thin_block.AsCherenkovBlock()));
}

// Configure (x)emacs for this file ...
// Local Variables:
// mode:c++
// End:
<|endoftext|>


<commit_before>// Copyright (c) 2019-2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/pivx/settings/settingsbittoolwidget.h"
#include "qt/pivx/settings/forms/ui_settingsbittoolwidget.h"
#include "qt/pivx/qtutils.h"

#include "guiutil.h"
#include "walletmodel.h"

#include "base58.h"
#include "bip38.h"
#include "init.h"
#include "wallet/wallet.h"
#include "askpassphrasedialog.h"

#include <string>
#include <vector>

SettingsBitToolWidget::SettingsBitToolWidget(PIVXGUI* _window, QWidget *parent) :
    PWidget(_window, parent),
    ui(new Ui::SettingsBitToolWidget)
{
    ui->setupUi(this);

    this->setStyleSheet(parent->styleSheet());

    /* Containers */
    setCssProperty(ui->left, "container");
    ui->left->setContentsMargins(10,10,10,10);

    /* Title */
    ui->labelTitle->setText(tr("BIP38 Tool"));
    setCssTitleScreen(ui->labelTitle);

    //Button Group
    ui->pushLeft->setText(tr("Encrypt"));
    setCssProperty(ui->pushLeft, "btn-check-left");
    ui->pushRight->setText(tr("Decrypt"));
    setCssProperty(ui->pushRight, "btn-check-right");
    ui->pushLeft->setChecked(true);

    // Subtitle
    ui->labelSubtitle1->setText("Encrypt your PIVX addresses (key pair actually) using BIP38 encryption.\nUsing this mechanism you can share your keys without middle-man risk, only need to store your passphrase safely.");
    setCssSubtitleScreen(ui->labelSubtitle1);

    // Key
    ui->labelSubtitleKey->setText(tr("Encrypted key"));
    setCssProperty(ui->labelSubtitleKey, "text-title");
    ui->lineEditKey->setPlaceholderText(tr("Enter a encrypted key"));
    initCssEditLine(ui->lineEditKey);

    // Passphrase
    ui->labelSubtitlePassphrase->setText(tr("Passphrase"));
    setCssProperty(ui->labelSubtitlePassphrase, "text-title");

    ui->lineEditPassphrase->setPlaceholderText(tr("Enter a passphrase "));
    initCssEditLine(ui->lineEditPassphrase);

    // Decrypt controls
    ui->labelSubtitleDecryptResult->setText(tr("Decrypted address result"));
    setCssProperty(ui->labelSubtitleDecryptResult, "text-title");
    ui->lineEditDecryptResult->setPlaceholderText(tr("Decrypted Address"));
    ui->lineEditDecryptResult->setAttribute(Qt::WA_MacShowFocusRect, 0);
    ui->lineEditDecryptResult->setReadOnly(true);
    initCssEditLine(ui->lineEditDecryptResult);

    // Buttons
    ui->pushButtonDecrypt->setText(tr("DECRYPT KEY"));
    setCssBtnPrimary(ui->pushButtonDecrypt);

    ui->pushButtonImport->setText(tr("Import Address"));
    setCssProperty(ui->pushButtonImport, "btn-text-primary");

    connect(ui->pushLeft, &QPushButton::clicked, [this](){onEncryptSelected(true);});
    connect(ui->pushRight,  &QPushButton::clicked, [this](){onEncryptSelected(false);});

    // Encrypt

    // Address
    ui->labelSubtitleAddress->setText(tr("PIVX address"));
    setCssProperty(ui->labelSubtitleAddress, "text-title");

    ui->addressIn_ENC->setPlaceholderText(tr("Enter address"));
    setCssProperty(ui->addressIn_ENC, "edit-primary-multi-book");
    ui->addressIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);
    setShadow(ui->addressIn_ENC);

    // Message
    ui->labelSubtitleMessage->setText(tr("Passphrase"));
    setCssProperty(ui->labelSubtitleMessage, "text-title");

    setCssProperty(ui->passphraseIn_ENC, "edit-primary");
    ui->passphraseIn_ENC->setPlaceholderText(tr("Enter passphrase"));
    setCssProperty(ui->passphraseIn_ENC,"edit-primary");
    setShadow(ui->passphraseIn_ENC);
    ui->passphraseIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);

    ui->labelSubtitleEncryptedKey->setText(tr("Encrypted Key"));
    setCssProperty(ui->labelSubtitleEncryptedKey, "text-title");
    ui->encryptedKeyOut_ENC->setPlaceholderText(tr("Encrypted key"));
    ui->encryptedKeyOut_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);
    ui->encryptedKeyOut_ENC->setReadOnly(true);
    initCssEditLine(ui->encryptedKeyOut_ENC);

    btnContact = ui->addressIn_ENC->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition);
    ui->pushButtonEncrypt->setText(tr("ENCRYPT"));
    ui->pushButtonClear->setText(tr("CLEAR ALL"));
    ui->pushButtonDecryptClear->setText(tr("CLEAR"));
    setCssBtnPrimary(ui->pushButtonEncrypt);
    setCssBtnSecondary(ui->pushButtonClear);
    setCssBtnSecondary(ui->pushButtonDecryptClear);

    ui->statusLabel_ENC->setStyleSheet("QLabel { color: transparent; }");
    ui->statusLabel_DEC->setStyleSheet("QLabel { color: transparent; }");

    connect(ui->pushButtonEncrypt, &QPushButton::clicked, this, &SettingsBitToolWidget::onEncryptKeyButtonENCClicked);
    connect(ui->pushButtonDecrypt, SIGNAL(clicked()), this, SLOT(onDecryptClicked()));
    connect(ui->pushButtonImport, SIGNAL(clicked()), this, SLOT(importAddressFromDecKey()));
    connect(btnContact, SIGNAL(triggered()), this, SLOT(onAddressesClicked()));
    connect(ui->pushButtonClear, &QPushButton::clicked, this, &SettingsBitToolWidget::onClearAll);
    connect(ui->pushButtonDecryptClear, SIGNAL(clicked()), this, SLOT(onClearDecrypt()));
}

void SettingsBitToolWidget::setAddress_ENC(const QString& address){
    ui->addressIn_ENC->setText(address);
    ui->passphraseIn_ENC->setFocus();
}

void SettingsBitToolWidget::onEncryptSelected(bool isEncr) {
    ui->stackedWidget->setCurrentIndex(isEncr);
}

QString specialChar = "\"@!#$%&'()*+,-./:;<=>?`{|}~^_[]\\";
QString validChar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + specialChar;
bool isValidPassphrase(QString strPassphrase, QString& strInvalid)
{
    for (int i = 0; i < strPassphrase.size(); i++) {
        if (!validChar.contains(strPassphrase[i], Qt::CaseSensitive)) {
            if (QString("\"'").contains(strPassphrase[i]))
                continue;

            strInvalid = strPassphrase[i];
            return false;
        }
    }

    return true;
}

void SettingsBitToolWidget::onEncryptKeyButtonENCClicked()
{
    if (!walletModel)
        return;

    QString qstrPassphrase = ui->passphraseIn_ENC->text();
    QString strInvalid;
    if (!isValidPassphrase(qstrPassphrase, strInvalid)) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered passphrase is invalid. ") + strInvalid + QString(" is not valid") + QString(" ") + tr("Allowed: 0-9,a-z,A-Z,") + specialChar);
        return;
    }

    CBitcoinAddress addr(ui->addressIn_ENC->text().toStdString());
    if (!addr.IsValid()) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    CKeyID keyID;
    if (!addr.GetKeyID(keyID)) {
        //ui->addressIn_ENC->setValid(false);
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true));
    if (!ctx.isValid()) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("Wallet unlock was cancelled."));
        return;
    }

    CKey key;
    if (!pwalletMain->GetKey(keyID, key)) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("Private key for the entered address is not available."));
        return;
    }

    std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed());
    ui->encryptedKeyOut_ENC->setText(QString::fromStdString(encryptedKey));

    ui->statusLabel_ENC->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_ENC->setText(QString("<nobr>") + tr("Address encrypted.") + QString("</nobr>"));
}

void SettingsBitToolWidget::onClearAll(){
    ui->addressIn_ENC->clear();
    ui->passphraseIn_ENC->clear();
    ui->encryptedKeyOut_ENC->clear();
    ui->statusLabel_ENC->clear();
    ui->addressIn_ENC->setFocus();
}

void SettingsBitToolWidget::onAddressesClicked(){
    int addressSize = walletModel->getAddressTableModel()->sizeRecv();
    if(addressSize == 0) {
        inform(tr("No addresses available, you can go to the receive screen and add some there!"));
        return;
    }

    int height = (addressSize <= 2) ? ui->addressIn_ENC->height() * ( 2 * (addressSize + 1 )) : ui->addressIn_ENC->height() * 4;
    int width = ui->containerAddressEnc->width();

    if(!menuContacts){
        menuContacts = new ContactsDropdown(
                width,
                height,
                this
        );
        menuContacts->setWalletModel(walletModel, AddressTableModel::Receive);
        connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label){
            setAddress_ENC(address);
        });

    }

    if(menuContacts->isVisible()){
        menuContacts->hide();
        return;
    }

    menuContacts->resizeList(width, height);
    menuContacts->setStyleSheet(this->styleSheet());
    menuContacts->adjustSize();

    QPoint pos = ui->containerAddressEnc->rect().bottomLeft();
    pos.setY(pos.y() + ui->containerAddressEnc->height());
    pos.setX(pos.x() + 10);
    menuContacts->move(pos);
    menuContacts->show();
}

void SettingsBitToolWidget::resizeMenu(){
    if(menuContacts && menuContacts->isVisible()){
        int width = ui->containerAddress->width();
        menuContacts->resizeList(width, menuContacts->height());
        menuContacts->resize(width, menuContacts->height());
        QPoint pos = ui->containerAddressEnc->rect().bottomLeft();
        pos.setY(pos.y() + ui->containerAddressEnc->height());
        pos.setX(pos.x() + 10);
        menuContacts->move(pos);
    }
}

void SettingsBitToolWidget::onClearDecrypt(){
    ui->lineEditKey->clear();
    ui->lineEditDecryptResult->clear();
    ui->lineEditPassphrase->clear();
    key = CKey();
}

void SettingsBitToolWidget::onDecryptClicked(){
    std::string strPassphrase = ui->lineEditPassphrase->text().toStdString();
    std::string strKey = ui->lineEditKey->text().toStdString();

    uint256 privKey;
    bool fCompressed;
    if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Failed to decrypt.") + QString(" ") + tr("Please check the key and passphrase and try again."));
        return;
    }

    key.Set(privKey.begin(), privKey.end(), fCompressed);
    CPubKey pubKey = key.GetPubKey();
    CBitcoinAddress address(pubKey.GetID());
    ui->lineEditDecryptResult->setText(QString::fromStdString(address.ToString()));
}

void SettingsBitToolWidget::importAddressFromDecKey(){
    WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true));
    if (!ctx.isValid()) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Wallet unlock was cancelled."));
        return;
    }

    CBitcoinAddress address(ui->lineEditDecryptResult->text().toStdString());
    CPubKey pubkey = key.GetPubKey();

    if (!address.IsValid() || !key.IsValid() || CBitcoinAddress(pubkey.GetID()).ToString() != address.ToString()) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Data Not Valid.") + QString(" ") + tr("Please try again."));
        return;
    }

    CKeyID vchAddress = pubkey.GetID();
    {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Please wait while key is imported"));

        pwalletMain->MarkDirty();
        pwalletMain->SetAddressBook(vchAddress, "", AddressBook::AddressBookPurpose::RECEIVE);

        // Don't throw error in case a key is already there
        if (pwalletMain->HaveKey(vchAddress)) {
            ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
            ui->statusLabel_DEC->setText(tr("Cannot import address, key already held by the wallet"));
            return;
        }

        pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;

        if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
            ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
            ui->statusLabel_DEC->setText(tr("Error adding key to the wallet"));
            return;
        }

        // whenever a key is imported, we need to scan the whole chain
        pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
        pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
    }

    ui->statusLabel_DEC->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_DEC->setText(tr("Successfully added pivate key to the wallet"));
}

void SettingsBitToolWidget::resizeEvent(QResizeEvent *event){
    resizeMenu();
    QWidget::resizeEvent(event);
}

SettingsBitToolWidget::~SettingsBitToolWidget()
{
    delete ui;
}
<commit_msg>Update settingsbittoolwidget.cpp<commit_after>// Copyright (c) 2019-2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/pivx/settings/settingsbittoolwidget.h"
#include "qt/pivx/settings/forms/ui_settingsbittoolwidget.h"
#include "qt/pivx/qtutils.h"

#include "guiutil.h"
#include "walletmodel.h"

#include "base58.h"
#include "bip38.h"
#include "init.h"
#include "wallet/wallet.h"
#include "askpassphrasedialog.h"

#include <string>
#include <vector>

SettingsBitToolWidget::SettingsBitToolWidget(PIVXGUI* _window, QWidget *parent) :
    PWidget(_window, parent),
    ui(new Ui::SettingsBitToolWidget)
{
    ui->setupUi(this);

    this->setStyleSheet(parent->styleSheet());

    /* Containers */
    setCssProperty(ui->left, "container");
    ui->left->setContentsMargins(10,10,10,10);

    /* Title */
    ui->labelTitle->setText(tr("BIP38 Tool"));
    setCssTitleScreen(ui->labelTitle);

    //Button Group
    ui->pushLeft->setText(tr("Encrypt"));
    setCssProperty(ui->pushLeft, "btn-check-left");
    ui->pushRight->setText(tr("Decrypt"));
    setCssProperty(ui->pushRight, "btn-check-right");
    ui->pushLeft->setChecked(true);

    // Subtitle
    ui->labelSubtitle1->setText("Encrypt your PIVX addresses (key pair actually) using BIP38 encryption.\nUsing this mechanism you can share your keys without middle-man risk, only need to store your passphrase safely.");
    setCssSubtitleScreen(ui->labelSubtitle1);

    // Key
    ui->labelSubtitleKey->setText(tr("Encrypted key"));
    setCssProperty(ui->labelSubtitleKey, "text-title");
    ui->lineEditKey->setPlaceholderText(tr("Enter a encrypted key"));
    initCssEditLine(ui->lineEditKey);

    // Passphrase
    ui->labelSubtitlePassphrase->setText(tr("Passphrase"));
    setCssProperty(ui->labelSubtitlePassphrase, "text-title");

    ui->lineEditPassphrase->setPlaceholderText(tr("Enter a passphrase "));
    initCssEditLine(ui->lineEditPassphrase);

    // Decrypt controls
    ui->labelSubtitleDecryptResult->setText(tr("Decrypted address result"));
    setCssProperty(ui->labelSubtitleDecryptResult, "text-title");
    ui->lineEditDecryptResult->setPlaceholderText(tr("Decrypted Address"));
    ui->lineEditDecryptResult->setAttribute(Qt::WA_MacShowFocusRect, 0);
    ui->lineEditDecryptResult->setReadOnly(true);
    initCssEditLine(ui->lineEditDecryptResult);

    // Buttons
    ui->pushButtonDecrypt->setText(tr("DECRYPT KEY"));
    setCssBtnPrimary(ui->pushButtonDecrypt);

    ui->pushButtonImport->setText(tr("Import Address"));
    setCssProperty(ui->pushButtonImport, "btn-text-primary");

    connect(ui->pushLeft, &QPushButton::clicked, [this](){onEncryptSelected(true);});
    connect(ui->pushRight,  &QPushButton::clicked, [this](){onEncryptSelected(false);});

    // Encrypt

    // Address
    ui->labelSubtitleAddress->setText(tr("PIVX address"));
    setCssProperty(ui->labelSubtitleAddress, "text-title");

    ui->addressIn_ENC->setPlaceholderText(tr("Enter address"));
    setCssProperty(ui->addressIn_ENC, "edit-primary-multi-book");
    ui->addressIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);
    setShadow(ui->addressIn_ENC);

    // Message
    ui->labelSubtitleMessage->setText(tr("Passphrase"));
    setCssProperty(ui->labelSubtitleMessage, "text-title");

    setCssProperty(ui->passphraseIn_ENC, "edit-primary");
    ui->passphraseIn_ENC->setPlaceholderText(tr("Enter passphrase"));
    setCssProperty(ui->passphraseIn_ENC,"edit-primary");
    setShadow(ui->passphraseIn_ENC);
    ui->passphraseIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);

    ui->labelSubtitleEncryptedKey->setText(tr("Encrypted Key"));
    setCssProperty(ui->labelSubtitleEncryptedKey, "text-title");
    ui->encryptedKeyOut_ENC->setPlaceholderText(tr("Encrypted key"));
    ui->encryptedKeyOut_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0);
    ui->encryptedKeyOut_ENC->setReadOnly(true);
    initCssEditLine(ui->encryptedKeyOut_ENC);

    btnContact = ui->addressIn_ENC->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition);
    ui->pushButtonEncrypt->setText(tr("ENCRYPT"));
    ui->pushButtonClear->setText(tr("CLEAR ALL"));
    ui->pushButtonDecryptClear->setText(tr("CLEAR"));
    setCssBtnPrimary(ui->pushButtonEncrypt);
    setCssBtnSecondary(ui->pushButtonClear);
    setCssBtnSecondary(ui->pushButtonDecryptClear);

    ui->statusLabel_ENC->setStyleSheet("QLabel { color: transparent; }");
    ui->statusLabel_DEC->setStyleSheet("QLabel { color: transparent; }");

    connect(ui->pushButtonEncrypt, &QPushButton::clicked, this, &SettingsBitToolWidget::onEncryptKeyButtonENCClicked);
    connect(ui->pushButtonDecrypt, SIGNAL(clicked()), this, SLOT(onDecryptClicked()));
    connect(ui->pushButtonImport, SIGNAL(clicked()), this, SLOT(importAddressFromDecKey()));
    connect(btnContact, SIGNAL(triggered()), this, SLOT(onAddressesClicked()));
    connect(ui->pushButtonClear, &QPushButton::clicked, this, &SettingsBitToolWidget::onClearAll);
    connect(ui->pushButtonDecryptClear, SIGNAL(clicked()), this, SLOT(onClearDecrypt()));
}

void SettingsBitToolWidget::setAddress_ENC(const QString& address){
    ui->addressIn_ENC->setText(address);
    ui->passphraseIn_ENC->setFocus();
}

void SettingsBitToolWidget::onEncryptSelected(bool isEncr) {
    ui->stackedWidget->setCurrentIndex(isEncr);
}

QString specialChar = "\"@!#$%&'()*+,-./:;<=>?`{|}~^_[]\\";
QString validChar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + specialChar;
bool isValidPassphrase(QString strPassphrase, QString& strInvalid)
{
    for (int i = 0; i < strPassphrase.size(); i++) {
        if (!validChar.contains(strPassphrase[i], Qt::CaseSensitive)) {
            if (QString("\"'").contains(strPassphrase[i]))
                continue;

            strInvalid = strPassphrase[i];
            return false;
        }
    }

    return true;
}

void SettingsBitToolWidget::onEncryptKeyButtonENCClicked()
{
    if (!walletModel)
        return;

    QString qstrPassphrase = ui->passphraseIn_ENC->text();
    QString strInvalid;
    if (!isValidPassphrase(qstrPassphrase, strInvalid)) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered passphrase is invalid. ") + strInvalid + QString(" is not valid") + QString(" ") + tr("Allowed: 0-9,a-z,A-Z,") + specialChar);
        return;
    }

    CBitcoinAddress addr(ui->addressIn_ENC->text().toStdString());
    if (!addr.IsValid()) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    CKeyID keyID;
    if (!addr.GetKeyID(keyID)) {
        //ui->addressIn_ENC->setValid(false);
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true));
    if (!ctx.isValid()) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("Wallet unlock was cancelled."));
        return;
    }

    CKey key;
    if (!pwalletMain->GetKey(keyID, key)) {
        ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_ENC->setText(tr("Private key for the entered address is not available."));
        return;
    }

    std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed());
    ui->encryptedKeyOut_ENC->setText(QString::fromStdString(encryptedKey));

    ui->statusLabel_ENC->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_ENC->setText(QString("<nobr>") + tr("Address encrypted.") + QString("</nobr>"));
}

void SettingsBitToolWidget::onClearAll(){
    ui->addressIn_ENC->clear();
    ui->passphraseIn_ENC->clear();
    ui->encryptedKeyOut_ENC->clear();
    ui->statusLabel_ENC->clear();
    ui->addressIn_ENC->setFocus();
}

void SettingsBitToolWidget::onAddressesClicked(){
    int addressSize = walletModel->getAddressTableModel()->sizeRecv();
    if(addressSize == 0) {
        inform(tr("No addresses available, you can go to the receive screen and add some there!"));
        return;
    }

    int height = (addressSize <= 2) ? ui->addressIn_ENC->height() * ( 2 * (addressSize + 1 )) : ui->addressIn_ENC->height() * 4;
    int width = ui->containerAddressEnc->width();

    if(!menuContacts){
        menuContacts = new ContactsDropdown(
                width,
                height,
                this
        );
        menuContacts->setWalletModel(walletModel, AddressTableModel::Receive);
        connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label){
            setAddress_ENC(address);
        });

    }

    if(menuContacts->isVisible()){
        menuContacts->hide();
        return;
    }

    menuContacts->resizeList(width, height);
    menuContacts->setStyleSheet(this->styleSheet());
    menuContacts->adjustSize();

    QPoint pos = ui->containerAddressEnc->rect().bottomLeft();
    pos.setY(pos.y() + ui->containerAddressEnc->height());
    pos.setX(pos.x() + 10);
    menuContacts->move(pos);
    menuContacts->show();
}

void SettingsBitToolWidget::resizeMenu(){
    if(menuContacts && menuContacts->isVisible()){
        int width = ui->containerAddress->width();
        menuContacts->resizeList(width, menuContacts->height());
        menuContacts->resize(width, menuContacts->height());
        QPoint pos = ui->containerAddressEnc->rect().bottomLeft();
        pos.setY(pos.y() + ui->containerAddressEnc->height());
        pos.setX(pos.x() + 10);
        menuContacts->move(pos);
    }
}

void SettingsBitToolWidget::onClearDecrypt(){
    ui->lineEditKey->clear();
    ui->lineEditDecryptResult->clear();
    ui->lineEditPassphrase->clear();
    key = CKey();
}

void SettingsBitToolWidget::onDecryptClicked(){
    std::string strPassphrase = ui->lineEditPassphrase->text().toStdString();
    std::string strKey = ui->lineEditKey->text().toStdString();

    uint256 privKey;
    bool fCompressed;
    if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Failed to decrypt.") + QString(" ") + tr("Please check the key and passphrase and try again."));
        return;
    }

    key.Set(privKey.begin(), privKey.end(), fCompressed);
    CPubKey pubKey = key.GetPubKey();
    CBitcoinAddress address(pubKey.GetID());
    ui->lineEditDecryptResult->setText(QString::fromStdString(address.ToString()));
}

void SettingsBitToolWidget::importAddressFromDecKey(){
    WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true));
    if (!ctx.isValid()) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Wallet unlock was cancelled."));
        return;
    }

    CBitcoinAddress address(ui->lineEditDecryptResult->text().toStdString());
    CPubKey pubkey = key.GetPubKey();

    if (!address.IsValid() || !key.IsValid() || CBitcoinAddress(pubkey.GetID()).ToString() != address.ToString()) {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Data Not Valid.") + QString(" ") + tr("Please try again."));
        return;
    }

    CKeyID vchAddress = pubkey.GetID();
    {
        ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_DEC->setText(tr("Please wait while key is imported"));

        pwalletMain->MarkDirty();
        pwalletMain->SetAddressBook(vchAddress, "", AddressBook::AddressBookPurpose::RECEIVE);

        // Don't throw error in case a key is already there
        if (pwalletMain->HaveKey(vchAddress)) {
            ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
            ui->statusLabel_DEC->setText(tr("Cannot import address, key already held by the wallet"));
            return;
        }

        pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;

        if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
            ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }");
            ui->statusLabel_DEC->setText(tr("Error adding key to the wallet"));
            return;
        }

        // whenever a key is imported, we need to scan the whole chain
        pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
        pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
    }

    ui->statusLabel_DEC->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_DEC->setText(tr("Successfully added private key to the wallet"));
}

void SettingsBitToolWidget::resizeEvent(QResizeEvent *event){
    resizeMenu();
    QWidget::resizeEvent(event);
}

SettingsBitToolWidget::~SettingsBitToolWidget()
{
    delete ui;
}
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/***************************************************************************
  Socket operations

***************************************************************************/
#include "ts/ink_platform.h"
#include "ts/ink_assert.h"
#include "ts/ink_string.h"
#include "ts/ink_inet.h"

//
// Compilation options
//

// #define CHECK_PLAUSIBILITY_OF_SOCKADDR

#ifdef CHECK_PLAUSIBILITY_OF_SOCKADDR
#define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l) check_plausible_sockaddr(_n, _f, _n)
inline void
check_valid_sockaddr(sockaddr *sa, char *file, int line)
{
  sockaddr_in *si     = (sockaddr_in *)sa;
  unsigned short port = ntohs(si->sin_port);
  unsigned short addr = ntohl(si->sin_addr.s_addr);

  if (port > 20000) {
    cerr << "[byteordering] In " << file << ", line " << line << " the IP port ";
    cerr << "was found to be " << port << "(in host byte order).\n";
    cerr << "[byteordering] This seems inplausible, so check for byte order problems\n";
  }
}
#else
#define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l)
#endif

int
safe_setsockopt(int s, int level, int optname, char *optval, int optlevel)
{
  int r;
  do {
    r = setsockopt(s, level, optname, optval, optlevel);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getsockopt(int s, int level, int optname, char *optval, int *optlevel)
{
  int r;
  do {
    r = getsockopt(s, level, optname, optval, (socklen_t *)optlevel);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_fcntl(int fd, int cmd, int arg)
{
  int r = 0;
  do {
    r = fcntl(fd, cmd, arg);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_set_fl(int fd, int arg)
{
  int flags = safe_fcntl(fd, F_GETFL, 0);
  if (flags < 0)
    return flags;
  flags |= arg;
  flags = safe_fcntl(fd, F_SETFL, flags);
  return flags;
}

int
safe_clr_fl(int fd, int arg)
{
  int flags = safe_fcntl(fd, F_GETFL, 0);
  if (flags < 0)
    return flags;
  flags &= ~arg;
  flags = safe_fcntl(fd, F_SETFL, flags);
  return flags;
}

int
safe_nonblocking(int fd)
{
  return safe_set_fl(fd, O_NONBLOCK);
}

int
safe_blocking(int fd)
{
  return safe_clr_fl(fd, O_NONBLOCK);
}

int
write_ready(int fd, int timeout_msec)
{
  struct pollfd p;
  p.events = POLLOUT;
  p.fd     = fd;
  int r    = poll(&p, 1, timeout_msec);
  if (r <= 0)
    return r;
  if (p.revents & (POLLERR | POLLNVAL))
    return -1;
  if (p.revents & (POLLOUT | POLLHUP))
    return 1;
  return 0;
}

int
read_ready(int fd, int timeout_msec)
{
  struct pollfd p;
  p.events = POLLIN;
  p.fd     = fd;
  int r    = poll(&p, 1, timeout_msec);
  if (r <= 0)
    return r;
  if (p.revents & (POLLERR | POLLNVAL))
    return -1;
  if (p.revents & (POLLIN | POLLHUP))
    return 1;
  return 0;
}

int
safe_ioctl(int fd, int request, char *arg)
{
  int r = -1;
  do {
    r = ioctl(fd, request, arg);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_bind(int s, struct sockaddr const *name, int namelen)
{
  int r;
  CHECK_PLAUSIBLE_SOCKADDR(name, __FILE__, __LINE__);
  do {
    r = bind(s, name, namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_listen(int s, int backlog)
{
  int r;
  do {
    r = listen(s, backlog);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getsockname(int s, struct sockaddr *name, int *namelen)
{
  int r;
  do {
    r = getsockname(s, name, (socklen_t *)namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getpeername(int s, struct sockaddr *name, int *namelen)
{
  int r;
  do {
    r = getpeername(s, name, (socklen_t *)namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

char
fd_read_char(int fd)
{
  char c;
  int r;
  do {
    r = read(fd, &c, 1);
    if (r > 0)
      return c;
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  perror("fd_read_char");
  ink_assert(!"fd_read_char");
  return c;
}

int
fd_read_line(int fd, char *s, int len)
{
  char c;
  int numread = 0, r;
  // char *buf = s;
  do {
    do
      r = read(fd, &c, 1);
    while (r < 0 && (errno == EAGAIN || errno == EINTR));

    if (r <= 0 && numread)
      break;

    if (r <= 0)
      return r;

    if (c == '\n')
      break;

    s[numread++] = c;
  } while (numread < len - 1);

  s[numread] = 0;
  return numread;
}

int
close_socket(int s)
{
  return close(s);
}

int
write_socket(int s, const char *buffer, int length)
{
  return write(s, (const void *)buffer, length);
}

int
read_socket(int s, char *buffer, int length)
{
  return read(s, (void *)buffer, length);
}

int
bind_unix_domain_socket(const char *path, mode_t mode)
{
  int sockfd;
  struct sockaddr_un sockaddr;
  socklen_t socklen;

  (void)unlink(path);

  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd < 0) {
    return sockfd;
  }

  ink_zero(sockaddr);
  sockaddr.sun_family = AF_UNIX;
  ink_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path));

#if defined(darwin) || defined(freebsd)
  socklen = sizeof(struct sockaddr_un);
#else
  socklen = strlen(sockaddr.sun_path) + sizeof(sockaddr.sun_family);
#endif

  safe_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, SOCKOPT_ON, sizeof(int));
  safe_fcntl(sockfd, F_SETFD, FD_CLOEXEC);

  if (bind(sockfd, (struct sockaddr *)&sockaddr, socklen) < 0) {
    goto fail;
  }

  if (chmod(path, mode) < 0) {
    goto fail;
  }

  if (listen(sockfd, 5) < 0) {
    goto fail;
  }

  return sockfd;

fail:
  int errsav = errno;
  close(sockfd);
  errno = errsav;
  return -1;
}
<commit_msg>TS-4779: Fix CID 1361961 - Check return value on safe_fcntl()<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/***************************************************************************
  Socket operations

***************************************************************************/
#include "ts/ink_platform.h"
#include "ts/ink_assert.h"
#include "ts/ink_string.h"
#include "ts/ink_inet.h"

//
// Compilation options
//

// #define CHECK_PLAUSIBILITY_OF_SOCKADDR

#ifdef CHECK_PLAUSIBILITY_OF_SOCKADDR
#define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l) check_plausible_sockaddr(_n, _f, _n)
inline void
check_valid_sockaddr(sockaddr *sa, char *file, int line)
{
  sockaddr_in *si     = (sockaddr_in *)sa;
  unsigned short port = ntohs(si->sin_port);
  unsigned short addr = ntohl(si->sin_addr.s_addr);

  if (port > 20000) {
    cerr << "[byteordering] In " << file << ", line " << line << " the IP port ";
    cerr << "was found to be " << port << "(in host byte order).\n";
    cerr << "[byteordering] This seems inplausible, so check for byte order problems\n";
  }
}
#else
#define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l)
#endif

int
safe_setsockopt(int s, int level, int optname, char *optval, int optlevel)
{
  int r;
  do {
    r = setsockopt(s, level, optname, optval, optlevel);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getsockopt(int s, int level, int optname, char *optval, int *optlevel)
{
  int r;
  do {
    r = getsockopt(s, level, optname, optval, (socklen_t *)optlevel);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_fcntl(int fd, int cmd, int arg)
{
  int r = 0;
  do {
    r = fcntl(fd, cmd, arg);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_set_fl(int fd, int arg)
{
  int flags = safe_fcntl(fd, F_GETFL, 0);
  if (flags < 0)
    return flags;
  flags |= arg;
  flags = safe_fcntl(fd, F_SETFL, flags);
  return flags;
}

int
safe_clr_fl(int fd, int arg)
{
  int flags = safe_fcntl(fd, F_GETFL, 0);
  if (flags < 0)
    return flags;
  flags &= ~arg;
  flags = safe_fcntl(fd, F_SETFL, flags);
  return flags;
}

int
safe_nonblocking(int fd)
{
  return safe_set_fl(fd, O_NONBLOCK);
}

int
safe_blocking(int fd)
{
  return safe_clr_fl(fd, O_NONBLOCK);
}

int
write_ready(int fd, int timeout_msec)
{
  struct pollfd p;
  p.events = POLLOUT;
  p.fd     = fd;
  int r    = poll(&p, 1, timeout_msec);
  if (r <= 0)
    return r;
  if (p.revents & (POLLERR | POLLNVAL))
    return -1;
  if (p.revents & (POLLOUT | POLLHUP))
    return 1;
  return 0;
}

int
read_ready(int fd, int timeout_msec)
{
  struct pollfd p;
  p.events = POLLIN;
  p.fd     = fd;
  int r    = poll(&p, 1, timeout_msec);
  if (r <= 0)
    return r;
  if (p.revents & (POLLERR | POLLNVAL))
    return -1;
  if (p.revents & (POLLIN | POLLHUP))
    return 1;
  return 0;
}

int
safe_ioctl(int fd, int request, char *arg)
{
  int r = -1;
  do {
    r = ioctl(fd, request, arg);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_bind(int s, struct sockaddr const *name, int namelen)
{
  int r;
  CHECK_PLAUSIBLE_SOCKADDR(name, __FILE__, __LINE__);
  do {
    r = bind(s, name, namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_listen(int s, int backlog)
{
  int r;
  do {
    r = listen(s, backlog);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getsockname(int s, struct sockaddr *name, int *namelen)
{
  int r;
  do {
    r = getsockname(s, name, (socklen_t *)namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

int
safe_getpeername(int s, struct sockaddr *name, int *namelen)
{
  int r;
  do {
    r = getpeername(s, name, (socklen_t *)namelen);
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  return r;
}

char
fd_read_char(int fd)
{
  char c;
  int r;
  do {
    r = read(fd, &c, 1);
    if (r > 0)
      return c;
  } while (r < 0 && (errno == EAGAIN || errno == EINTR));
  perror("fd_read_char");
  ink_assert(!"fd_read_char");
  return c;
}

int
fd_read_line(int fd, char *s, int len)
{
  char c;
  int numread = 0, r;
  // char *buf = s;
  do {
    do
      r = read(fd, &c, 1);
    while (r < 0 && (errno == EAGAIN || errno == EINTR));

    if (r <= 0 && numread)
      break;

    if (r <= 0)
      return r;

    if (c == '\n')
      break;

    s[numread++] = c;
  } while (numread < len - 1);

  s[numread] = 0;
  return numread;
}

int
close_socket(int s)
{
  return close(s);
}

int
write_socket(int s, const char *buffer, int length)
{
  return write(s, (const void *)buffer, length);
}

int
read_socket(int s, char *buffer, int length)
{
  return read(s, (void *)buffer, length);
}

int
bind_unix_domain_socket(const char *path, mode_t mode)
{
  int sockfd;
  struct sockaddr_un sockaddr;
  socklen_t socklen;

  (void)unlink(path);

  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd < 0) {
    return sockfd;
  }

  ink_zero(sockaddr);
  sockaddr.sun_family = AF_UNIX;
  ink_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path));

#if defined(darwin) || defined(freebsd)
  socklen = sizeof(struct sockaddr_un);
#else
  socklen = strlen(sockaddr.sun_path) + sizeof(sockaddr.sun_family);
#endif

  if (safe_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, SOCKOPT_ON, sizeof(int)) < 0) {
    goto fail;
  }

  if (safe_fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
    goto fail;
  }

  if (bind(sockfd, (struct sockaddr *)&sockaddr, socklen) < 0) {
    goto fail;
  }

  if (chmod(path, mode) < 0) {
    goto fail;
  }

  if (listen(sockfd, 5) < 0) {
    goto fail;
  }

  return sockfd;

fail:
  int errsav = errno;
  close(sockfd);
  errno = errsav;
  return -1;
}
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>

#include <pdal/FileUtils.hpp>
#include "Support.hpp"

using namespace pdal;

BOOST_AUTO_TEST_SUITE(FileUtilsTest)

BOOST_AUTO_TEST_CASE(test_file_ops)
{
    std::string tmp1 = "unittest1.tmp";
    std::string tmp2 = "unittest2.tmp";

    // first, clean up from any previous test run
    FileUtils::deleteFile(tmp1);
    FileUtils::deleteFile(tmp2);
    BOOST_CHECK(FileUtils::fileExists(tmp1)==false);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==false);

    // write test
    std::ostream* ostr = FileUtils::createFile(tmp1);
    *ostr << "yow";
    FileUtils::closeFile(ostr);

    BOOST_CHECK(FileUtils::fileExists(tmp1)==true);
    BOOST_CHECK(FileUtils::fileSize(tmp1)==3);

    // rename test
    FileUtils::renameFile(tmp2,tmp1);
    BOOST_CHECK(FileUtils::fileExists(tmp1)==false);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==true);

    // read test
    std::istream* istr = FileUtils::openFile(tmp2);
    std::string yow;
    *istr >> yow;
    FileUtils::closeFile(istr);
    BOOST_CHECK(yow=="yow");

    // delete test
    FileUtils::deleteFile(tmp2);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==false);
}

BOOST_AUTO_TEST_CASE(test_getcwd)
{
#if 0
    // this is hardcoded for mpg's environment
    const std::string cwd = FileUtils::getcwd();
    BOOST_CHECK(cwd == "D:/dev/pdal/test/unit/");
#endif

    return;
}

#ifdef PDAL_COMPILER_MSVC
static const std::string drive = "A:";
#else
static const std::string drive = "";
#endif

BOOST_AUTO_TEST_CASE(test_toAbsolutePath)
{
    using namespace std;

    const string root = FileUtils::getcwd();

    // check 1-arg version: make absolute when file is relative, via current working dir
    const string a = FileUtils::toAbsolutePath("foo.txt");
    BOOST_CHECK_EQUAL(a, root + "foo.txt");

    // check 1-arg version: make absolute when file is already absolute
    const string b = FileUtils::toAbsolutePath(drive + "/baz/foo.txt");
    BOOST_CHECK_EQUAL(b, drive + "/baz/foo.txt");

    // check 2-arg version: make absolute when file relative, via given base
    const string c = FileUtils::toAbsolutePath("foo.txt", drive + "/a/b/c/d");
    BOOST_CHECK_EQUAL(c, drive + "/a/b/c/d/foo.txt");

    // check 2-arg version: make absolute when file is relative, via given base (which isn't absolute)
    const string d = FileUtils::toAbsolutePath("foo.txt", "x/y/z");
    BOOST_CHECK_EQUAL(d, root + "x/y/z/" + "foo.txt");

    // check 1-arg version: make absolute when file is already absolute
    const string e = FileUtils::toAbsolutePath(drive+"/baz/foo.txt", drive+"/a/b/c/d");
    BOOST_CHECK_EQUAL(e, drive + "/baz/foo.txt");

    return;
}

BOOST_AUTO_TEST_CASE(test_getDirectory)
{
    // test absolute case
    const std::string a = FileUtils::getDirectory(drive + "/a/b/foo.txt");
    BOOST_CHECK_EQUAL(a, drive + "/a/b/");

    // test relative case
    const std::string b = FileUtils::getDirectory("a/b/foo.txt");
    BOOST_CHECK_EQUAL(b, "a/b/");

    return;
}

BOOST_AUTO_TEST_CASE(test_isAbsolute)
{
    // test absolute case
    const bool a = FileUtils::isAbsolutePath(drive + "/a/b/foo.txt");
    BOOST_CHECK(a);

    // test relative case
    const bool b = FileUtils::isAbsolutePath("a/b/foo.txt");
    BOOST_CHECK(!b);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>fix windows paths issues<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>

#include <pdal/FileUtils.hpp>
#include "Support.hpp"

using namespace pdal;

BOOST_AUTO_TEST_SUITE(FileUtilsTest)

BOOST_AUTO_TEST_CASE(test_file_ops)
{
    std::string tmp1 = "unittest1.tmp";
    std::string tmp2 = "unittest2.tmp";

    // first, clean up from any previous test run
    FileUtils::deleteFile(tmp1);
    FileUtils::deleteFile(tmp2);
    BOOST_CHECK(FileUtils::fileExists(tmp1)==false);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==false);

    // write test
    std::ostream* ostr = FileUtils::createFile(tmp1);
    *ostr << "yow";
    FileUtils::closeFile(ostr);

    BOOST_CHECK(FileUtils::fileExists(tmp1)==true);
    BOOST_CHECK(FileUtils::fileSize(tmp1)==3);

    // rename test
    FileUtils::renameFile(tmp2,tmp1);
    BOOST_CHECK(FileUtils::fileExists(tmp1)==false);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==true);

    // read test
    std::istream* istr = FileUtils::openFile(tmp2);
    std::string yow;
    *istr >> yow;
    FileUtils::closeFile(istr);
    BOOST_CHECK(yow=="yow");

    // delete test
    FileUtils::deleteFile(tmp2);
    BOOST_CHECK(FileUtils::fileExists(tmp2)==false);
}

BOOST_AUTO_TEST_CASE(test_getcwd)
{
#if 0
    // this is hardcoded for mpg's environment
    const std::string cwd = FileUtils::getcwd();
    BOOST_CHECK(cwd == "D:/dev/pdal/test/unit/");
#endif

    return;
}

#ifdef PDAL_COMPILER_MSVC
static const std::string drive = "A:";
#else
static const std::string drive = "";
#endif

static std::string normalize(const std::string p)
{
    return Support::replaceAll(p, "\\", "/");
}

static void compare_paths(const std::string a, const std::string b)
{
    BOOST_CHECK_EQUAL(normalize(a), normalize(b));
}

BOOST_AUTO_TEST_CASE(test_toAbsolutePath)
{
    using namespace std;

    const string root = FileUtils::getcwd();

    // check 1-arg version: make absolute when file is relative, via current working dir
    const string a = FileUtils::toAbsolutePath("foo.txt");
    compare_paths(a, root + "foo.txt");

    // check 1-arg version: make absolute when file is already absolute
    const string b = FileUtils::toAbsolutePath(drive + "/baz/foo.txt");
    compare_paths(b, drive + "/baz/foo.txt");

    // check 2-arg version: make absolute when file relative, via given base
    const string c = FileUtils::toAbsolutePath("foo.txt", drive + "/a/b/c/d");
    compare_paths(c, drive + "/a/b/c/d/foo.txt");

    // check 2-arg version: make absolute when file is relative, via given base (which isn't absolute)
    const string d = FileUtils::toAbsolutePath("foo.txt", "x/y/z");
    compare_paths(d, root + "x/y/z/" + "foo.txt");

    // check 1-arg version: make absolute when file is already absolute
    const string e = FileUtils::toAbsolutePath(drive+"/baz/foo.txt", drive+"/a/b/c/d");
    compare_paths(e, drive + "/baz/foo.txt");

    return;
}

BOOST_AUTO_TEST_CASE(test_getDirectory)
{
    // test absolute case
    const std::string a = FileUtils::getDirectory(drive + "/a/b/foo.txt");
    compare_paths(a, drive + "/a/b/");

    // test relative case
    const std::string b = FileUtils::getDirectory("a/b/foo.txt");
    compare_paths(b, "a/b/");

    return;
}

BOOST_AUTO_TEST_CASE(test_isAbsolute)
{
    // test absolute case
    const bool a = FileUtils::isAbsolutePath(drive + "/a/b/foo.txt");
    BOOST_CHECK(a);

    // test relative case
    const bool b = FileUtils::isAbsolutePath("a/b/foo.txt");
    BOOST_CHECK(!b);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>