<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/io/imagewriterutil.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/fileextension.h>
#include <inviwo/core/util/filedialog.h>
#include <inviwo/core/util/dialogfactory.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/io/datawriter.h>
#include <inviwo/core/io/datawriterfactory.h>

namespace inviwo {

namespace util {

void util::saveLayer(const Layer& layer, const std::string& path, const FileExtension& extension) {
    auto factory = InviwoApplication::getPtr()->getDataWriterFactory();

    auto writer = std::shared_ptr<DataWriterType<Layer>>(
        factory->getWriterForTypeAndExtension<Layer>(extension));

    if (!writer) {
        // could not find a reader for the given extension, extension might be invalid
        // try to get reader for the extension extracted from the file name, i.e. path
        const auto ext = filesystem::getFileExtension(path);
        writer = std::shared_ptr<DataWriterType<Layer>>(
            factory->getWriterForTypeAndExtension<Layer>(ext));
        if (!writer) {
            LogInfoCustom(
                "ImageWriterUtil",
                "Could not find a writer for the specified file extension (\"" << ext << "\")");
            return;
        }
    }

    try {
        writer->setOverwrite(true);
        writer->writeData(&layer, path);
        LogInfoCustom("ImageWriterUtil", "Canvas layer exported to disk: " << path);
    } catch (DataWriterException const& e) {
        LogErrorCustom("ImageWriterUtil", e.getMessage());
    }
}

IVW_CORE_API void saveLayer(const Layer& layer) {
    auto fileDialog = util::dynamic_unique_ptr_cast<FileDialog>(
        InviwoApplication::getPtr()->getDialogFactory()->create("FileDialog"));
    if (!fileDialog) {
        return;
    }
    fileDialog->setTitle("Save Layer to File...");
    fileDialog->setAcceptMode(AcceptMode::Save);
    fileDialog->setFileMode(FileMode::AnyFile);

    auto writerFactory = InviwoApplication::getPtr()->getDataWriterFactory();
    fileDialog->addExtensions(writerFactory->getExtensionsForType<Layer>());

    if (fileDialog->show()) {
        saveLayer(layer, fileDialog->getSelectedFile(), fileDialog->getSelectedFileExtension());
    }
}

} // namespace

} // namespace

<commit_msg>Core: typo fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/io/imagewriterutil.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/fileextension.h>
#include <inviwo/core/util/filedialog.h>
#include <inviwo/core/util/dialogfactory.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/io/datawriter.h>
#include <inviwo/core/io/datawriterfactory.h>

namespace inviwo {

namespace util {

void saveLayer(const Layer& layer, const std::string& path, const FileExtension& extension) {
    auto factory = InviwoApplication::getPtr()->getDataWriterFactory();

    auto writer = std::shared_ptr<DataWriterType<Layer>>(
        factory->getWriterForTypeAndExtension<Layer>(extension));

    if (!writer) {
        // could not find a reader for the given extension, extension might be invalid
        // try to get reader for the extension extracted from the file name, i.e. path
        const auto ext = filesystem::getFileExtension(path);
        writer = std::shared_ptr<DataWriterType<Layer>>(
            factory->getWriterForTypeAndExtension<Layer>(ext));
        if (!writer) {
            LogInfoCustom(
                "ImageWriterUtil",
                "Could not find a writer for the specified file extension (\"" << ext << "\")");
            return;
        }
    }

    try {
        writer->setOverwrite(true);
        writer->writeData(&layer, path);
        LogInfoCustom("ImageWriterUtil", "Canvas layer exported to disk: " << path);
    } catch (DataWriterException const& e) {
        LogErrorCustom("ImageWriterUtil", e.getMessage());
    }
}

void saveLayer(const Layer& layer) {
    auto fileDialog = util::dynamic_unique_ptr_cast<FileDialog>(
        InviwoApplication::getPtr()->getDialogFactory()->create("FileDialog"));
    if (!fileDialog) {
        return;
    }
    fileDialog->setTitle("Save Layer to File...");
    fileDialog->setAcceptMode(AcceptMode::Save);
    fileDialog->setFileMode(FileMode::AnyFile);

    auto writerFactory = InviwoApplication::getPtr()->getDataWriterFactory();
    fileDialog->addExtensions(writerFactory->getExtensionsForType<Layer>());

    if (fileDialog->show()) {
        saveLayer(layer, fileDialog->getSelectedFile(), fileDialog->getSelectedFileExtension());
    }
}

} // namespace

} // namespace

<|endoftext|>


<commit_before>//
// QtMark JSON Library
//
// Copyright (C) 2015 Assured Information Security, Inc.
// Author: Rian Quinn       <quinnr@ainfosec.com>
// Author: Rodney Forbes    <forbesr@ainfosec.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// ============================================================================
// Includes
// ============================================================================

#include <qmjsontype_qstring.h>

// ============================================================================
// QMJsonType<QString> Implementation
// ============================================================================

template <>
QMPointer<QMJsonValue> QM_JSON_EXPORT QMJsonType<QString>::fromJson(const QString &json, int32_t &index)
{
    auto result = QString();

    index++;

    while (1)
    {
        QMJsonValue::verifyIndex(json, index);

        switch (json.at(index).toLatin1())
        {
            case '\\':
            {
                index++;
                QMJsonValue::verifyIndex(json, index);

                switch (json.at(index).toLatin1())
                {
                    case '"': result += '"'; break;
                    case '\\': result += '\\'; break;
                    case '/': result += '/'; break;
                    case 'b': result += '\b'; break;
                    case 'f': result += '\f'; break;
                    case 'n': result += '\n'; break;
                    case 'r': result += '\r'; break;
                    case 't': result += '\t'; break;

                    // TODO: Need to add support for \u [number]

                    default:
                        break;
                };

                index++;
                break;
            }

            case '"':
                index++;
                return QMPointer<QMJsonValue>(new QMJsonValue(result));

            default:
                result += json.at(index++);
                break;
        };
    }

    return QMPointer<QMJsonValue>();
}

template <>
QString QM_JSON_EXPORT QMJsonType<QString>::toJson(int32_t tab, QMJsonSort sort)
{
    (void)tab;
    (void)sort;

    auto result = QString();
    const auto &str = this->get();

    result += '"';
    for (int i = 0; i < str.length(); i++)
    {
        auto c = str.at(i).toLatin1();

        switch (c)
        {
            case '\\':
                result += "\\\\";
                break;
            case '"':
                result += "\\\"";
                break;

            case '/':
                result += "\\/";
                break;

            case '\b':
                result += "\\b";
                break;

            case '\f':
                result += "\\f";
                break;

            case '\n':
                result += "\\n";
                break;

            case '\r':
                result += "\\r";
                break;

            case '\t':
                result += "\\t";
                break;

            default:
                result += c;
                break;
        }

    }
    result += '"';

    return result;
}

template <>
bool QM_JSON_EXPORT QMJsonType<QString>::isBaseType(void)
{
    return true;
}
<commit_msg>Support \u escapes when converting from json.<commit_after>//
// QtMark JSON Library
//
// Copyright (C) 2015 Assured Information Security, Inc.
// Author: Rian Quinn       <quinnr@ainfosec.com>
// Author: Rodney Forbes    <forbesr@ainfosec.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// ============================================================================
// Includes
// ============================================================================

#include <qmjsontype_qstring.h>

// ============================================================================
// QMJsonType<QString> Implementation
// ============================================================================

template <>
QMPointer<QMJsonValue> QM_JSON_EXPORT QMJsonType<QString>::fromJson(const QString &json, int32_t &index)
{
    auto result = QString();

    index++;

    while (1)
    {
        QMJsonValue::verifyIndex(json, index);

        switch (json.at(index).toLatin1())
        {
            case '\\':
            {
                index++;
                QMJsonValue::verifyIndex(json, index);

                const int32_t CHARS_IN_UNICODE_ESCAPE = 4;
                const int32_t HEX_BASE = 16;
                switch (json.at(index).toLatin1())
                {
                    case '"': result += '"'; break;
                    case '\\': result += '\\'; break;
                    case '/': result += '/'; break;
                    case 'b': result += '\b'; break;
                    case 'f': result += '\f'; break;
                    case 'n': result += '\n'; break;
                    case 'r': result += '\r'; break;
                    case 't': result += '\t'; break;
                    case 'u':
                        QMJsonValue::verifyIndex(json, index + CHARS_IN_UNICODE_ESCAPE);
                        result += json.mid(index + 1, CHARS_IN_UNICODE_ESCAPE).toUShort(Q_NULLPTR, HEX_BASE);
                        index += CHARS_IN_UNICODE_ESCAPE;
                        break;

                    default:
                        break;
                };

                index++;
                break;
            }

            case '"':
                index++;
                return QMPointer<QMJsonValue>(new QMJsonValue(result));

            default:
                result += json.at(index++);
                break;
        };
    }

    return QMPointer<QMJsonValue>();
}

template <>
QString QM_JSON_EXPORT QMJsonType<QString>::toJson(int32_t tab, QMJsonSort sort)
{
    (void)tab;
    (void)sort;

    auto result = QString();
    const auto &str = this->get();

    result += '"';
    for (int i = 0; i < str.length(); i++)
    {
        auto c = str.at(i).toLatin1();

        switch (c)
        {
            case '\\':
                result += "\\\\";
                break;
            case '"':
                result += "\\\"";
                break;

            case '/':
                result += "\\/";
                break;

            case '\b':
                result += "\\b";
                break;

            case '\f':
                result += "\\f";
                break;

            case '\n':
                result += "\\n";
                break;

            case '\r':
                result += "\\r";
                break;

            case '\t':
                result += "\\t";
                break;

            default:
                result += c;
                break;
        }

    }
    result += '"';

    return result;
}

template <>
bool QM_JSON_EXPORT QMJsonType<QString>::isBaseType(void)
{
    return true;
}
<|endoftext|>


<commit_before>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pch.h"

#include "windowsinformation.h"

#include <cstdlib>
#include <windows.h>
#include <Shlobj.h>

#include <boost/locale/encoding_utf.hpp>

GAMEKEEPER_NAMESPACE_START(core)

using boost::locale::conv::utf_to_utf;

std::string
WindowsInformation::getEnv(const char * name)
{
	wchar_t buffer[32767];
	DWORD size = GetEnvironmentVariableW(utf_to_utf<wchar_t>(name).c_str(), buffer, 32767);
	return utf_to_utf<char>(buffer, &buffer[size]);
}

void
WindowsInformation::setEnv(const char * name, const char * value)
{
	SetEnvironmentVariableW(utf_to_utf<wchar_t>(name).c_str(), utf_to_utf<wchar_t>(value).c_str());
}

std::string
WindowsInformation::getEnvSeperator()
{
	return ";";
}

boost::filesystem::path
WindowsInformation::getSystemRoot()
{
	return "C:\\";
}

boost::filesystem::path
WindowsInformation::getUserPath()
{
	TCHAR szPath[MAX_PATH];
	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, szPath);
	return szPath;
}

GAMEKEEPER_NAMESPACE_END(core)
<commit_msg>core/windowsinformation: fix compile error while crosscompile<commit_after>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pch.h"

#include "windowsinformation.h"

#include <cstdlib>

#include <windows.h>
#include <shlobj.h>

#include <boost/locale/encoding_utf.hpp>

GAMEKEEPER_NAMESPACE_START(core)

using boost::locale::conv::utf_to_utf;

std::string
WindowsInformation::getEnv(const char * name)
{
	wchar_t buffer[32767];
	DWORD size = GetEnvironmentVariableW(utf_to_utf<wchar_t>(name).c_str(), buffer, 32767);
	return utf_to_utf<char>(buffer, &buffer[size]);
}

void
WindowsInformation::setEnv(const char * name, const char * value)
{
	SetEnvironmentVariableW(utf_to_utf<wchar_t>(name).c_str(), utf_to_utf<wchar_t>(value).c_str());
}

std::string
WindowsInformation::getEnvSeperator()
{
	return ";";
}

boost::filesystem::path
WindowsInformation::getSystemRoot()
{
	return "C:\\";
}

boost::filesystem::path
WindowsInformation::getUserPath()
{
	TCHAR szPath[MAX_PATH];
	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, szPath);
	return szPath;
}

GAMEKEEPER_NAMESPACE_END(core)
<|endoftext|>


<commit_before>#include "Camera.h"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <iostream>

Camera::Camera():
  up({0, 1.0f, 0}),
  pos({0, 0, 0}),
  dir({0, 0, 1.0f}),
  view_mat(glm::lookAt(pos, dir+pos, up))
  {}

void Camera::translate(glm::vec3 pos) {
  this->pos += pos;
}

void Camera::rotate(float angle, glm::vec3 axis) {
  rot = glm::rotate(rot, angle, axis);
  dir = glm::vec3(glm::vec4(0, 0, 1, 0.0f) * glm::mat4_cast(rot));
}

glm::mat4 Camera::get_view_mat() {
  view_mat = glm::mat4{};
  view_mat = glm::mat4_cast(rot) * view_mat;
  view_mat = glm::translate(view_mat, pos);
  return view_mat;
}

void Camera::move_forward(float dist) {
  glm::vec3 temp = dir;
  temp.y = 0;
  temp = glm::normalize(temp);
  this->translate(dist*temp);
}

void Camera::move_right(float dist) {
  glm::vec3 left = glm::cross(up, dir);
  this->translate(dist*left);
}
<commit_msg>Changed camera move direction<commit_after>#include "Camera.h"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <iostream>

Camera::Camera():
  up({0, 1.0f, 0}),
  pos({0, 0, 0}),
  dir({0, 0, 1.0f}),
  view_mat(glm::lookAt(pos, dir+pos, up))
  {}

void Camera::translate(glm::vec3 pos) {
  this->pos += pos;
}

void Camera::rotate(float angle, glm::vec3 axis) {
  rot = glm::rotate(rot, angle, axis);
  dir = glm::vec3(glm::vec4(0, 0, 1, 0.0f) * glm::mat4_cast(rot));
}

glm::mat4 Camera::get_view_mat() {
  view_mat = glm::mat4{};
  view_mat = glm::mat4_cast(rot) * view_mat;
  view_mat = glm::translate(view_mat, pos);
  return view_mat;
}

void Camera::move_forward(float dist) {
  glm::vec3 temp = dir;
  temp.y = 0;
  temp = glm::normalize(temp);
  this->translate(dist*temp);
}

void Camera::move_right(float dist) {
  glm::vec3 left = glm::cross(up, dir);
  this->translate(-dist*left);
}
<|endoftext|>


<commit_before>#include "opt/mLibInclude.h"

#include "mLibCore.cpp"
#include "mLibLodePNG.cpp"

#include <gtest/gtest.h>
#include <kfusion/warp_field.hpp>
#include <string>
#include <vector>
#include "opt/main.h"
#include "opt/CombinedSolver.h"
#include "opt/OpenMesh.h"
#include <kfusion/warp_field.hpp>

TEST(OPT_WARP_FIELD, EnergyDataTest)
{
    const float max_error = 1e-3;

    kfusion::WarpField warpField;
    std::vector<cv::Vec3f> warp_init;

    warp_init.emplace_back(cv::Vec3f(1,1,1));
    warp_init.emplace_back(cv::Vec3f(1,2,-1));
    warp_init.emplace_back(cv::Vec3f(1,-2,1));
    warp_init.emplace_back(cv::Vec3f(1,-1,-1));
    warp_init.emplace_back(cv::Vec3f(-1,1,5));
    warp_init.emplace_back(cv::Vec3f(-1,1,-1));
    warp_init.emplace_back(cv::Vec3f(-1,-1,1));
    warp_init.emplace_back(cv::Vec3f(-1,-1,-1));
    warp_init.emplace_back(cv::Vec3f(2,-3,-1));

    warpField.init(warp_init);

    std::vector<cv::Vec3f> canonical_vertices;
    canonical_vertices.emplace_back(cv::Vec3f(-3,-3,-3));
    canonical_vertices.emplace_back(cv::Vec3f(-2,-2,-2));
    canonical_vertices.emplace_back(cv::Vec3f(0,0,0));
    canonical_vertices.emplace_back(cv::Vec3f(2,2,2));
    canonical_vertices.emplace_back(cv::Vec3f(3,3,3));
    canonical_vertices.emplace_back(cv::Vec3f(4,4,4));

    std::vector<cv::Vec3f> canonical_normals;
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));

    std::vector<cv::Vec3f> live_vertices;
    live_vertices.emplace_back(cv::Vec3f(-2.95f,-2.95f,-2.95f));
    live_vertices.emplace_back(cv::Vec3f(-1.95f,-1.95f,-1.95f));
    live_vertices.emplace_back(cv::Vec3f(0.05,0.05,0.05));
    live_vertices.emplace_back(cv::Vec3f(2.05,2.05,2.05));
    live_vertices.emplace_back(cv::Vec3f(3.05,3.05,3.05));
    live_vertices.emplace_back(cv::Vec3f(4.5,4.05,6));

    std::vector<cv::Vec3f> live_normals;
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));

//    CombinedSolverParameters params;
//    params.numIter = 20;
//    params.nonLinearIter = 15;
//    params.linearIter = 250;
//    params.useOpt = false;
//    params.useOptLM = true;
//
//    CombinedSolver solver(&warpField,
//                          canonical_vertices,
//                          canonical_normals,
//                          live_vertices,
//                          live_normals,
//                          params);
//    solver.solveAll();
    warpField.energy_data(canonical_vertices, canonical_normals, live_vertices, live_normals);
    warpField.warp(canonical_vertices, canonical_normals);

    for(size_t i = 0; i < canonical_vertices.size(); i++)
    {
        ASSERT_NEAR(canonical_vertices[i][0], live_vertices[i][0], max_error);
        ASSERT_NEAR(canonical_vertices[i][1], live_vertices[i][1], max_error);
        ASSERT_NEAR(canonical_vertices[i][2], live_vertices[i][2], max_error);
    }
}

<commit_msg>Fixed Opt test<commit_after>#include "opt/mLibInclude.h"

#include "mLibCore.cpp"
#include "mLibLodePNG.cpp"

#include <gtest/gtest.h>
#include <kfusion/warp_field.hpp>
#include <kfusion/warp_field_optimiser.hpp>
#include <string>
#include <vector>
#include "opt/main.h"
#include "opt/CombinedSolver.h"
#include "opt/OpenMesh.h"
#include <kfusion/warp_field.hpp>

TEST(OPT_WARP_FIELD, EnergyDataTest)
{
    const float max_error = 1e-3;

    kfusion::WarpField warpField;
    std::vector<cv::Vec3f> warp_init;

    warp_init.emplace_back(cv::Vec3f(1,1,1));
    warp_init.emplace_back(cv::Vec3f(1,2,-1));
    warp_init.emplace_back(cv::Vec3f(1,-2,1));
    warp_init.emplace_back(cv::Vec3f(1,-1,-1));
    warp_init.emplace_back(cv::Vec3f(-1,1,5));
    warp_init.emplace_back(cv::Vec3f(-1,1,-1));
    warp_init.emplace_back(cv::Vec3f(-1,-1,1));
    warp_init.emplace_back(cv::Vec3f(-1,-1,-1));
    warp_init.emplace_back(cv::Vec3f(2,-3,-1));

    warpField.init(warp_init);

    std::vector<cv::Vec3f> canonical_vertices;
    canonical_vertices.emplace_back(cv::Vec3f(-3,-3,-3));
    canonical_vertices.emplace_back(cv::Vec3f(-2,-2,-2));
    canonical_vertices.emplace_back(cv::Vec3f(0,0,0));
    canonical_vertices.emplace_back(cv::Vec3f(2,2,2));
    canonical_vertices.emplace_back(cv::Vec3f(3,3,3));
    canonical_vertices.emplace_back(cv::Vec3f(4,4,4));

    std::vector<cv::Vec3f> canonical_normals;
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));
    canonical_normals.emplace_back(cv::Vec3f(0,0,1));

    std::vector<cv::Vec3f> live_vertices;
    live_vertices.emplace_back(cv::Vec3f(-2.95f,-2.95f,-2.95f));
    live_vertices.emplace_back(cv::Vec3f(-1.95f,-1.95f,-1.95f));
    live_vertices.emplace_back(cv::Vec3f(0.05,0.05,0.05));
    live_vertices.emplace_back(cv::Vec3f(2.05,2.05,2.05));
    live_vertices.emplace_back(cv::Vec3f(3.05,3.05,3.05));
    live_vertices.emplace_back(cv::Vec3f(4.5,4.05,6));

    std::vector<cv::Vec3f> live_normals;
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));
    live_normals.emplace_back(cv::Vec3f(0,0,1));

    CombinedSolverParameters params;
    params.numIter = 20;
    params.nonLinearIter = 15;
    params.linearIter = 250;
    params.useOpt = false;
    params.useOptLM = true;

    kfusion::WarpFieldOptimiser optimiser(&warpField, params);

    optimiser.optimiseWarpData(canonical_vertices, canonical_normals, live_vertices, live_normals);
    warpField.warp(canonical_vertices, canonical_normals);

    for(size_t i = 0; i < canonical_vertices.size(); i++)
    {
        ASSERT_NEAR(canonical_vertices[i][0], live_vertices[i][0], max_error);
        ASSERT_NEAR(canonical_vertices[i][1], live_vertices[i][1], max_error);
        ASSERT_NEAR(canonical_vertices[i][2], live_vertices[i][2], max_error);
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Luke San Antonio
 * All rights reserved.
 */
#include "object.h"
namespace survive
{
  namespace gfx
  {
    Object create_object(gfx::IDriver& driver, std::string obj,
                         std::string mat) noexcept
    {
      auto ret = Object{};
      ret.mesh = driver.prepare_mesh(Mesh::from_file(obj));
      ret.material = load_material(mat);
      return ret;
    }
    void object_render(Object const& obj) noexcept
    {
      if(obj.material) obj.material->use();
      if(obj.mesh) obj.mesh->render();
    }
  }
}
<commit_msg>object_render should be render_object in gfx/object.cpp.<commit_after>/*
 * Copyright (C) 2014 Luke San Antonio
 * All rights reserved.
 */
#include "object.h"
namespace survive
{
  namespace gfx
  {
    Object create_object(gfx::IDriver& driver, std::string obj,
                         std::string mat) noexcept
    {
      auto ret = Object{};
      ret.mesh = driver.prepare_mesh(Mesh::from_file(obj));
      ret.material = load_material(mat);
      return ret;
    }
    void render_object(Object const& obj) noexcept
    {
      if(obj.material) obj.material->use();
      if(obj.mesh) obj.mesh->render();
    }
  }
}
<|endoftext|>


<commit_before>//
// $Id$

#include "script/Lexer.h"

Lexer::Lexer (const QString& expr, const QString& source) :
    _expr(expr),
    _source(source),
    _idx(0),
    _line(0),
    _lineIdx(0)
{
}

/**
 * Checks whether the specified character is a delimiter.
 */
static bool isDelimiter (QChar ch)
{
    return ch.isSpace() || ch == ';' || ch == '#' || ch == '\"' ||
        ch == '(' || ch == ')' || ch == '[' || ch == ']';
}

/**
 * Creates the named character map.
 */
static QHash<QString, QChar> createNamedChars ()
{
    QHash<QString, QChar> hash;
    hash.insert("nul", 0x0);
    hash.insert("alarm", 0x07);
    hash.insert("backspace", 0x08);
    hash.insert("tab", 0x09);
    hash.insert("linefeed", 0x0A);
    hash.insert("newline", 0x0A);
    hash.insert("vtab", 0x0B);
    hash.insert("page", 0x0C);
    hash.insert("return", 0x0D);
    hash.insert("esc", 0x1B);
    hash.insert("space", 0x20);
    hash.insert("delete", 0x7F);
    return hash;
}

/**
 * Returns a reference to the named character map.
 */
static const QHash<QString, QChar>& namedChars ()
{
    static QHash<QString, QChar> namedChars = createNamedChars();
    return namedChars;
}

int Lexer::nextLexeme ()
{
    for (int nn = _expr.length(); _idx < nn; _idx++) {
        QChar ch = _expr.at(_idx);
        if (ch.isSpace()) {
            if (ch == '\n') {
                _line++;
                _lineIdx = _idx + 1;
            }
            continue;
        }
        if (ch == ';') { // comment; ignore everything until the next line
            for (_idx++; _idx < nn; _idx++) {
                QChar ch = _expr.at(_idx);
                if (ch == '\n') {
                    _line++;
                    _lineIdx = _idx + 1;
                    break;
                }
            }
            continue;
        }
        _position = pos();
        if (ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '\'' || ch == '`') {
            _idx++;
            return ch.unicode();
        }
        if (ch == ',') {
            _idx++;
            if (_idx < nn && _expr.at(_idx) == '@') {
                _idx++;
                return UnquoteSplicing;
            }
            return ',';
        }
        if (ch == '\"') {
            _string = "";
            for (_idx++; _idx < nn; _idx++) {
                QChar ch = _expr.at(_idx);
                if (ch == '\\') {
                    if (++_idx == nn) {
                        break; // means the literal is unclosed
                    }
                    ch = _expr.at(_idx);
                    if (ch.isSpace()) { // continuation
                        for (; _idx < nn; _idx++) {
                            ch = _expr.at(_idx);
                            if (ch == '\n') {
                                _line++;
                                _lineIdx = _idx + 1;
                                break;
                            }
                        }
                        for (_idx++; _idx < nn; _idx++) {
                            ch = _expr.at(_idx);
                            if (!ch.isSpace() || ch == '\n') {
                                _idx--;
                                break;
                            }
                        }
                        continue;
                    }
                    switch (ch.unicode()) {
                        case '\"':
                        case '\\':
                            break;

                        case 'n':
                            ch = '\n';
                            break;

                        default:
                            throw ScriptError("Unrecognized escape.", pos());
                    }
                } else if (ch == '\"') {
                    _idx++;
                    return String;
                }
                _string.append(ch);
            }
            throw ScriptError("Unclosed string literal.", _position);
        }
        if (ch == '#') {
            if (_idx + 1 < nn) {
                switch (_expr.at(_idx + 1).unicode()) {
                    case 't':
                    case 'T':
                        _boolValue = true;
                        _idx += 2;
                        return Boolean;

                    case 'f':
                    case 'F':
                        _boolValue = false;
                        _idx += 2;
                        return Boolean;

                    case '\\':
                        if (_idx + 2 < nn) {
                            QString string(_expr.at(_idx + 2));
                            for (_idx += 3; _idx < nn; _idx++) {
                                QChar ch = _expr.at(_idx);
                                if (isDelimiter(ch)) {
                                    break;
                                }
                                string.append(ch);
                            }
                            if (string.size() == 1) {
                                _charValue = string.at(0);
                                return Char;
                            }
                            QHash<QString, QChar>::const_iterator it = namedChars().find(string);
                            if (it != namedChars().constEnd()) {
                                _charValue = it.value();
                                return Char;
                            }
                            if (string.at(0) != 'x') {
                                throw ScriptError("Unknown character.", _position);
                            }
                            bool ok;
                            int value = string.remove(0, 1).toInt(&ok, 16);
                            if (!ok || value < 0) {
                                throw ScriptError("Invalid character value.", _position);
                            }
                            _charValue = value;
                            return Char;
                        }
                        break;

                    case '(':
                        _idx += 2;
                        return Vector;

                    case 'v':
                        if (_idx + 4 < nn && _expr.mid(_idx + 2, 3) == "u8(") {
                            _idx += 5;
                            return ByteVector;
                        }
                        break;

                    case '\'':
                        _idx += 2;
                        return Syntax;

                    case '`':
                        _idx += 2;
                        return Quasisyntax;

                    case ',':
                        if (_idx + 2 < nn && _expr.at(_idx + 2) == '@') {
                            _idx += 3;
                            return UnsyntaxSplicing;
                        }
                        _idx += 2;
                        return Unsyntax;

                    case '!':
                        if (_idx + 5 < nn && _expr.mid(_idx + 2, 4) == "r6rs") {
                            _idx += 6;
                            continue;
                        }
                        break;

                    case '|': {
                        int depth = 1;
                        for (_idx += 2; _idx < nn; _idx++) {
                            QChar ch = _expr.at(_idx);
                            switch (ch.unicode()) {
                                case '\n':
                                    _line++;
                                    _lineIdx = _idx + 1;
                                    break;

                                case '#':
                                    if (_idx + 1 < nn && _expr.at(_idx + 1) == '|') {
                                        _idx++;
                                        depth++;
                                    }
                                    break;

                                case '|':
                                    if (_idx + 1 < nn && _expr.at(_idx + 1) == '#') {
                                        _idx++;
                                        if (--depth == 0) {
                                            goto outerContinue;
                                        }
                                    }
                                    break;
                            }
                        }
                        break;
                    }
                    case ';':
                        _idx += 2;
                        return Comment;
                }
            }
        } else if (ch == '+' || ch == '-') {
            if (_idx + 1 < nn) {
                QChar nch = _expr.at(_idx + 1);
                if (nch.isDigit() || nch == '.') {
                    return readNumber();
                }
            }
        } else if (ch == '.') {
            if (_idx + 1 < nn) {
                QChar nch = _expr.at(_idx + 1);
                if (nch.isDigit()) {
                    return readNumber();
                }
            }
        } else if (ch.isDigit()) {
            return readNumber();
        }

        // assume it to be an identifier; search for first non-identifier character or end
        _string = "";
        for (; _idx < nn; _idx++) {
            QChar ch = _expr.at(_idx);
            if (isDelimiter(ch)) {
                break;
            }
            _string.append(ch);
        }
        return Identifier;

        // allow nested loops to continue
        outerContinue: ;
    }
    return NoLexeme;
}

Lexer::LexemeType Lexer::readNumber ()
{
    // read until we reach a non-number character, noting if we see a decimal
    QString nstr;
    bool decimal = false;

    for (int nn = _expr.length(); _idx < nn; _idx++) {
        QChar ch = _expr.at(_idx);
        if (ch == '.') {
            nstr.append(ch);
            decimal = true;
            continue;
        }
        if (!(ch.isLetter() || ch.isDigit() || ch == '+' || ch == '-')) {
            break;
        }
        nstr.append(ch);
    }
    bool valid;
    if (decimal) {
        _floatValue = nstr.toFloat(&valid);
        if (!valid) {
            throw ScriptError("Invalid float literal.", _position);
        }
        return Float;

    } else {
        _intValue = nstr.toInt(&valid, 0); // allow 0x### for hex, 0### for octal
        if (!valid) {
            throw ScriptError("Invalid integer literal.", _position);
        }
        return Integer;
    }
}
<commit_msg>Character codes in strings.<commit_after>//
// $Id$

#include "script/Lexer.h"

Lexer::Lexer (const QString& expr, const QString& source) :
    _expr(expr),
    _source(source),
    _idx(0),
    _line(0),
    _lineIdx(0)
{
}

/**
 * Checks whether the specified character is a delimiter.
 */
static bool isDelimiter (QChar ch)
{
    return ch.isSpace() || ch == ';' || ch == '#' || ch == '\"' ||
        ch == '(' || ch == ')' || ch == '[' || ch == ']';
}

/**
 * Creates the named character map.
 */
static QHash<QString, QChar> createNamedChars ()
{
    QHash<QString, QChar> hash;
    hash.insert("nul", 0x0);
    hash.insert("alarm", 0x07);
    hash.insert("backspace", 0x08);
    hash.insert("tab", 0x09);
    hash.insert("linefeed", 0x0A);
    hash.insert("newline", 0x0A);
    hash.insert("vtab", 0x0B);
    hash.insert("page", 0x0C);
    hash.insert("return", 0x0D);
    hash.insert("esc", 0x1B);
    hash.insert("space", 0x20);
    hash.insert("delete", 0x7F);
    return hash;
}

/**
 * Returns a reference to the named character map.
 */
static const QHash<QString, QChar>& namedChars ()
{
    static QHash<QString, QChar> namedChars = createNamedChars();
    return namedChars;
}

int Lexer::nextLexeme ()
{
    for (int nn = _expr.length(); _idx < nn; _idx++) {
        QChar ch = _expr.at(_idx);
        if (ch.isSpace()) {
            if (ch == '\n') {
                _line++;
                _lineIdx = _idx + 1;
            }
            continue;
        }
        if (ch == ';') { // comment; ignore everything until the next line
            for (_idx++; _idx < nn; _idx++) {
                QChar ch = _expr.at(_idx);
                if (ch == '\n') {
                    _line++;
                    _lineIdx = _idx + 1;
                    break;
                }
            }
            continue;
        }
        _position = pos();
        if (ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '\'' || ch == '`') {
            _idx++;
            return ch.unicode();
        }
        if (ch == ',') {
            _idx++;
            if (_idx < nn && _expr.at(_idx) == '@') {
                _idx++;
                return UnquoteSplicing;
            }
            return ',';
        }
        if (ch == '\"') {
            _string = "";
            for (_idx++; _idx < nn; _idx++) {
                QChar ch = _expr.at(_idx);
                if (ch == '\\') {
                    if (++_idx == nn) {
                        break; // means the literal is unclosed
                    }
                    ch = _expr.at(_idx);
                    if (ch.isSpace()) { // continuation
                        for (; _idx < nn; _idx++) {
                            ch = _expr.at(_idx);
                            if (ch == '\n') {
                                _line++;
                                _lineIdx = _idx + 1;
                                break;
                            }
                        }
                        for (_idx++; _idx < nn; _idx++) {
                            ch = _expr.at(_idx);
                            if (!ch.isSpace() || ch == '\n') {
                                _idx--;
                                break;
                            }
                        }
                        continue;
                    }
                    switch (ch.unicode()) {
                        case '\"':
                        case '\\':
                            break;

                        case 'a':
                            ch = '\a';
                            break;

                        case 'b':
                            ch = '\b';
                            break;

                        case 't':
                            ch = '\t';
                            break;

                        case 'n':
                            ch = '\n';
                            break;

                        case 'v':
                            ch = '\v';
                            break;

                        case 'f':
                            ch = '\f';
                            break;

                        case 'r':
                            ch = '\r';
                            break;

                        case 'x': {
                            QString string;
                            for (_idx++; _idx < nn; _idx++) {
                                QChar ch = _expr.at(_idx);
                                if (ch == ';') {
                                    break;
                                }
                                string.append(ch);
                            }
                            bool ok;
                            ch = string.toInt(&ok, 16);
                            if (!ok) {
                                throw ScriptError("Invalid character code.", pos());
                            }
                            break;
                        }
                        default:
                            throw ScriptError("Unrecognized escape.", pos());
                    }
                } else if (ch == '\"') {
                    _idx++;
                    return String;
                }
                _string.append(ch);
            }
            throw ScriptError("Unclosed string literal.", _position);
        }
        if (ch == '#') {
            if (_idx + 1 < nn) {
                switch (_expr.at(_idx + 1).unicode()) {
                    case 't':
                    case 'T':
                        _boolValue = true;
                        _idx += 2;
                        return Boolean;

                    case 'f':
                    case 'F':
                        _boolValue = false;
                        _idx += 2;
                        return Boolean;

                    case '\\':
                        if (_idx + 2 < nn) {
                            QString string(_expr.at(_idx + 2));
                            for (_idx += 3; _idx < nn; _idx++) {
                                QChar ch = _expr.at(_idx);
                                if (isDelimiter(ch)) {
                                    break;
                                }
                                string.append(ch);
                            }
                            if (string.size() == 1) {
                                _charValue = string.at(0);
                                return Char;
                            }
                            QHash<QString, QChar>::const_iterator it = namedChars().find(string);
                            if (it != namedChars().constEnd()) {
                                _charValue = it.value();
                                return Char;
                            }
                            if (string.at(0) != 'x') {
                                throw ScriptError("Unknown character.", _position);
                            }
                            bool ok;
                            _charValue = string.remove(0, 1).toInt(&ok, 16);
                            if (!ok) {
                                throw ScriptError("Invalid character value.", _position);
                            }
                            return Char;
                        }
                        break;

                    case '(':
                        _idx += 2;
                        return Vector;

                    case 'v':
                        if (_idx + 4 < nn && _expr.mid(_idx + 2, 3) == "u8(") {
                            _idx += 5;
                            return ByteVector;
                        }
                        break;

                    case '\'':
                        _idx += 2;
                        return Syntax;

                    case '`':
                        _idx += 2;
                        return Quasisyntax;

                    case ',':
                        if (_idx + 2 < nn && _expr.at(_idx + 2) == '@') {
                            _idx += 3;
                            return UnsyntaxSplicing;
                        }
                        _idx += 2;
                        return Unsyntax;

                    case '!':
                        if (_idx + 5 < nn && _expr.mid(_idx + 2, 4) == "r6rs") {
                            _idx += 6;
                            continue;
                        }
                        break;

                    case '|': {
                        int depth = 1;
                        for (_idx += 2; _idx < nn; _idx++) {
                            QChar ch = _expr.at(_idx);
                            switch (ch.unicode()) {
                                case '\n':
                                    _line++;
                                    _lineIdx = _idx + 1;
                                    break;

                                case '#':
                                    if (_idx + 1 < nn && _expr.at(_idx + 1) == '|') {
                                        _idx++;
                                        depth++;
                                    }
                                    break;

                                case '|':
                                    if (_idx + 1 < nn && _expr.at(_idx + 1) == '#') {
                                        _idx++;
                                        if (--depth == 0) {
                                            goto outerContinue;
                                        }
                                    }
                                    break;
                            }
                        }
                        break;
                    }
                    case ';':
                        _idx += 2;
                        return Comment;
                }
            }
        } else if (ch == '+' || ch == '-') {
            if (_idx + 1 < nn) {
                QChar nch = _expr.at(_idx + 1);
                if (nch.isDigit() || nch == '.') {
                    return readNumber();
                }
            }
        } else if (ch == '.') {
            if (_idx + 1 < nn) {
                QChar nch = _expr.at(_idx + 1);
                if (nch.isDigit()) {
                    return readNumber();
                }
            }
        } else if (ch.isDigit()) {
            return readNumber();
        }

        // assume it to be an identifier; search for first non-identifier character or end
        _string = "";
        for (; _idx < nn; _idx++) {
            QChar ch = _expr.at(_idx);
            if (isDelimiter(ch)) {
                break;
            }
            _string.append(ch);
        }
        return Identifier;

        // allow nested loops to continue
        outerContinue: ;
    }
    return NoLexeme;
}

Lexer::LexemeType Lexer::readNumber ()
{
    // read until we reach a non-number character, noting if we see a decimal
    QString nstr;
    bool decimal = false;

    for (int nn = _expr.length(); _idx < nn; _idx++) {
        QChar ch = _expr.at(_idx);
        if (ch == '.') {
            nstr.append(ch);
            decimal = true;
            continue;
        }
        if (!(ch.isLetter() || ch.isDigit() || ch == '+' || ch == '-')) {
            break;
        }
        nstr.append(ch);
    }
    bool valid;
    if (decimal) {
        _floatValue = nstr.toFloat(&valid);
        if (!valid) {
            throw ScriptError("Invalid float literal.", _position);
        }
        return Float;

    } else {
        _intValue = nstr.toInt(&valid, 0); // allow 0x### for hex, 0### for octal
        if (!valid) {
            throw ScriptError("Invalid integer literal.", _position);
        }
        return Integer;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov 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.
//
// uncov 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 uncov.  If not, see <http://www.gnu.org/licenses/>.

#include "Catch/catch.hpp"

#include <cstdlib>

#include <iostream>
#include <stdexcept>
#include <string>

#include "BuildHistory.hpp"
#include "DB.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"

#include "TestUtils.hpp"

/**
 * @brief Temporarily redirects specified stream from a string.
 */
class StreamSubstitute
{
public:
    /**
     * @brief Constructs instance that redirects @p is.
     *
     * @param is Stream to redirect.
     * @param str Contents to splice into the stream.
     */
    StreamSubstitute(std::istream &is, const std::string &str)
        : is(is), iss(str)
    {
        rdbuf = is.rdbuf();
        is.rdbuf(iss.rdbuf());
    }

    /**
     * @brief Restores original state of the stream.
     */
    ~StreamSubstitute()
    {
        is.rdbuf(rdbuf);
    }

private:
    /**
     * @brief Stream that is being redirected.
     */
    std::istream &is;
    /**
     * @brief Temporary input buffer of the stream.
     */
    std::istringstream iss;
    /**
     * @brief Original input buffer of the stream.
     */
    std::streambuf *rdbuf;
};

static SubCommand * getCmd(const std::string &name);

TEST_CASE("Diff fails on wrong file path", "[subcommands][diff-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    DB db(repo.getGitPath() + "/uncover.sqlite");
    BuildHistory bh(db);

    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);
    REQUIRE(getCmd("diff")->exec(bh, repo, { "no-such-path" }) == EXIT_FAILURE);
    CHECK(coutCapture.get() == std::string());
    CHECK(cerrCapture.get() != std::string());
}

TEST_CASE("New handles input gracefully", "[subcommands][new-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    DB db(repo.getGitPath() + "/uncover.sqlite");
    BuildHistory bh(db);
    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);

    SECTION("Missing hashsum")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    SECTION("Not number in coverage")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 asdf -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    SECTION("Wrong file hash")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    CHECK(coutCapture.get() == std::string());
    CHECK(cerrCapture.get() != std::string());
}

TEST_CASE("New creates new builds", "[subcommands][new-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    const std::string dbPath = repo.getGitPath() + "/uncover.sqlite";
    FileRestorer databaseRestorer(dbPath, dbPath + "_original");
    DB db(dbPath);
    BuildHistory bh(db);
    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);

    SECTION("File missing from commit is just skipped")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "no-such-file\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() == vs({}));

        CHECK(cerrCapture.get() != std::string());
    }

    SECTION("File path is normalized")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "././test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() != vs({}));

        CHECK(cerrCapture.get() == std::string());
    }

    SECTION("Well-formed input is accepted")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        REQUIRE(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() != vs({}));

        CHECK(cerrCapture.get() == std::string());
    }

    CHECK(coutCapture.get() != std::string());
}

static SubCommand *
getCmd(const std::string &name)
{
    for (SubCommand *cmd : SubCommand::getAll()) {
        if (cmd->getName() == name) {
            return cmd;
        }
    }
    throw std::invalid_argument("No such command: " + name);
}
<commit_msg>REQUIRE => CHECK in some sub_commands tests<commit_after>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov 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.
//
// uncov 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 uncov.  If not, see <http://www.gnu.org/licenses/>.

#include "Catch/catch.hpp"

#include <cstdlib>

#include <iostream>
#include <stdexcept>
#include <string>

#include "BuildHistory.hpp"
#include "DB.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"

#include "TestUtils.hpp"

/**
 * @brief Temporarily redirects specified stream from a string.
 */
class StreamSubstitute
{
public:
    /**
     * @brief Constructs instance that redirects @p is.
     *
     * @param is Stream to redirect.
     * @param str Contents to splice into the stream.
     */
    StreamSubstitute(std::istream &is, const std::string &str)
        : is(is), iss(str)
    {
        rdbuf = is.rdbuf();
        is.rdbuf(iss.rdbuf());
    }

    /**
     * @brief Restores original state of the stream.
     */
    ~StreamSubstitute()
    {
        is.rdbuf(rdbuf);
    }

private:
    /**
     * @brief Stream that is being redirected.
     */
    std::istream &is;
    /**
     * @brief Temporary input buffer of the stream.
     */
    std::istringstream iss;
    /**
     * @brief Original input buffer of the stream.
     */
    std::streambuf *rdbuf;
};

static SubCommand * getCmd(const std::string &name);

TEST_CASE("Diff fails on wrong file path", "[subcommands][diff-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    DB db(repo.getGitPath() + "/uncover.sqlite");
    BuildHistory bh(db);

    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);
    CHECK(getCmd("diff")->exec(bh, repo, { "no-such-path" }) == EXIT_FAILURE);
    CHECK(coutCapture.get() == std::string());
    CHECK(cerrCapture.get() != std::string());
}

TEST_CASE("New handles input gracefully", "[subcommands][new-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    DB db(repo.getGitPath() + "/uncover.sqlite");
    BuildHistory bh(db);
    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);

    SECTION("Missing hashsum")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    SECTION("Not number in coverage")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 asdf -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    SECTION("Wrong file hash")
    {
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_FAILURE);
    }

    CHECK(coutCapture.get() == std::string());
    CHECK(cerrCapture.get() != std::string());
}

TEST_CASE("New creates new builds", "[subcommands][new-subcommand]")
{
    Repository repo("tests/test-repo/subdir");
    const std::string dbPath = repo.getGitPath() + "/uncover.sqlite";
    FileRestorer databaseRestorer(dbPath, dbPath + "_original");
    DB db(dbPath);
    BuildHistory bh(db);
    StreamCapture coutCapture(std::cout), cerrCapture(std::cerr);

    SECTION("File missing from commit is just skipped")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "no-such-file\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() == vs({}));

        CHECK(cerrCapture.get() != std::string());
    }

    SECTION("File path is normalized")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "././test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() != vs({}));

        CHECK(cerrCapture.get() == std::string());
    }

    SECTION("Well-formed input is accepted")
    {
        auto sizeWas = bh.getBuilds().size();
        StreamSubstitute cinSubst(std::cin,
                                  "8e354da4df664b71e06c764feb29a20d64351a01\n"
                                  "master\n"
                                  "test-file1.cpp\n"
                                  "7e734c598d6ebdc19bbd660f6a7a6c73\n"
                                  "5\n"
                                  "-1 1 -1 1 -1\n");
        CHECK(getCmd("new")->exec(bh, repo, {}) == EXIT_SUCCESS);
        REQUIRE(bh.getBuilds().size() == sizeWas + 1);
        REQUIRE(bh.getBuilds().back().getPaths() != vs({}));

        CHECK(cerrCapture.get() == std::string());
    }

    CHECK(coutCapture.get() != std::string());
}

static SubCommand *
getCmd(const std::string &name)
{
    for (SubCommand *cmd : SubCommand::getAll()) {
        if (cmd->getName() == name) {
            return cmd;
        }
    }
    throw std::invalid_argument("No such command: " + name);
}
<|endoftext|>


<commit_before>#include "h2olog.h"
#include "json.h"

#include <cstdio>
#include <cstring>
#include <cinttypes>

extern "C" {
#include <sys/socket.h>
#include <netinet/in.h>
#include "h2o/socket.h"
}

using namespace std;

#define FPUTS_LIT(s, out) fwrite(s, 1, strlen(s), out)

static bool json_need_escape(char c)
{
    return static_cast<unsigned char>(c) < 0x20 || c == 0x7f;
}

static void json_write_str_value(FILE *out, const char *str)
{
    fputc('"', out);
    while (*str) {
        switch (*str) {
        case '\"':
            FPUTS_LIT("\\\"", out);
            break;
        case '\\':
            FPUTS_LIT("\\\\", out);
            break;
        case '\b':
            FPUTS_LIT("\\b", out);
            break;
        case '\f':
            FPUTS_LIT("\\f", out);
            break;
        case '\n':
            FPUTS_LIT("\\n", out);
            break;
        case '\r':
            FPUTS_LIT("\\r", out);
            break;
        case '\t':
            FPUTS_LIT("\\t", out);
            break;
        default:
            if (!json_need_escape(*str)) {
                fputc(*str, out);
            } else {
                auto u8 = static_cast<uint8_t>(*str);
                fprintf(out, "\\u%04x", u8);
            }
            break;
        }
        str++;
    }
    fputc('"', out);
}

static void json_write_name_value(FILE *out, const char *name, size_t name_len)
{
    fputc('"', out);
    fwrite(name, 1, name_len, out);
    fputc('"', out);
    fputc(':', out);
}

void json_write_pair_n(FILE *out, const char *name, size_t name_len, const char *value)
{
    json_write_name_value(out, name, name_len);
    json_write_str_value(out, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const char *value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    json_write_str_value(out, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const void *value, size_t len)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fputc('"', out);
    const uint8_t *bin = static_cast<const uint8_t *>(value);
    for (size_t i = 0; i < len; i++) {
        fputc("0123456789abcdef"[bin[i] >> 4], out);
        fputc("0123456789abcdef"[bin[i] & 0xf], out);
    }
    fputc('"', out);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, int32_t value)
{
    json_write_pair_c(out, name, name_len, static_cast<int64_t>(value));
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, uint32_t value)
{
    json_write_pair_c(out, name, name_len, static_cast<uint64_t>(value));
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, int64_t value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fprintf(out, "%" PRId64, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, uint64_t value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fprintf(out, "%" PRIu64, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const h2olog_address_t &value)
{
    const sockaddr *sa = &value.sa;
    fputc(',', out);

    json_write_name_value(out, name, name_len);

    char addr[NI_MAXHOST];
    size_t addr_len = h2o_socket_getnumerichost(sa, sizeof(h2olog_address_t), addr);
    if (addr_len == SIZE_MAX) {
        fprintf(out, "null");
        return;
    }
    int32_t port = h2o_socket_getport(sa);

    fputc('"', out);

    if (sa->sa_family == AF_INET) {
        // e.g. "1.2.3.4:12345"
        fwrite(addr, 1, addr_len, out);
    } else if (sa->sa_family == AF_INET6) {
        // e.g. "[2001:0db8:85a3::8a2e:0370:7334]:12345"
        fputc('[', out);
        fwrite(addr, 1, addr_len, out);
        fputc(']', out);
    }
    fputc(':', out);
    fprintf(out, "%" PRId32, port);

    fputc('"', out);
}
<commit_msg>include netdb.h for NI_MAXHOST<commit_after>#include "h2olog.h"
#include "json.h"

#include <cstdio>
#include <cstring>
#include <cinttypes>

extern "C" {
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "h2o/socket.h"
}

using namespace std;

#define FPUTS_LIT(s, out) fwrite(s, 1, strlen(s), out)

static bool json_need_escape(char c)
{
    return static_cast<unsigned char>(c) < 0x20 || c == 0x7f;
}

static void json_write_str_value(FILE *out, const char *str)
{
    fputc('"', out);
    while (*str) {
        switch (*str) {
        case '\"':
            FPUTS_LIT("\\\"", out);
            break;
        case '\\':
            FPUTS_LIT("\\\\", out);
            break;
        case '\b':
            FPUTS_LIT("\\b", out);
            break;
        case '\f':
            FPUTS_LIT("\\f", out);
            break;
        case '\n':
            FPUTS_LIT("\\n", out);
            break;
        case '\r':
            FPUTS_LIT("\\r", out);
            break;
        case '\t':
            FPUTS_LIT("\\t", out);
            break;
        default:
            if (!json_need_escape(*str)) {
                fputc(*str, out);
            } else {
                auto u8 = static_cast<uint8_t>(*str);
                fprintf(out, "\\u%04x", u8);
            }
            break;
        }
        str++;
    }
    fputc('"', out);
}

static void json_write_name_value(FILE *out, const char *name, size_t name_len)
{
    fputc('"', out);
    fwrite(name, 1, name_len, out);
    fputc('"', out);
    fputc(':', out);
}

void json_write_pair_n(FILE *out, const char *name, size_t name_len, const char *value)
{
    json_write_name_value(out, name, name_len);
    json_write_str_value(out, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const char *value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    json_write_str_value(out, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const void *value, size_t len)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fputc('"', out);
    const uint8_t *bin = static_cast<const uint8_t *>(value);
    for (size_t i = 0; i < len; i++) {
        fputc("0123456789abcdef"[bin[i] >> 4], out);
        fputc("0123456789abcdef"[bin[i] & 0xf], out);
    }
    fputc('"', out);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, int32_t value)
{
    json_write_pair_c(out, name, name_len, static_cast<int64_t>(value));
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, uint32_t value)
{
    json_write_pair_c(out, name, name_len, static_cast<uint64_t>(value));
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, int64_t value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fprintf(out, "%" PRId64, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, uint64_t value)
{
    fputc(',', out);
    json_write_name_value(out, name, name_len);
    fprintf(out, "%" PRIu64, value);
}

void json_write_pair_c(FILE *out, const char *name, size_t name_len, const h2olog_address_t &value)
{
    const sockaddr *sa = &value.sa;
    fputc(',', out);

    json_write_name_value(out, name, name_len);

    char addr[NI_MAXHOST];
    size_t addr_len = h2o_socket_getnumerichost(sa, sizeof(h2olog_address_t), addr);
    if (addr_len == SIZE_MAX) {
        fprintf(out, "null");
        return;
    }
    int32_t port = h2o_socket_getport(sa);

    fputc('"', out);

    if (sa->sa_family == AF_INET) {
        // e.g. "1.2.3.4:12345"
        fwrite(addr, 1, addr_len, out);
    } else if (sa->sa_family == AF_INET6) {
        // e.g. "[2001:0db8:85a3::8a2e:0370:7334]:12345"
        fputc('[', out);
        fwrite(addr, 1, addr_len, out);
        fputc(']', out);
    }
    fputc(':', out);
    fprintf(out, "%" PRId32, port);

    fputc('"', out);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 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 HOLDER 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 "httpserver.h"
#include <cstring>
#include <cassert>
#include <iostream>
#include <sstream>
#include "utils/stringutils.h"

static const char* NOT_FOUND_PAGE = "<title>Not found</title>
No resource found at this address.
";
static const char* BAD_REQUEST = "<title>Bad request</title>
Bad request
";

HTTPServer::HTTPServer(const uint16_t http_port): m_http_port(http_port)
{
	m_mhd_daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, m_http_port, NULL,
			NULL, &HTTPServer::request_handler, this, MHD_OPTION_NOTIFY_COMPLETED,
			&HTTPServer::request_completed, NULL, MHD_OPTION_END);
}

HTTPServer::~HTTPServer()
{
	if (m_mhd_daemon) {
		MHD_stop_daemon(m_mhd_daemon);
	}
}

struct HTTPRequestSession
{
	std::string result = "";
	bool data_handled = false;
	uint32_t http_code = MHD_HTTP_OK;
};

int HTTPServer::request_handler(void *http_server, struct MHD_Connection *connection,
	const char *url, const char *method, const char *version, const char *upload_data,
	size_t *upload_data_size, void **con_cls)
{
	HTTPServer *httpd = (HTTPServer *) http_server;
	HTTPMethod http_method;
	struct MHD_Response *response;
	int ret;

	if (strcmp(method, "GET") == 0) {
		http_method = HTTP_METHOD_GET;
	}
	else if (strcmp(method, "POST") == 0) {
		http_method = HTTP_METHOD_POST;
	}
	else if (strcmp(method, "PUT") == 0) {
		http_method = HTTP_METHOD_PUT;
	}
	else if (strcmp(method, "PATCH") == 0) {
		http_method = HTTP_METHOD_PATCH;
	}
	else if (strcmp(method, "PROPFIND") == 0) {
		http_method = HTTP_METHOD_PROPFIND;
	}
	else if (strcmp(method, "DELETE") == 0) {
		http_method = HTTP_METHOD_DELETE;
	}
	else if (strcmp(method, "HEAD") == 0) {
		http_method = HTTP_METHOD_HEAD;
	}
	else {
		return MHD_NO; /* unexpected method */
	}

	if (*con_cls == NULL) {
		// The first time only the headers are valid,
		//   do not respond in the first round...
		//   Just init our response
		HTTPRequestSession *session = new HTTPRequestSession();
		*con_cls = session;
		return MHD_YES;
	}

	// Handle request
	HTTPRequestSession *session = (HTTPRequestSession *) *con_cls;
	if (!session->data_handled && !httpd->handle_query(http_method, connection, std::string(url),
		std::string(upload_data, *upload_data_size), session->result)) {
		session->result = std::string(BAD_REQUEST);
		session->http_code = MHD_HTTP_BAD_REQUEST;
	}

	// When post data is available, reinit the data_size because this function
	// is called another time. And mark the current session as handled
	if (*upload_data_size > 0) {
		*upload_data_size = 0;
		session->data_handled = true;
		return MHD_YES;
	}

	response = MHD_create_response_from_buffer(session->result.length(),
		(void *) session->result.c_str(), MHD_RESPMEM_MUST_COPY);
	ret = MHD_queue_response(connection, session->http_code, response);
	MHD_destroy_response(response);

	// clear context pointer
	delete session;
	*con_cls = NULL;
	return ret;
}

void HTTPServer::request_completed(void *cls, struct MHD_Connection *connection,
		void **con_cls, MHD_RequestTerminationCode toe)
{
}

bool HTTPServer::handle_query(HTTPMethod m, MHD_Connection *conn, const std::string &url,
	const std::string &upload_data, std::string &result)
{
	assert(m < HTTP_METHOD_MAX);

	HTTPServerReqHandlerMap::const_iterator url_handler = m_handlers[m].find(url);
	if (url_handler == m_handlers[m].end()) {
		return false;
	}

	HTTPQueryPtr q;

	// Read which params we want and store them
	const char* content_type = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "Content-Type");
	if (!content_type) {
		q = HTTPQueryPtr(new HTTPQuery());
	}
	else if (strcmp(content_type, "application/x-www-form-urlencoded") == 0) {
		q = HTTPQueryPtr(new HTTPFormQuery());
		if (!parse_post_data(upload_data, q)) {
			return false;
		}
	}
	else if (strcmp(content_type, "application/json") == 0) {
		HTTPJsonQuery *jq = new HTTPJsonQuery();
		q = HTTPQueryPtr(jq);
		Json::Reader reader;
		if (!reader.parse(upload_data, jq->json_query)) {
			return false;
		}
	}
	else {
		q = HTTPQueryPtr(new HTTPQuery());
	}

	q->url = url;
	MHD_get_connection_values(conn, MHD_HEADER_KIND, &HTTPServer::mhd_iter_headers, q.get());
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND, &HTTPServer::mhd_iter_getargs, q.get());

	return url_handler->second(q, result);
}

int HTTPServer::mhd_iter_headers(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->headers[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

int HTTPServer::mhd_iter_getargs(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->get_params[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

bool HTTPServer::parse_post_data(const std::string &data, HTTPQueryPtr q)
{
	HTTPFormQuery *qf = dynamic_cast<HTTPFormQuery *>(q.get());
	assert(qf);
	std::vector<std::string> first_split;
	str_split(data, '&', first_split);

	for (const auto &s: first_split) {
		// If this post data is empty, abort
		if (s.empty()) {
			return false;
		}

		std::vector<std::string> kv;
		str_split(s, '=', kv);

		// If the key value pair is invalid, abort
		if (kv.size() != 2 || kv[0].empty() || kv[1].empty()) {
			return false;
		}

		qf->post_data[kv[0]] = kv[1];
	}

	return true;
}
<commit_msg>Properly create strings using strlen for length of strings<commit_after>/**
 * Copyright (c) 2016, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 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 HOLDER 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 "httpserver.h"
#include <cstring>
#include <cassert>
#include <iostream>
#include <sstream>
#include "utils/stringutils.h"

static const char* NOT_FOUND_PAGE = "<title>Not found</title>
No resource found at this address.
";
static const char* BAD_REQUEST = "<title>Bad request</title>
Bad request
";

HTTPServer::HTTPServer(const uint16_t http_port): m_http_port(http_port)
{
	m_mhd_daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, m_http_port, NULL,
			NULL, &HTTPServer::request_handler, this, MHD_OPTION_NOTIFY_COMPLETED,
			&HTTPServer::request_completed, NULL, MHD_OPTION_END);
}

HTTPServer::~HTTPServer()
{
	if (m_mhd_daemon) {
		MHD_stop_daemon(m_mhd_daemon);
	}
}

struct HTTPRequestSession
{
	std::string result = "";
	bool data_handled = false;
	uint32_t http_code = MHD_HTTP_OK;
};

int HTTPServer::request_handler(void *http_server, struct MHD_Connection *connection,
	const char *url, const char *method, const char *version, const char *upload_data,
	size_t *upload_data_size, void **con_cls)
{
	HTTPServer *httpd = (HTTPServer *) http_server;
	HTTPMethod http_method;
	struct MHD_Response *response;
	int ret;

	if (strcmp(method, "GET") == 0) {
		http_method = HTTP_METHOD_GET;
	}
	else if (strcmp(method, "POST") == 0) {
		http_method = HTTP_METHOD_POST;
	}
	else if (strcmp(method, "PUT") == 0) {
		http_method = HTTP_METHOD_PUT;
	}
	else if (strcmp(method, "PATCH") == 0) {
		http_method = HTTP_METHOD_PATCH;
	}
	else if (strcmp(method, "PROPFIND") == 0) {
		http_method = HTTP_METHOD_PROPFIND;
	}
	else if (strcmp(method, "DELETE") == 0) {
		http_method = HTTP_METHOD_DELETE;
	}
	else if (strcmp(method, "HEAD") == 0) {
		http_method = HTTP_METHOD_HEAD;
	}
	else {
		return MHD_NO; /* unexpected method */
	}

	if (*con_cls == NULL) {
		// The first time only the headers are valid,
		//   do not respond in the first round...
		//   Just init our response
		HTTPRequestSession *session = new HTTPRequestSession();
		*con_cls = session;
		return MHD_YES;
	}

	// Handle request
	HTTPRequestSession *session = (HTTPRequestSession *) *con_cls;
	if (!session->data_handled && !httpd->handle_query(http_method, connection, std::string(url),
		std::string(upload_data, *upload_data_size), session->result)) {
		session->result = std::string(BAD_REQUEST);
		session->http_code = MHD_HTTP_BAD_REQUEST;
	}

	// When post data is available, reinit the data_size because this function
	// is called another time. And mark the current session as handled
	if (*upload_data_size > 0) {
		*upload_data_size = 0;
		session->data_handled = true;
		return MHD_YES;
	}

	response = MHD_create_response_from_buffer(session->result.length(),
		(void *) session->result.c_str(), MHD_RESPMEM_MUST_COPY);
	ret = MHD_queue_response(connection, session->http_code, response);
	MHD_destroy_response(response);

	// clear context pointer
	delete session;
	*con_cls = NULL;
	return ret;
}

void HTTPServer::request_completed(void *cls, struct MHD_Connection *connection,
		void **con_cls, MHD_RequestTerminationCode toe)
{
}

bool HTTPServer::handle_query(HTTPMethod m, MHD_Connection *conn, const std::string &url,
	const std::string &upload_data, std::string &result)
{
	assert(m < HTTP_METHOD_MAX);

	HTTPServerReqHandlerMap::const_iterator url_handler = m_handlers[m].find(url);
	if (url_handler == m_handlers[m].end()) {
		return false;
	}

	HTTPQueryPtr q;

	// Read which params we want and store them
	const char* content_type = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "Content-Type");
	if (!content_type) {
		q = HTTPQueryPtr(new HTTPQuery());
	}
	else if (strcmp(content_type, "application/x-www-form-urlencoded") == 0) {
		q = HTTPQueryPtr(new HTTPFormQuery());
		if (!parse_post_data(upload_data, q)) {
			return false;
		}
	}
	else if (strcmp(content_type, "application/json") == 0) {
		HTTPJsonQuery *jq = new HTTPJsonQuery();
		q = HTTPQueryPtr(jq);
		Json::Reader reader;
		if (!reader.parse(upload_data, jq->json_query)) {
			return false;
		}
	}
	else {
		q = HTTPQueryPtr(new HTTPQuery());
	}

	q->url = url;
	MHD_get_connection_values(conn, MHD_HEADER_KIND, &HTTPServer::mhd_iter_headers, q.get());
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND, &HTTPServer::mhd_iter_getargs, q.get());

	return url_handler->second(q, result);
}

int HTTPServer::mhd_iter_headers(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->headers[std::string(key, strlen(key))] = std::string(value, strlen(value));
	}
	return MHD_YES; // continue iteration
}

int HTTPServer::mhd_iter_getargs(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->get_params[std::string(key, strlen(key))] = std::string(value, strlen(value));
	}
	return MHD_YES; // continue iteration
}

bool HTTPServer::parse_post_data(const std::string &data, HTTPQueryPtr q)
{
	HTTPFormQuery *qf = dynamic_cast<HTTPFormQuery *>(q.get());
	assert(qf);
	std::vector<std::string> first_split;
	str_split(data, '&', first_split);

	for (const auto &s: first_split) {
		// If this post data is empty, abort
		if (s.empty()) {
			return false;
		}

		std::vector<std::string> kv;
		str_split(s, '=', kv);

		// If the key value pair is invalid, abort
		if (kv.size() != 2 || kv[0].empty() || kv[1].empty()) {
			return false;
		}

		qf->post_data[kv[0]] = kv[1];
	}

	return true;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 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 HOLDER 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 "httpserver.h"
#include <cstring>
#include <cassert>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include "utils/stringutils.h"

static const char* NOT_FOUND_PAGE = "<title>Not found</title>
No resource found at this address.
";
static const char* BAD_REQUEST = "<title>Bad request</title>
Bad request
";

HTTPServer::HTTPServer(const uint16_t http_port): m_http_port(http_port)
{
	m_mhd_daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, m_http_port, NULL,
			NULL, &HTTPServer::request_handler, this, MHD_OPTION_NOTIFY_COMPLETED,
			&HTTPServer::request_completed, NULL, MHD_OPTION_END);
}

HTTPServer::~HTTPServer()
{
	if (m_mhd_daemon) {
		MHD_stop_daemon(m_mhd_daemon);
	}
}

struct HTTPRequestSession
{
	std::string result = "";
	bool data_handled = false;
};

int HTTPServer::request_handler(void *http_server, struct MHD_Connection *connection,
	const char *url, const char *method, const char *version, const char *upload_data,
	size_t *upload_data_size, void **con_cls)
{
	HTTPServer *httpd = (HTTPServer *) http_server;
	HTTPMethod http_method;
	struct MHD_Response *response;
	int ret;

	if (strcmp(method, "GET") == 0) {
		http_method = HTTP_METHOD_GET;
	}
	else if (strcmp(method, "POST") == 0) {
		http_method = HTTP_METHOD_POST;
	}
	else if (strcmp(method, "PUT") == 0) {
		http_method = HTTP_METHOD_PUT;
	}
	else if (strcmp(method, "PATCH") == 0) {
		http_method = HTTP_METHOD_PATCH;
	}
	else if (strcmp(method, "PROPFIND") == 0) {
		http_method = HTTP_METHOD_PROPFIND;
	}
	else if (strcmp(method, "DELETE") == 0) {
		http_method = HTTP_METHOD_DELETE;
	}
	else if (strcmp(method, "HEAD") == 0) {
		http_method = HTTP_METHOD_HEAD;
	}
	else {
		return MHD_NO; /* unexpected method */
	}

	if (*con_cls == NULL) {
		/* The first time only the headers are valid,
		   do not respond in the first round...
		   Just init our response*/
		HTTPRequestSession *session = new HTTPRequestSession();
		*con_cls = session;
		return MHD_YES;
	}

	// Handle request
	HTTPRequestSession *session = (HTTPRequestSession *) *con_cls;
	if (!session->data_handled && !httpd->handle_query(http_method, connection, std::string(url),
		std::string(upload_data, *upload_data_size), session->result)) {
		session->result = std::string(BAD_REQUEST);
	}

	// When post data is available, reinit the data_size because this function
	// is called another time. And mark the current session as handled
	if (*upload_data_size > 0) {
		*upload_data_size = 0;
		session->data_handled = true;
		return MHD_YES;
	}

	response = MHD_create_response_from_buffer(session->result.length(),
		(void *) session->result.c_str(), MHD_RESPMEM_MUST_COPY);
	ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
	MHD_destroy_response(response);

	delete session;
	*con_cls = NULL; /* clear context pointer */
	return ret;
}

void HTTPServer::request_completed(void *cls, struct MHD_Connection *connection,
		void **con_cls, MHD_RequestTerminationCode toe)
{
}

bool HTTPServer::handle_query(HTTPMethod m, MHD_Connection *conn, const std::string &url,
	const std::string &upload_data, std::string &result)
{
	assert(m < HTTP_METHOD_MAX);

	HTTPServerReqHandlerMap::const_iterator url_handler = m_handlers[m].find(url);
	if (url_handler == m_handlers[m].end()) {
		return false;
	}

	// Read which params we want and store them
	HTTPQuery q;

	q.url = url;
	MHD_get_connection_values(conn, MHD_HEADER_KIND, &HTTPServer::mhd_iter_headers, &q);
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND, &HTTPServer::mhd_iter_getargs, &q);

	const auto ct_itr = q.headers.find("Content-Type");
	if (ct_itr != q.headers.end()) {
		if (ct_itr->second == "application/x-www-form-urlencoded") {
			// Abort if upload_data is invalid
			if (!parse_post_data(upload_data, q)) {
				return false;
			}
		}
	}

	return url_handler->second(q, result);
}

int HTTPServer::mhd_iter_headers(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->headers[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

int HTTPServer::mhd_iter_getargs(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->get_params[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

bool HTTPServer::parse_post_data(const std::string &data, HTTPQuery &q)
{
	std::vector<std::string> first_split;
	str_split(data, '&', first_split);

	for (const auto &s: first_split) {
		// If this post data is empty, abort
		if (s.empty()) {
			return false;
		}

		std::vector<std::string> kv;
		str_split(s, '=', kv);

		// If the key value pair is invalid, abort
		if (kv.size() != 2 || kv[0].empty() || kv[1].empty()) {
			return false;
		}

		q.post_data[kv[0]] = kv[1];
	}

	return true;
}
<commit_msg>Update comments<commit_after>/**
 * Copyright (c) 2016, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 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 HOLDER 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 "httpserver.h"
#include <cstring>
#include <cassert>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include "utils/stringutils.h"

static const char* NOT_FOUND_PAGE = "<title>Not found</title>
No resource found at this address.
";
static const char* BAD_REQUEST = "<title>Bad request</title>
Bad request
";

HTTPServer::HTTPServer(const uint16_t http_port): m_http_port(http_port)
{
	m_mhd_daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, m_http_port, NULL,
			NULL, &HTTPServer::request_handler, this, MHD_OPTION_NOTIFY_COMPLETED,
			&HTTPServer::request_completed, NULL, MHD_OPTION_END);
}

HTTPServer::~HTTPServer()
{
	if (m_mhd_daemon) {
		MHD_stop_daemon(m_mhd_daemon);
	}
}

struct HTTPRequestSession
{
	std::string result = "";
	bool data_handled = false;
};

int HTTPServer::request_handler(void *http_server, struct MHD_Connection *connection,
	const char *url, const char *method, const char *version, const char *upload_data,
	size_t *upload_data_size, void **con_cls)
{
	HTTPServer *httpd = (HTTPServer *) http_server;
	HTTPMethod http_method;
	struct MHD_Response *response;
	int ret;

	if (strcmp(method, "GET") == 0) {
		http_method = HTTP_METHOD_GET;
	}
	else if (strcmp(method, "POST") == 0) {
		http_method = HTTP_METHOD_POST;
	}
	else if (strcmp(method, "PUT") == 0) {
		http_method = HTTP_METHOD_PUT;
	}
	else if (strcmp(method, "PATCH") == 0) {
		http_method = HTTP_METHOD_PATCH;
	}
	else if (strcmp(method, "PROPFIND") == 0) {
		http_method = HTTP_METHOD_PROPFIND;
	}
	else if (strcmp(method, "DELETE") == 0) {
		http_method = HTTP_METHOD_DELETE;
	}
	else if (strcmp(method, "HEAD") == 0) {
		http_method = HTTP_METHOD_HEAD;
	}
	else {
		return MHD_NO; /* unexpected method */
	}

	if (*con_cls == NULL) {
		// The first time only the headers are valid,
		//   do not respond in the first round...
		//   Just init our response
		HTTPRequestSession *session = new HTTPRequestSession();
		*con_cls = session;
		return MHD_YES;
	}

	// Handle request
	HTTPRequestSession *session = (HTTPRequestSession *) *con_cls;
	if (!session->data_handled && !httpd->handle_query(http_method, connection, std::string(url),
		std::string(upload_data, *upload_data_size), session->result)) {
		session->result = std::string(BAD_REQUEST);
	}

	// When post data is available, reinit the data_size because this function
	// is called another time. And mark the current session as handled
	if (*upload_data_size > 0) {
		*upload_data_size = 0;
		session->data_handled = true;
		return MHD_YES;
	}

	response = MHD_create_response_from_buffer(session->result.length(),
		(void *) session->result.c_str(), MHD_RESPMEM_MUST_COPY);
	ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
	MHD_destroy_response(response);

	// clear context pointer
	delete session;
	*con_cls = NULL;
	return ret;
}

void HTTPServer::request_completed(void *cls, struct MHD_Connection *connection,
		void **con_cls, MHD_RequestTerminationCode toe)
{
}

bool HTTPServer::handle_query(HTTPMethod m, MHD_Connection *conn, const std::string &url,
	const std::string &upload_data, std::string &result)
{
	assert(m < HTTP_METHOD_MAX);

	HTTPServerReqHandlerMap::const_iterator url_handler = m_handlers[m].find(url);
	if (url_handler == m_handlers[m].end()) {
		return false;
	}

	// Read which params we want and store them
	HTTPQuery q;

	q.url = url;
	MHD_get_connection_values(conn, MHD_HEADER_KIND, &HTTPServer::mhd_iter_headers, &q);
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND, &HTTPServer::mhd_iter_getargs, &q);

	const auto ct_itr = q.headers.find("Content-Type");
	if (ct_itr != q.headers.end()) {
		if (ct_itr->second == "application/x-www-form-urlencoded") {
			// Abort if upload_data is invalid
			if (!parse_post_data(upload_data, q)) {
				return false;
			}
		}
	}

	return url_handler->second(q, result);
}

int HTTPServer::mhd_iter_headers(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->headers[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

int HTTPServer::mhd_iter_getargs(void *cls, MHD_ValueKind, const char *key,
	const char *value)
{
	HTTPQuery *q = (HTTPQuery *) cls;
	if (q && key && value) {
		q->get_params[std::string(key)] = std::string(value);
	}
	return MHD_YES; // continue iteration
}

bool HTTPServer::parse_post_data(const std::string &data, HTTPQuery &q)
{
	std::vector<std::string> first_split;
	str_split(data, '&', first_split);

	for (const auto &s: first_split) {
		// If this post data is empty, abort
		if (s.empty()) {
			return false;
		}

		std::vector<std::string> kv;
		str_split(s, '=', kv);

		// If the key value pair is invalid, abort
		if (kv.size() != 2 || kv[0].empty() || kv[1].empty()) {
			return false;
		}

		q.post_data[kv[0]] = kv[1];
	}

	return true;
}
<|endoftext|>