<commit_before>#include "shape.hpp"

#include "glm/gtx/rotate_vector.hpp"

#include "utils.hpp"

namespace trac0r {

const glm::vec3 Shape::pos(const Shape &shape) {
    return shape.m_pos;
}

void Shape::set_pos(Shape &shape, glm::vec3 new_pos) {
    shape.m_pos = new_pos;
}

const glm::vec3 Shape::orientation(const Shape &shape) {
    return shape.m_orientation;
}

void Shape::set_orientation(Shape &shape, glm::vec3 new_orientation) {
    shape.m_orientation = new_orientation;
}

const glm::vec3 Shape::scale(const Shape &shape) {
    return shape.m_scale;
}

void Shape::set_scale(Shape &shape, glm::vec3 new_scale) {
    shape.m_scale = new_scale;
}

AABB &Shape::aabb(Shape &shape) {
    return shape.m_aabb;
}

const AABB &Shape::aabb(const Shape &shape) {
    return shape.m_aabb;
}

std::vector<Triangle> &Shape::triangles(Shape &shape) {
    return shape.m_triangles;
}

const std::vector<Triangle> &Shape::triangles(const Shape &shape) {
    return shape.m_triangles;
}

void Shape::add_triangle(Shape &shape, const Triangle triangle) {
    shape.m_triangles.push_back(triangle);
}

Shape Shape::make_box(glm::vec3 pos, glm::vec3 orientation, glm::vec3 size, Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, glm::normalize(orientation));
    Shape::set_scale(new_shape, size);

    auto p1 = glm::vec3{-0.5f, 0.5f, -0.5f};
    auto p2 = glm::vec3{-0.5f, -0.5f, -0.5f};
    auto p3 = glm::vec3{0.5f, -0.5f, -0.5f};
    auto p4 = glm::vec3{0.5f, 0.5f, -0.5f};
    auto p5 = glm::vec3{-0.5f, 0.5f, 0.5f};
    auto p6 = glm::vec3{-0.5f, -0.5f, 0.5f};
    auto p7 = glm::vec3{0.5f, -0.5f, 0.5f};
    auto p8 = glm::vec3{0.5f, 0.5f, 0.5f};

    // front face
    auto t1 = Triangle(p2, p1, p3, material);
    auto t2 = Triangle(p1, p4, p3, material);

    // right face
    auto t3 = Triangle(p4, p3, p8, material);
    auto t4 = Triangle(p3, p7, p8, material);

    // left face
    auto t5 = Triangle(p1, p2, p6, material);
    auto t6 = Triangle(p5, p1, p6, material);

    // back face
    auto t7 = Triangle(p5, p6, p8, material);
    auto t8 = Triangle(p6, p7, p8, material);

    // top face
    auto t9 = Triangle(p5, p1, p4, material);
    auto t10 = Triangle(p8, p4, p5, material);

    // bottom face
    auto t11 = Triangle(p2, p3, p6, material);
    auto t12 = Triangle(p3, p7, p6, material);

    Shape::add_triangle(new_shape, t1);
    Shape::add_triangle(new_shape, t2);
    Shape::add_triangle(new_shape, t3);
    Shape::add_triangle(new_shape, t4);
    Shape::add_triangle(new_shape, t5);
    Shape::add_triangle(new_shape, t6);
    Shape::add_triangle(new_shape, t7);
    Shape::add_triangle(new_shape, t8);
    Shape::add_triangle(new_shape, t9);
    Shape::add_triangle(new_shape, t10);
    Shape::add_triangle(new_shape, t11);
    Shape::add_triangle(new_shape, t12);

    glm::mat4 translation = glm::translate(pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(size);
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

Shape Shape::make_icosphere(glm::vec3 pos, glm::vec3 orientation, float radius, size_t iterations,
                            Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, glm::normalize(orientation));
    Shape::set_scale(new_shape, glm::vec3(radius, radius, radius));

    float t = 0.5 + glm::sqrt(5) / 2.f;

    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {-t, 0, 1}, {0, 1, t}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {0, 1, t}, {1, t, 0}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {1, t, 0}, {0, 1, -t}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {0, 1, -t}, {-t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {-t, 0, -1}, {-t, 0, 1}, material});

    triangles(new_shape).push_back(Triangle{{1, t, 0}, {0, 1, t}, {t, 0, 1}, material});
    triangles(new_shape).push_back(Triangle{{0, 1, t}, {-t, 0, 1}, {0, -1, t}, material});
    triangles(new_shape).push_back(Triangle{{-t, 0, 1}, {-t, 0, -1}, {-1, -t, 0}, material});
    triangles(new_shape).push_back(Triangle{{-t, 0, -1}, {0, 1, -t}, {0, -1, -t}, material});
    triangles(new_shape).push_back(Triangle{{0, 1, -t}, {1, t, 0}, {t, 0, -1}, material});

    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {t, 0, 1}, {0, -1, t}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {0, -1, t}, {-1, -t, 0}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {-1, -t, 0}, {0, -1, -t}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {0, -1, -t}, {t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {t, 0, -1}, {t, 0, 1}, material});

    triangles(new_shape).push_back(Triangle{{0, -1, t}, {t, 0, 1}, {0, 1, t}, material});
    triangles(new_shape).push_back(Triangle{{-1, -t, 0}, {0, -1, t}, {-t, 0, 1}, material});
    triangles(new_shape).push_back(Triangle{{0, -1, -t}, {-1, -t, 0}, {-t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{t, 0, -1}, {0, -1, -t}, {0, 1, -t}, material});
    triangles(new_shape).push_back(Triangle{{t, 0, 1}, {t, 0, -1}, {1, t, 0}, material});
    rebuild(new_shape);

    for (size_t i = 0; i < iterations; i++) {
        std::vector<Triangle> new_triangles;
        for (const auto &tri : triangles(new_shape)) {
            glm::vec3 a = glm::normalize(get_middle_point(tri.m_v1, tri.m_v2));
            glm::vec3 b = glm::normalize(get_middle_point(tri.m_v2, tri.m_v3));
            glm::vec3 c = glm::normalize(get_middle_point(tri.m_v3, tri.m_v1));

            new_triangles.push_back(Triangle{glm::normalize(tri.m_v1), a, c, material});
            new_triangles.push_back(Triangle{glm::normalize(tri.m_v2), b, a, material});
            new_triangles.push_back(Triangle{glm::normalize(tri.m_v3), c, b, material});
            new_triangles.push_back(Triangle{a, b, c, material});
        }

        new_shape.m_triangles = new_triangles;
    }

    glm::mat4 translation = glm::translate(pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(Shape::scale(new_shape));
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

Shape Shape::make_plane(glm::vec3 pos, glm::vec3 orientation, glm::vec2 size, Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, glm::normalize(orientation));
    Shape::set_scale(new_shape, glm::vec3(size.x, 0, size.y));

    auto p1 = glm::vec3{-0.5f, 0, 0.5f};
    auto p2 = glm::vec3{-0.5f, 0, -0.5f};
    auto p3 = glm::vec3{0.5f, 0, -0.5f};
    auto p4 = glm::vec3{0.5f, 0, 0.5f};

    auto triangle_left = Triangle(p2, p1, p3, material);
    auto triangle_right = Triangle(p1, p4, p3, material);

    Shape::add_triangle(new_shape, triangle_left);
    Shape::add_triangle(new_shape, triangle_right);

    glm::mat4 translation = glm::translate(pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(Shape::scale(new_shape));
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

void Shape::rebuild(Shape &shape) {
    auto &aabb = Shape::aabb(shape);
    AABB::reset(aabb);
    for (auto &tri : Shape::triangles(shape)) {
        AABB::extend(aabb, tri.m_v1);
        AABB::extend(aabb, tri.m_v2);
        AABB::extend(aabb, tri.m_v3);
    }
}
}
<commit_msg>Start matrix fixes<commit_after>#include "shape.hpp"

#include "glm/gtx/rotate_vector.hpp"

#include "utils.hpp"

namespace trac0r {

const glm::vec3 Shape::pos(const Shape &shape) {
    return shape.m_pos;
}

void Shape::set_pos(Shape &shape, glm::vec3 new_pos) {
    shape.m_pos = new_pos;
}

const glm::vec3 Shape::orientation(const Shape &shape) {
    return shape.m_orientation;
}

void Shape::set_orientation(Shape &shape, glm::vec3 new_orientation) {
    shape.m_orientation = new_orientation;
}

const glm::vec3 Shape::scale(const Shape &shape) {
    return shape.m_scale;
}

void Shape::set_scale(Shape &shape, glm::vec3 new_scale) {
    shape.m_scale = new_scale;
}

AABB &Shape::aabb(Shape &shape) {
    return shape.m_aabb;
}

const AABB &Shape::aabb(const Shape &shape) {
    return shape.m_aabb;
}

std::vector<Triangle> &Shape::triangles(Shape &shape) {
    return shape.m_triangles;
}

const std::vector<Triangle> &Shape::triangles(const Shape &shape) {
    return shape.m_triangles;
}

void Shape::add_triangle(Shape &shape, const Triangle triangle) {
    shape.m_triangles.push_back(triangle);
}

Shape Shape::make_box(glm::vec3 pos, glm::vec3 orientation, glm::vec3 size, Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, orientation);
    Shape::set_scale(new_shape, size);

    auto p1 = glm::vec3{-0.5f, 0.5f, -0.5f};
    auto p2 = glm::vec3{-0.5f, -0.5f, -0.5f};
    auto p3 = glm::vec3{0.5f, -0.5f, -0.5f};
    auto p4 = glm::vec3{0.5f, 0.5f, -0.5f};
    auto p5 = glm::vec3{-0.5f, 0.5f, 0.5f};
    auto p6 = glm::vec3{-0.5f, -0.5f, 0.5f};
    auto p7 = glm::vec3{0.5f, -0.5f, 0.5f};
    auto p8 = glm::vec3{0.5f, 0.5f, 0.5f};

    // front face
    auto t1 = Triangle(p2, p1, p3, material);
    auto t2 = Triangle(p1, p4, p3, material);

    // right face
    auto t3 = Triangle(p4, p3, p8, material);
    auto t4 = Triangle(p3, p7, p8, material);

    // left face
    auto t5 = Triangle(p1, p2, p6, material);
    auto t6 = Triangle(p5, p1, p6, material);

    // back face
    auto t7 = Triangle(p5, p6, p8, material);
    auto t8 = Triangle(p6, p7, p8, material);

    // top face
    auto t9 = Triangle(p5, p1, p4, material);
    auto t10 = Triangle(p8, p4, p5, material);

    // bottom face
    auto t11 = Triangle(p2, p3, p6, material);
    auto t12 = Triangle(p3, p7, p6, material);

    Shape::add_triangle(new_shape, t1);
    Shape::add_triangle(new_shape, t2);
    Shape::add_triangle(new_shape, t3);
    Shape::add_triangle(new_shape, t4);
    Shape::add_triangle(new_shape, t5);
    Shape::add_triangle(new_shape, t6);
    Shape::add_triangle(new_shape, t7);
    Shape::add_triangle(new_shape, t8);
    Shape::add_triangle(new_shape, t9);
    Shape::add_triangle(new_shape, t10);
    Shape::add_triangle(new_shape, t11);
    Shape::add_triangle(new_shape, t12);

    glm::mat4 translation = glm::translate(glm::mat4(1.f), pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(glm::mat4(1.f), size);
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

Shape Shape::make_icosphere(glm::vec3 pos, glm::vec3 orientation, float radius, size_t iterations,
                            Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, glm::normalize(orientation));
    Shape::set_scale(new_shape, glm::vec3(radius, radius, radius));

    float t = 0.5 + glm::sqrt(5) / 2.f;

    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {-t, 0, 1}, {0, 1, t}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {0, 1, t}, {1, t, 0}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {1, t, 0}, {0, 1, -t}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {0, 1, -t}, {-t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{-1, t, 0}, {-t, 0, -1}, {-t, 0, 1}, material});

    triangles(new_shape).push_back(Triangle{{1, t, 0}, {0, 1, t}, {t, 0, 1}, material});
    triangles(new_shape).push_back(Triangle{{0, 1, t}, {-t, 0, 1}, {0, -1, t}, material});
    triangles(new_shape).push_back(Triangle{{-t, 0, 1}, {-t, 0, -1}, {-1, -t, 0}, material});
    triangles(new_shape).push_back(Triangle{{-t, 0, -1}, {0, 1, -t}, {0, -1, -t}, material});
    triangles(new_shape).push_back(Triangle{{0, 1, -t}, {1, t, 0}, {t, 0, -1}, material});

    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {t, 0, 1}, {0, -1, t}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {0, -1, t}, {-1, -t, 0}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {-1, -t, 0}, {0, -1, -t}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {0, -1, -t}, {t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{1, -t, 0}, {t, 0, -1}, {t, 0, 1}, material});

    triangles(new_shape).push_back(Triangle{{0, -1, t}, {t, 0, 1}, {0, 1, t}, material});
    triangles(new_shape).push_back(Triangle{{-1, -t, 0}, {0, -1, t}, {-t, 0, 1}, material});
    triangles(new_shape).push_back(Triangle{{0, -1, -t}, {-1, -t, 0}, {-t, 0, -1}, material});
    triangles(new_shape).push_back(Triangle{{t, 0, -1}, {0, -1, -t}, {0, 1, -t}, material});
    triangles(new_shape).push_back(Triangle{{t, 0, 1}, {t, 0, -1}, {1, t, 0}, material});
    rebuild(new_shape);

    for (size_t i = 0; i < iterations; i++) {
        std::vector<Triangle> new_triangles;
        for (const auto &tri : triangles(new_shape)) {
            glm::vec3 a = glm::normalize(get_middle_point(tri.m_v1, tri.m_v2));
            glm::vec3 b = glm::normalize(get_middle_point(tri.m_v2, tri.m_v3));
            glm::vec3 c = glm::normalize(get_middle_point(tri.m_v3, tri.m_v1));

            new_triangles.push_back(Triangle{glm::normalize(tri.m_v1), a, c, material});
            new_triangles.push_back(Triangle{glm::normalize(tri.m_v2), b, a, material});
            new_triangles.push_back(Triangle{glm::normalize(tri.m_v3), c, b, material});
            new_triangles.push_back(Triangle{a, b, c, material});
        }

        new_shape.m_triangles = new_triangles;
    }

    glm::mat4 translation = glm::translate(pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(Shape::scale(new_shape));
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

Shape Shape::make_plane(glm::vec3 pos, glm::vec3 orientation, glm::vec2 size, Material material) {
    Shape new_shape;
    Shape::set_pos(new_shape, pos);
    Shape::set_orientation(new_shape, glm::normalize(orientation));
    Shape::set_scale(new_shape, glm::vec3(size.x, 0, size.y));

    auto p1 = glm::vec3{-0.5f, 0, 0.5f};
    auto p2 = glm::vec3{-0.5f, 0, -0.5f};
    auto p3 = glm::vec3{0.5f, 0, -0.5f};
    auto p4 = glm::vec3{0.5f, 0, 0.5f};

    auto triangle_left = Triangle(p2, p1, p3, material);
    auto triangle_right = Triangle(p1, p4, p3, material);

    Shape::add_triangle(new_shape, triangle_left);
    Shape::add_triangle(new_shape, triangle_right);

    glm::mat4 translation = glm::translate(pos);
    glm::mat4 rotation = glm::orientation(orientation, {0, 1, 0});
    glm::mat4 scale = glm::scale(Shape::scale(new_shape));
    glm::mat4 model = translation * rotation * scale;

    for (auto &tri : triangles(new_shape)) {
        tri.m_v1 = glm::vec3(model * glm::vec4(tri.m_v1, 1));
        tri.m_v2 = glm::vec3(model * glm::vec4(tri.m_v2, 1));
        tri.m_v3 = glm::vec3(model * glm::vec4(tri.m_v3, 1));
        tri.rebuild();
    }

    rebuild(new_shape);

    return new_shape;
}

void Shape::rebuild(Shape &shape) {
    auto &aabb = Shape::aabb(shape);
    AABB::reset(aabb);
    for (auto &tri : Shape::triangles(shape)) {
        AABB::extend(aabb, tri.m_v1);
        AABB::extend(aabb, tri.m_v2);
        AABB::extend(aabb, tri.m_v3);
    }
}
}
<|endoftext|>


<commit_before>#ifndef UTILS_HPP
#define UTILS_HPP

#include <glm/glm.hpp>

#include <SDL.h>
#include <SDL_ttf.h>

#include <cmath>
#include <string>
#include <iostream>

namespace trac0r {

SDL_Texture *make_text(SDL_Renderer *renderer, TTF_Font *font, std::string text,
                       const SDL_Color &color) {
    auto text_surface = TTF_RenderText_Blended(font, text.c_str(), color);
    auto text_tex = SDL_CreateTextureFromSurface(renderer, text_surface);
    SDL_FreeSurface(text_surface);

    return text_tex;
}

void render_text(SDL_Renderer *renderer, SDL_Texture *texture, int pos_x, int pos_y) {
    int tex_width;
    int tex_height;

    SDL_QueryTexture(texture, 0, 0, &tex_width, &tex_height);
    SDL_Rect rect{pos_x, pos_y, tex_width, tex_height};
    SDL_RenderCopy(renderer, texture, 0, &rect);
}

uint32_t pack_color_argb(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    uint32_t new_color = a << 24 | r << 16 | g << 8 | b;
    return new_color;
}

uint32_t pack_color_argb(glm::i8vec4 color) {
    uint32_t new_color = color.a << 24 | color.r << 16 | color.g << 8 | color.b;
    return new_color;
}

uint32_t pack_color_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
    uint32_t packed_color = r << 24 | g << 16 | b << 8 | a;
    return packed_color;
}

uint32_t pack_color_rgba(glm::i8vec4 color) {
    uint32_t packed_color = color.r << 24 | color.g << 16 | color.b << 8 | color.a;
    return packed_color;
}

uint32_t pack_color_rgba(glm::vec4 color) {
    uint32_t packed_color = int(std::round(color.r * 255)) << 24 |
                            int(std::round(color.g * 255)) << 16 |
                            int(std::round(color.b * 255)) << 8 | int(std::round(color.a * 255));
    return packed_color;
}

uint32_t pack_color_argb(glm::vec4 color) {
    uint32_t packed_color = int(std::round(color.a * 255)) << 24 |
                            int(std::round(color.r * 255)) << 16 |
                            int(std::round(color.g * 255)) << 8 | int(std::round(color.b * 255));
    return packed_color;
}

glm::i8vec4 unpack_color_rgba_to_i8vec4(uint32_t packed_color_rgba) {
    glm::i8vec4 unpacked_color;
    unpacked_color.r = packed_color_rgba >> 24 & 0xFF;
    unpacked_color.g = packed_color_rgba >> 16 & 0xFF;
    unpacked_color.b = packed_color_rgba >> 8 & 0xFF;
    unpacked_color.a = packed_color_rgba & 0xFF;
    return unpacked_color;
}

glm::i8vec4 unpack_color_argb_to_i8vec4(uint32_t packed_color_argb) {
    glm::i8vec4 unpacked_color;
    unpacked_color.a = packed_color_argb >> 24 & 0xFF;
    unpacked_color.r = packed_color_argb >> 16 & 0xFF;
    unpacked_color.g = packed_color_argb >> 8 & 0xFF;
    unpacked_color.b = packed_color_argb & 0xFF;
    return unpacked_color;
}

glm::vec4 unpack_color_rgbb_to_vec4(uint32_t packed_color_rgba) {
    glm::i8vec4 unpacked_color;
    unpacked_color.r = (packed_color_rgba >> 24 & 0xFF) / 255.f;
    unpacked_color.g = (packed_color_rgba >> 16 & 0xFF) / 255.f;
    unpacked_color.b = (packed_color_rgba >> 8 & 0xFF) / 255.f;
    unpacked_color.a = (packed_color_rgba & 0xFF) / 255.f;
    return unpacked_color;
}

glm::vec4 unpack_color_argb_to_vec4(uint32_t packed_color_argb) {
    glm::i8vec4 unpacked_color;
    unpacked_color.a = (packed_color_argb >> 24 & 0xFF) / 255.f;
    unpacked_color.r = (packed_color_argb >> 16 & 0xFF) / 255.f;
    unpacked_color.g = (packed_color_argb >> 8 & 0xFF) / 255.f;
    unpacked_color.b = (packed_color_argb & 0xFF) / 255.f;
    return unpacked_color;
}
}

#endif /* end of include guard: UTILS_HPP */
<commit_msg>Fix typo<commit_after>#ifndef UTILS_HPP
#define UTILS_HPP

#include <glm/glm.hpp>

#include <SDL.h>
#include <SDL_ttf.h>

#include <cmath>
#include <string>
#include <iostream>

namespace trac0r {

SDL_Texture *make_text(SDL_Renderer *renderer, TTF_Font *font, std::string text,
                       const SDL_Color &color) {
    auto text_surface = TTF_RenderText_Blended(font, text.c_str(), color);
    auto text_tex = SDL_CreateTextureFromSurface(renderer, text_surface);
    SDL_FreeSurface(text_surface);

    return text_tex;
}

void render_text(SDL_Renderer *renderer, SDL_Texture *texture, int pos_x, int pos_y) {
    int tex_width;
    int tex_height;

    SDL_QueryTexture(texture, 0, 0, &tex_width, &tex_height);
    SDL_Rect rect{pos_x, pos_y, tex_width, tex_height};
    SDL_RenderCopy(renderer, texture, 0, &rect);
}

uint32_t pack_color_argb(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
    uint32_t new_color = a << 24 | r << 16 | g << 8 | b;
    return new_color;
}

uint32_t pack_color_argb(glm::i8vec4 color) {
    uint32_t new_color = color.a << 24 | color.r << 16 | color.g << 8 | color.b;
    return new_color;
}

uint32_t pack_color_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
    uint32_t packed_color = r << 24 | g << 16 | b << 8 | a;
    return packed_color;
}

uint32_t pack_color_rgba(glm::i8vec4 color) {
    uint32_t packed_color = color.r << 24 | color.g << 16 | color.b << 8 | color.a;
    return packed_color;
}

uint32_t pack_color_rgba(glm::vec4 color) {
    uint32_t packed_color = int(std::round(color.r * 255)) << 24 |
                            int(std::round(color.g * 255)) << 16 |
                            int(std::round(color.b * 255)) << 8 | int(std::round(color.a * 255));
    return packed_color;
}

uint32_t pack_color_argb(glm::vec4 color) {
    uint32_t packed_color = int(std::round(color.a * 255)) << 24 |
                            int(std::round(color.r * 255)) << 16 |
                            int(std::round(color.g * 255)) << 8 | int(std::round(color.b * 255));
    return packed_color;
}

glm::i8vec4 unpack_color_rgba_to_i8vec4(uint32_t packed_color_rgba) {
    glm::i8vec4 unpacked_color;
    unpacked_color.r = packed_color_rgba >> 24 & 0xFF;
    unpacked_color.g = packed_color_rgba >> 16 & 0xFF;
    unpacked_color.b = packed_color_rgba >> 8 & 0xFF;
    unpacked_color.a = packed_color_rgba & 0xFF;
    return unpacked_color;
}

glm::i8vec4 unpack_color_argb_to_i8vec4(uint32_t packed_color_argb) {
    glm::i8vec4 unpacked_color;
    unpacked_color.a = packed_color_argb >> 24 & 0xFF;
    unpacked_color.r = packed_color_argb >> 16 & 0xFF;
    unpacked_color.g = packed_color_argb >> 8 & 0xFF;
    unpacked_color.b = packed_color_argb & 0xFF;
    return unpacked_color;
}

glm::vec4 unpack_color_rgbb_to_vec4(uint32_t packed_color_rgba) {
    glm::i8vec4 unpacked_color;
    unpacked_color.r = (packed_color_rgba >> 24 & 0xFF) / 255.f;
    unpacked_color.g = (packed_color_rgba >> 16 & 0xFF) / 255.f;
    unpacked_color.b = (packed_color_rgba >> 8 & 0xFF) / 255.f;
    unpacked_color.a = (packed_color_rgba & 0xFF) / 255.f;
    return unpacked_color;
}

glm::vec4 unpack_color_argb_to_vec4(uint32_t packed_color_argb) {
    glm::vec4 unpacked_color;
    unpacked_color.a = (packed_color_argb >> 24 & 0xFF) / 255.f;
    unpacked_color.r = (packed_color_argb >> 16 & 0xFF) / 255.f;
    unpacked_color.g = (packed_color_argb >> 8 & 0xFF) / 255.f;
    unpacked_color.b = (packed_color_argb & 0xFF) / 255.f;
    return unpacked_color;
}
}

#endif /* end of include guard: UTILS_HPP */
<|endoftext|>


<commit_before>#include "photoeffects.hpp"
#include <math.h>

using namespace cv;

#define MAX_KERNELSIZE 15

int edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft)
{
    CV_Assert(src.type() == CV_8UC3);
    dst.create(src.size(), src.type());
    Mat image = src.getMat(), outputImage = dst.getMat();

    CV_Assert(indentTop >= 0 && indentTop <= (image.rows / 2 - 10));
    CV_Assert(indentLeft >= 0 && indentLeft <= (image.cols / 2 - 10));

    float halfWidth = (image.cols / 2.0f) * (image.cols / 2.0f);
    float halfHeight = (image.rows / 2.0f) * (image.rows / 2.0f);
    float a = (image.cols / 2.0f - indentLeft)
            * (image.cols / 2.0f - indentLeft);
    float b = (image.rows / 2.0f - indentTop)
            * (image.rows / 2.0f - indentTop);
    int kSizeEdges = halfWidth / a + halfHeight / b;

    kSizeEdges = MIN(kSizeEdges, MAX_KERNELSIZE);
    Mat bearingImage(image.rows + 2 * kSizeEdges,
                    image.cols + 2 * kSizeEdges,
                    CV_8UC3);
    copyMakeBorder(image, bearingImage, kSizeEdges, kSizeEdges,
        kSizeEdges, kSizeEdges, BORDER_REPLICATE);

    for (int i = kSizeEdges; i < bearingImage.rows - kSizeEdges; i++)
    {
        for (int j = kSizeEdges; j < bearingImage.cols - kSizeEdges; j++)
        {
            int size;
            Vec3f sumF;
            Vec3b Color;
            float sumC = 0.0f, coeff;
            float bearHalfWidth = bearingImage.cols / 2.0f;
            float bearHalfHeight = bearingImage.rows / 2.0f;
            float radius = (bearHalfHeight - i)
                    * (bearHalfHeight - i)
                    / b

                    + (bearHalfWidth - j)
                    * (bearHalfWidth - j)
                    / a;
            if (radius < 1.0f)
            {
                outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) =
                    bearingImage.at<Vec3b>(i, j);
                continue;
            }
            size = radius;
            radius = 2.0f * (radius - 0.5f) * (radius - 0.5f);
            size = MIN(size, kSizeEdges);
            for (int x = -size; x <= size; x++)
            {
                for (int y = -size; y <= size; y++)
                {
                    coeff = 1.0f / (CV_PI * radius)
                            * exp(- (x * x + y * y) / radius);

                    Color = bearingImage.at<Vec3b>(x + i, y + j);
                    sumF += coeff * Color;
                    sumC += coeff;
                }
            }
            sumF *= (1.0f / sumC);
            outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) = sumF;
        }
    }

    return 0;
}
<commit_msg>Corrected<commit_after>#include "photoeffects.hpp"
#include <math.h>

using namespace cv;

#define MAX_KERNELSIZE 15

int edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft)
{
    CV_Assert(src.type() == CV_8UC3);
    dst.create(src.size(), src.type());
    Mat image = src.getMat(), outputImage = dst.getMat();

    CV_Assert(indentTop >= 0 && indentTop <= (image.rows / 2 - 10));
    CV_Assert(indentLeft >= 0 && indentLeft <= (image.cols / 2 - 10));

    float halfWidth = image.cols / 2.0f;
    float halfHeight = image.rows / 2.0f;
    float a = (image.cols / 2.0f - indentLeft)
            * (image.cols / 2.0f - indentLeft);
    float b = (image.rows / 2.0f - indentTop)
            * (image.rows / 2.0f - indentTop);
    int kSizeEdges = halfWidth * halfWidth / a + halfHeight * halfHeight / b;

    kSizeEdges = MIN(kSizeEdges, MAX_KERNELSIZE);
    Mat bearingImage(image.rows + 2 * kSizeEdges,
                    image.cols + 2 * kSizeEdges,
                    CV_8UC3);
    copyMakeBorder(image, bearingImage, kSizeEdges, kSizeEdges,
        kSizeEdges, kSizeEdges, BORDER_REPLICATE);

    for (int i = kSizeEdges; i < bearingImage.rows - kSizeEdges; i++)
    {
        for (int j = kSizeEdges; j < bearingImage.cols - kSizeEdges; j++)
        {
            int size;
            Vec3f sumF;
            Vec3b Color;
            float sumC = 0.0f, coeff;
            float radius = (halfHeight - i)
                    * (halfHeight- i)
                    / b

                    + (halfWidth - j)
                    * (halfHeight - j)
                    / a;
            if (radius < 1.0f)
            {
                outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) =
                    bearingImage.at<Vec3b>(i, j);
                continue;
            }
            size = radius;
            radius = 2.0f * (radius - 0.5f) * (radius - 0.5f);
            size = MIN(size, kSizeEdges);
            for (int x = -size; x <= size; x++)
            {
                for (int y = -size; y <= size; y++)
                {
                    coeff = 1.0f / (CV_PI * radius)
                            * exp(- (x * x + y * y) / radius);

                    Color = bearingImage.at<Vec3b>(x + i, y + j);
                    sumF += coeff * (Vec3f)Color;
                    sumC += coeff;
                }
            }
            sumF *= (1.0f / sumC);
            outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) = sumF;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
    This file is part of KOrganizer.
    Copyright (c) 1999 Preston Brown, Ian Dawes

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qkeycode.h>
#include <qcombobox.h>
#include <qdatetime.h>
#include <qlineedit.h>

#include <kmessagebox.h>
#include <kglobal.h>
#include <kdebug.h>
#include <klocale.h>

#include "ktimeedit.h"
#include <qvalidator.h>
#include "ktimeedit.moc"

// Validator for a time value with only hours and minutes (no seconds)
// Mostly locale aware. Author: David Faure <faure@kde.org>
class KOTimeValidator : public QValidator
{
public:
    KOTimeValidator(QWidget* parent, const char* name=0) : QValidator(parent, name) {}

    virtual State validate(QString& str, int& /*cursorPos*/) const
    {
        int length = str.length();
        // empty string is intermediate so one can clear the edit line and start from scratch
        if ( length <= 0 )
            return Intermediate;

        bool ok = false;
        /*QTime time =*/ KGlobal::locale()->readTime(str, KLocale::WithoutSeconds, &ok);
        if ( ok )
            return Acceptable;
//         kdDebug(5300)<<"Time "<<str<<" not directly acceptable, trying military format "<<endl;
        // Also try to accept times in "military format", i.e. no delimiter, like 1200
        int tm = str.toInt( &ok );
        if ( ok && ( 0 <= tm ) ) {
          if ( ( tm < 2400 ) && ( tm%100 < 60 ) )
            return Acceptable;
          else
            return Intermediate;
        }
//         kdDebug(5300)<<str<<" not acceptable or intermediate for military format, either "<<str<<endl;

        // readTime doesn't help knowing when the string is "Intermediate".
        // HACK. Not fully locale aware etc. (esp. the separator is '.' in sv_SE...)
        QChar sep = ':';
        // I want to allow "HH:", ":MM" and ":" to make editing easier
        if ( str[0] == sep )
        {
            if ( length == 1 ) // just ":"
                return Intermediate;
            QString minutes = str.mid(1);
            int m = minutes.toInt(&ok);
            if ( ok && m >= 0 && m < 60 )
                return Intermediate;
        } else if ( str[str.length()-1] == sep )
        {
            QString hours = str.left(length-1);
            int h = hours.toInt(&ok);
            if ( ok && h >= 0 && h < 24 )
                return Intermediate;
        }
        return Invalid;
    }
    virtual void fixup ( QString & input ) const {
      bool ok = false;
      KGlobal::locale()->readTime( input, KLocale::WithoutSeconds, &ok );
      if ( !ok ) {
        // Also try to accept times in "military format", i.e. no delimiter, like 1200
        int tm = input.toInt( &ok );
        if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
          input = KGlobal::locale()->formatTime( QTime( tm / 100, tm % 100, 0 ) );
        }
      }
    }
};

// KTimeWidget/QTimeEdit provide nicer editing, but don't provide a combobox.
// Difficult to get all in one...
// But Qt-3.2 will offer QLineEdit::setMask, so a "99:99" mask would help.
KTimeEdit::KTimeEdit( QWidget *parent, QTime qt, const char *name )
  : QComboBox( true, parent, name )
{
  setInsertionPolicy( NoInsertion );
  setValidator( new KOTimeValidator( this ) );

  mTime = qt;

//  mNoTimeString = i18n("No Time");
//  insertItem( mNoTimeString );

  // Fill combo box with selection of times in localized format.
  QTime timeEntry(0,0,0);
  do {
    insertItem(KGlobal::locale()->formatTime(timeEntry));
    timeEntry = timeEntry.addSecs(60*15);
  } while (!timeEntry.isNull());
  // Add end of day.
  insertItem( KGlobal::locale()->formatTime( QTime( 23, 59, 59 ) ) );

  updateText();
  setFocusPolicy(QWidget::StrongFocus);

  connect(this, SIGNAL(activated(int)), this, SLOT(active(int)));
  connect(this, SIGNAL(highlighted(int)), this, SLOT(hilit(int)));
  connect(this, SIGNAL(textChanged(const QString&)),this,SLOT(changedText()));
}

KTimeEdit::~KTimeEdit()
{
}

bool KTimeEdit::hasTime() const
{
  // Can't happen
  if ( currentText().isEmpty() ) return false;
  //if ( currentText() == mNoTimeString ) return false;

  return true; // always
}

QTime KTimeEdit::getTime() const
{
  //kdDebug(5300) << "KTimeEdit::getTime(), currentText() = " << currentText() << endl;
  // TODO use KLocale::WithoutSeconds in HEAD
  bool ok = false;
  QTime time = KGlobal::locale()->readTime( currentText(), KLocale::WithoutSeconds, &ok );
  if ( !ok ) {
    // Also try to accept times in "military format", i.e. no delimiter, like 1200
    int tm = currentText().toInt( &ok );
    if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
      time.setHMS( tm / 100, tm % 100, 0 );
    } else {
      ok = false;
    }
  }
  kdDebug(5300) << "KTimeEdit::getTime(): " << time.toString() << endl;
  return time;
}

QSizePolicy  KTimeEdit::sizePolicy() const
{
  // Set size policy to Fixed, because edit cannot contain more text than the
  // string representing the time. It doesn't make sense to provide more space.
  QSizePolicy sizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);

  return sizePolicy;
}

void KTimeEdit::setTime(QTime newTime)
{
  if ( mTime != newTime )
  {
    kdDebug(5300) << "KTimeEdit::setTime(): " << newTime.toString() << endl;

    mTime = newTime;
    updateText();
  }
}

void KTimeEdit::active(int i)
{
    // The last entry, 23:59, is a special case
    if( i == count() - 1 )
        mTime = QTime( 23, 59, 0 );
    else
        mTime = QTime(0,0,0).addSecs(i*15*60);
    emit timeChanged(mTime);
}

void KTimeEdit::hilit(int )
{
  // we don't currently need to do anything here.
}

void KTimeEdit::addTime(QTime qt)
{
  // Calculate the new time.
  mTime = qt.addSecs(mTime.minute()*60+mTime.hour()*3600);
  updateText();
  emit timeChanged(mTime);
}

void KTimeEdit::subTime(QTime qt)
{
  int h, m;

  // Note that we cannot use the same method for determining the new
  // time as we did in addTime, because QTime does not handle adding
  // negative seconds well at all.
  h = mTime.hour()-qt.hour();
  m = mTime.minute()-qt.minute();

  if(m < 0) {
    m += 60;
    h -= 1;
  }

  if(h < 0) {
    h += 24;
  }

  // store the newly calculated time.
  mTime.setHMS(h, m, 0);
  updateText();
  emit timeChanged(mTime);
}

void KTimeEdit::keyPressEvent(QKeyEvent *qke)
{
  switch(qke->key()) {
  case Key_Down:
    addTime(QTime(0,1,0));
    break;
  case Key_Up:
    subTime(QTime(0,1,0));
    break;
  case Key_Prior:
    subTime(QTime(1,0,0));
    break;
  case Key_Next:
    addTime(QTime(1,0,0));
    break;
  default:
    QComboBox::keyPressEvent(qke);
    break;
  } // switch
}

void KTimeEdit::updateText()
{
//  kdDebug(5300) << "KTimeEdit::updateText() " << endl;
  QString s = KGlobal::locale()->formatTime(mTime);
  // Set the text but without emitting signals, nor losing the cursor position
  QLineEdit *line = lineEdit();
  line->blockSignals(true);
  int pos = line->cursorPosition();
  line->setText(s);
  line->setCursorPosition(pos);
  line->blockSignals(false);

//  kdDebug(5300) << "KTimeEdit::updateText(): " << s << endl;

  if (!mTime.minute() % 15) {
    setCurrentItem((mTime.hour()*4)+(mTime.minute()/15));
  }
}

bool KTimeEdit::inputIsValid() const
{
  int cursorPos = lineEdit()->cursorPosition();
  QString str = currentText();
  return validator()->validate( str, cursorPos ) == QValidator::Acceptable;
}

void KTimeEdit::changedText()
{
  //kdDebug(5300) << "KTimeEdit::changedText()" << endl;
  if ( inputIsValid() )
  {
    mTime = getTime();
    emit timeChanged(mTime);
  }
}
<commit_msg>Now that cvs head is open for commits again, apply the patch. It allows all input into time edit widgets until the dialog is closed. Without it, working with am/pm times didnt' work at all.<commit_after>/*
    This file is part of KOrganizer.
    Copyright (c) 1999 Preston Brown, Ian Dawes

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qkeycode.h>
#include <qcombobox.h>
#include <qdatetime.h>
#include <qlineedit.h>

#include <kmessagebox.h>
#include <kglobal.h>
#include <kdebug.h>
#include <klocale.h>

#include "ktimeedit.h"
#include <qvalidator.h>
#include "ktimeedit.moc"

// Validator for a time value with only hours and minutes (no seconds)
// Mostly locale aware. Author: David Faure <faure@kde.org>
class KOTimeValidator : public QValidator
{
public:
    KOTimeValidator(QWidget* parent, const char* name=0) : QValidator(parent, name) {}

    virtual State validate(QString& str, int& /*cursorPos*/) const
    {
        int length = str.length();
        // empty string is intermediate so one can clear the edit line and start from scratch
        if ( length <= 0 )
            return Intermediate;

        bool ok = false;
        /*QTime time =*/ KGlobal::locale()->readTime(str, KLocale::WithoutSeconds, &ok);
        if ( ok )
            return Acceptable;
//         kdDebug(5300)<<"Time "<<str<<" not directly acceptable, trying military format "<<endl;
        // Also try to accept times in "military format", i.e. no delimiter, like 1200
        int tm = str.toInt( &ok );
        if ( ok && ( 0 <= tm ) ) {
          if ( ( tm < 2400 ) && ( tm%100 < 60 ) )
            return Acceptable;
          else
            return Intermediate;
        }
//         kdDebug(5300)<<str<<" not acceptable or intermediate for military format, either "<<str<<endl;

        // readTime doesn't help knowing when the string is "Intermediate".
        // HACK. Not fully locale aware etc. (esp. the separator is '.' in sv_SE...)
        QChar sep = ':';
        // I want to allow "HH:", ":MM" and ":" to make editing easier
        if ( str[0] == sep )
        {
            if ( length == 1 ) // just ":"
                return Intermediate;
            QString minutes = str.mid(1);
            int m = minutes.toInt(&ok);
            if ( ok && m >= 0 && m < 60 )
                return Intermediate;
        } else if ( str[str.length()-1] == sep )
        {
            QString hours = str.left(length-1);
            int h = hours.toInt(&ok);
            if ( ok && h >= 0 && h < 24 )
                return Intermediate;
        }
//        return Invalid;
        return Intermediate;
    }
    virtual void fixup ( QString & input ) const {
      bool ok = false;
      KGlobal::locale()->readTime( input, KLocale::WithoutSeconds, &ok );
      if ( !ok ) {
        // Also try to accept times in "military format", i.e. no delimiter, like 1200
        int tm = input.toInt( &ok );
        if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
          input = KGlobal::locale()->formatTime( QTime( tm / 100, tm % 100, 0 ) );
        }
      }
    }
};

// KTimeWidget/QTimeEdit provide nicer editing, but don't provide a combobox.
// Difficult to get all in one...
// But Qt-3.2 will offer QLineEdit::setMask, so a "99:99" mask would help.
KTimeEdit::KTimeEdit( QWidget *parent, QTime qt, const char *name )
  : QComboBox( true, parent, name )
{
  setInsertionPolicy( NoInsertion );
  setValidator( new KOTimeValidator( this ) );

  mTime = qt;

//  mNoTimeString = i18n("No Time");
//  insertItem( mNoTimeString );

  // Fill combo box with selection of times in localized format.
  QTime timeEntry(0,0,0);
  do {
    insertItem(KGlobal::locale()->formatTime(timeEntry));
    timeEntry = timeEntry.addSecs(60*15);
  } while (!timeEntry.isNull());
  // Add end of day.
  insertItem( KGlobal::locale()->formatTime( QTime( 23, 59, 59 ) ) );

  updateText();
  setFocusPolicy(QWidget::StrongFocus);

  connect(this, SIGNAL(activated(int)), this, SLOT(active(int)));
  connect(this, SIGNAL(highlighted(int)), this, SLOT(hilit(int)));
  connect(this, SIGNAL(textChanged(const QString&)),this,SLOT(changedText()));
}

KTimeEdit::~KTimeEdit()
{
}

bool KTimeEdit::hasTime() const
{
  // Can't happen
  if ( currentText().isEmpty() ) return false;
  //if ( currentText() == mNoTimeString ) return false;

  return true; // always
}

QTime KTimeEdit::getTime() const
{
  //kdDebug(5300) << "KTimeEdit::getTime(), currentText() = " << currentText() << endl;
  // TODO use KLocale::WithoutSeconds in HEAD
  bool ok = false;
  QTime time = KGlobal::locale()->readTime( currentText(), KLocale::WithoutSeconds, &ok );
  if ( !ok ) {
    // Also try to accept times in "military format", i.e. no delimiter, like 1200
    int tm = currentText().toInt( &ok );
    if ( ( 0 <= tm ) && ( tm < 2400 ) && ( tm%100 < 60 ) && ok ) {
      time.setHMS( tm / 100, tm % 100, 0 );
    } else {
      ok = false;
    }
  }
  kdDebug(5300) << "KTimeEdit::getTime(): " << time.toString() << endl;
  return time;
}

QSizePolicy  KTimeEdit::sizePolicy() const
{
  // Set size policy to Fixed, because edit cannot contain more text than the
  // string representing the time. It doesn't make sense to provide more space.
  QSizePolicy sizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);

  return sizePolicy;
}

void KTimeEdit::setTime(QTime newTime)
{
  if ( mTime != newTime )
  {
    kdDebug(5300) << "KTimeEdit::setTime(): " << newTime.toString() << endl;

    mTime = newTime;
    updateText();
  }
}

void KTimeEdit::active(int i)
{
    // The last entry, 23:59, is a special case
    if( i == count() - 1 )
        mTime = QTime( 23, 59, 0 );
    else
        mTime = QTime(0,0,0).addSecs(i*15*60);
    emit timeChanged(mTime);
}

void KTimeEdit::hilit(int )
{
  // we don't currently need to do anything here.
}

void KTimeEdit::addTime(QTime qt)
{
  // Calculate the new time.
  mTime = qt.addSecs(mTime.minute()*60+mTime.hour()*3600);
  updateText();
  emit timeChanged(mTime);
}

void KTimeEdit::subTime(QTime qt)
{
  int h, m;

  // Note that we cannot use the same method for determining the new
  // time as we did in addTime, because QTime does not handle adding
  // negative seconds well at all.
  h = mTime.hour()-qt.hour();
  m = mTime.minute()-qt.minute();

  if(m < 0) {
    m += 60;
    h -= 1;
  }

  if(h < 0) {
    h += 24;
  }

  // store the newly calculated time.
  mTime.setHMS(h, m, 0);
  updateText();
  emit timeChanged(mTime);
}

void KTimeEdit::keyPressEvent(QKeyEvent *qke)
{
  switch(qke->key()) {
  case Key_Down:
    addTime(QTime(0,1,0));
    break;
  case Key_Up:
    subTime(QTime(0,1,0));
    break;
  case Key_Prior:
    subTime(QTime(1,0,0));
    break;
  case Key_Next:
    addTime(QTime(1,0,0));
    break;
  default:
    QComboBox::keyPressEvent(qke);
    break;
  } // switch
}

void KTimeEdit::updateText()
{
//  kdDebug(5300) << "KTimeEdit::updateText() " << endl;
  QString s = KGlobal::locale()->formatTime(mTime);
  // Set the text but without emitting signals, nor losing the cursor position
  QLineEdit *line = lineEdit();
  line->blockSignals(true);
  int pos = line->cursorPosition();
  line->setText(s);
  line->setCursorPosition(pos);
  line->blockSignals(false);

//  kdDebug(5300) << "KTimeEdit::updateText(): " << s << endl;

  if (!mTime.minute() % 15) {
    setCurrentItem((mTime.hour()*4)+(mTime.minute()/15));
  }
}

bool KTimeEdit::inputIsValid() const
{
  int cursorPos = lineEdit()->cursorPosition();
  QString str = currentText();
  return validator()->validate( str, cursorPos ) == QValidator::Acceptable;
}

void KTimeEdit::changedText()
{
  //kdDebug(5300) << "KTimeEdit::changedText()" << endl;
  if ( inputIsValid() )
  {
    mTime = getTime();
    emit timeChanged(mTime);
  }
}
<|endoftext|>


<commit_before>// $Id: steepestDescent.C,v 1.2 1999/08/31 22:01:17 oliver Exp $

#include <BALL/MOLMEC/MINIMIZATION/steepestDescent.h>
#include <BALL/COMMON/limits.h>

namespace BALL
{
	Size	SteepestDescentMinimizer::Default::MAX_STEPS = 6;
	float SteepestDescentMinimizer::Default::MAX_GRADIENT = 0.001;

	const char* SteepestDescentMinimizer::Option::MAX_STEPS = "max_steps";
	const char*	SteepestDescentMinimizer::Option::MAX_GRADIENT = "max_gradient";

	// default constructor
	SteepestDescentMinimizer::SteepestDescentMinimizer()
		:	EnergyMinimizer()
	{
	}

	// copy constructor
	SteepestDescentMinimizer::SteepestDescentMinimizer(const SteepestDescentMinimizer& line_search_minimizer, bool /* deep */)
		:	EnergyMinimizer(line_search_minimizer)
	{
	}

	// assignment operator
	SteepestDescentMinimizer& SteepestDescentMinimizer::operator = (const SteepestDescentMinimizer& line_search_minimizer)
	{
		EnergyMinimizer::operator = (line_search_minimizer);
		return *this;
	}

	// Constructor initialized with a force field
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field)
		:	EnergyMinimizer()
	{
    valid_ = setup(force_field);

    if (!valid_)
    {
      Log.level(LogStream::ERROR) << " line search minimizer setup failed! " << endl;
		}
	}

	// Constructor initialized with a force field and a set of options
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field, const Options& new_options)
		:	EnergyMinimizer()
	{
    valid_ = setup(force_field, new_options);

    if (!valid_)
    {
      Log.level(LogStream::ERROR) << " Line search minimizer setup failed! " << endl;
		}
	}

	// destructor
	SteepestDescentMinimizer::~SteepestDescentMinimizer()
	{
	}

	// virtual function for the specific setup of derived classes
	bool SteepestDescentMinimizer::specificSetup()
	{

		max_steps_ = (Size)options.setDefaultInteger(SteepestDescentMinimizer::Option::MAX_STEPS, (long)SteepestDescentMinimizer::Default::MAX_STEPS);
		max_gradient_ = options.setDefaultReal(SteepestDescentMinimizer::Option::MAX_GRADIENT, SteepestDescentMinimizer::Default::MAX_GRADIENT);

		return true;
	}

	// Set the parameter max_steps_
	void	SteepestDescentMinimizer::setMaxSteps(Size max_steps)
	{
		max_steps_	= max_steps;
	}

	//	Get the parameter max_steps_
	Size	SteepestDescentMinimizer::getMaxSteps() const
	{
		return max_steps_;
	}

	// Set the parameter max_gradient_
	void	SteepestDescentMinimizer::setMaxGradient(float max_gradient)
	{
		max_gradient_	= max_gradient;
	}

	//	Get the parameter max_steps_
	float	SteepestDescentMinimizer::getMaxGradient() const
	{
		return max_gradient_;
	}

	/*	The minimizer optimizes the energy of the system
			using a modified line search algorithm.
	*/

	bool SteepestDescentMinimizer::minimize(Size steps, bool restart)
	{
		// define some static variables used for restarting

		static float	step_size = maximal_shift_;	// the current step size
		static Size		last_update = 1;						// last update of gradient (in number of iterations)
		static Size		same_energy_counter = 0;		// number of times the same energy was calculated (in number of iterations)
		static float	gradient_norm = 0;					// norm of the gradient
		static float	last_energy = 0;						// energy of the last iteration
		static float	min_energy = 0;							// minimum energy encountered
		static float	energy = 0;									// last calculated energy

		// Checking the minimizer
		if (isValid() == false)
		{
			Log.level(LogStream::ERROR) << "The steepest descent minimizer is not valid!" << endl;
			return false;
		}

		// if there are no atoms to optimize, return immediately - we have found the optimal
		// solution!
		Size number_of_movable_atoms = force_field_->getNumberOfMovableAtoms();
		if (number_of_movable_atoms == 0)
		{
			return true;
		}

		vector<Atom*>::const_iterator it;
		if (!restart)
		{
			// reset the step size to its default value
			step_size = maximal_shift_;

			// calculate initial gradient and gradient norm
			force_field_->updateForces();
			gradient_norm = 0;
			it = force_field_->getAtoms().begin();
			for ( ; it != force_field_->getAtoms().end() ; ++it)
			{
				gradient_norm += (*it)->getForce().getSquareLength();
			}

			// calculate the RMS gradient (termination condition)
			// in units of kJ/(mol A)
			gradient_norm = sqrt(gradient_norm / (3.0 * (float)number_of_movable_atoms));
			gradient_norm *= Constants::AVOGADRO / 1e13;

			// if the gradient norm is zero, return (we are converged)
			if (gradient_norm == 0.0)
			{
				return true;
			}
		}

		float factor;

		// Iterate and minimize
		Size iteration = 0;

		// if no limit to the number of steps is given, ignore it
		if (steps == 0)
		{
			steps = Limits<Size>::max();
		}

		float energy_change = 0.0;
		while ((number_of_iteration_ < maximal_number_of_iterations_) && (iteration < steps))
		{
			// calculate current energy
			energy_change = energy;
			energy = force_field_->updateEnergy();
			energy_change = energy - energy_change;

			// check whether the energy changed
			if (fabs((energy - last_energy) / energy) < 1e-9)
			{
				same_energy_counter++;
				if (same_energy_counter == 20)
				{
					break;
				}
			} else {
				last_energy = energy;
				same_energy_counter = 0;
			}

			// accept a taken step if it results in a lower energy
			if ((energy < min_energy) || (number_of_iteration_ == 0)
					|| ((restart == false) && (iteration == 0))
					|| (last_update > 10))
			{
				// if the last 10 steps didn't improve energy, we're in trouble
				// let's recalculate the gradient and increase the step size to get
				// out of here
				if (last_update > 10)
				{
					step_size *= 500;
				} else {
					min_energy = energy;
				}
				last_update = 0;

				// update gradient and gradient norm
				force_field_->updateForces();
				gradient_norm = 0;
				it = force_field_->getAtoms().begin();
				for ( ; it != force_field_->getAtoms().end() ; ++it)
				{
					gradient_norm += (*it)->getForce().getSquareLength();
				}
				// calculate the RMS gradient (termination condition)
				// in units of kJ/(mol A)
				gradient_norm = sqrt(gradient_norm / (3.0 * (float)number_of_movable_atoms));
				gradient_norm *= Constants::AVOGADRO / 1.0e13;

				// check for convergence
				if (gradient_norm <= max_gradient_)
				{
					break;
				}

				// increase step_size
				step_size *= 1.1;

				// calculate factor for atom displacements
				factor = Constants::AVOGADRO / 1.0e13 * step_size / gradient_norm;

				cout << "+step: " << step_size << " -> ";

			} else {

				// this step didn't result in a lower energy
				// make half a step back and retry

				// calculate factor for atom displacements
				factor = - Constants::AVOGADRO / 1.0e13 * (step_size * 0.5) / gradient_norm; // half step back

				// reduce step size
				step_size *= 0.5;
				last_update++;
				cout << "-step: " << step_size << " -> ";
			}

			//iterate over all movable atoms
			it = force_field_->getAtoms().begin();
			for (Size i = 0; i < number_of_movable_atoms ; ++i, ++it)
			{
				(*it)->setPosition((*it)->getPosition() + factor * (*it)->getForce());
			}

			// BAUSTELLE: Trajectory and non-bonded vector
			// Test if the trajectory has to be updated

			if ((number_of_iteration_ % force_field_->getUpdateFrequency()) == 0)
			{
				force_field_->update();
			}

			// Test if the energy has to be written
			if (number_of_iteration_ % energy_output_frequency_ == 0)
			{
				Log.info() << "iteration " << number_of_iteration_
									 << " energy: " << energy << " kJ/mol"
									 << " min_en: " << min_energy << " kJ/mol"
									 << " grad: " << gradient_norm / 4.184 << " kcal/(mol A)"
									 << " energy_change: " << energy_change << " kJ/mol"
									 << endl;
			}

			// count iterations
			iteration++;
			number_of_iteration_++;
		}

		// test whether convergence was reached
		return (gradient_norm <= max_gradient_) || (same_energy_counter == 20);
	}

} // namespace BALL
<commit_msg>removed some debugging messages<commit_after>// $Id: steepestDescent.C,v 1.3 1999/09/15 08:40:25 len Exp $

#include <BALL/MOLMEC/MINIMIZATION/steepestDescent.h>
#include <BALL/COMMON/limits.h>

namespace BALL
{
	Size	SteepestDescentMinimizer::Default::MAX_STEPS = 6;
	float SteepestDescentMinimizer::Default::MAX_GRADIENT = 0.001;

	const char* SteepestDescentMinimizer::Option::MAX_STEPS = "max_steps";
	const char*	SteepestDescentMinimizer::Option::MAX_GRADIENT = "max_gradient";

	// default constructor
	SteepestDescentMinimizer::SteepestDescentMinimizer()
		:	EnergyMinimizer()
	{
	}

	// copy constructor
	SteepestDescentMinimizer::SteepestDescentMinimizer(const SteepestDescentMinimizer& line_search_minimizer, bool /* deep */)
		:	EnergyMinimizer(line_search_minimizer)
	{
	}

	// assignment operator
	SteepestDescentMinimizer& SteepestDescentMinimizer::operator = (const SteepestDescentMinimizer& line_search_minimizer)
	{
		EnergyMinimizer::operator = (line_search_minimizer);
		return *this;
	}

	// Constructor initialized with a force field
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field)
		:	EnergyMinimizer()
	{
    valid_ = setup(force_field);

    if (!valid_)
    {
      Log.level(LogStream::ERROR) << " line search minimizer setup failed! " << endl;
		}
	}

	// Constructor initialized with a force field and a set of options
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field, const Options& new_options)
		:	EnergyMinimizer()
	{
    valid_ = setup(force_field, new_options);

    if (!valid_)
    {
      Log.level(LogStream::ERROR) << " Line search minimizer setup failed! " << endl;
		}
	}

	// destructor
	SteepestDescentMinimizer::~SteepestDescentMinimizer()
	{
	}

	// virtual function for the specific setup of derived classes
	bool SteepestDescentMinimizer::specificSetup()
	{

		max_steps_ = (Size)options.setDefaultInteger(SteepestDescentMinimizer::Option::MAX_STEPS, (long)SteepestDescentMinimizer::Default::MAX_STEPS);
		max_gradient_ = options.setDefaultReal(SteepestDescentMinimizer::Option::MAX_GRADIENT, SteepestDescentMinimizer::Default::MAX_GRADIENT);

		return true;
	}

	// Set the parameter max_steps_
	void	SteepestDescentMinimizer::setMaxSteps(Size max_steps)
	{
		max_steps_	= max_steps;
	}

	//	Get the parameter max_steps_
	Size	SteepestDescentMinimizer::getMaxSteps() const
	{
		return max_steps_;
	}

	// Set the parameter max_gradient_
	void	SteepestDescentMinimizer::setMaxGradient(float max_gradient)
	{
		max_gradient_	= max_gradient;
	}

	//	Get the parameter max_steps_
	float	SteepestDescentMinimizer::getMaxGradient() const
	{
		return max_gradient_;
	}

	/*	The minimizer optimizes the energy of the system
			using a modified line search algorithm.
	*/

	bool SteepestDescentMinimizer::minimize(Size steps, bool restart)
	{
		// define some static variables used for restarting

		static float	step_size = maximal_shift_;	// the current step size
		static Size		last_update = 1;						// last update of gradient (in number of iterations)
		static Size		same_energy_counter = 0;		// number of times the same energy was calculated (in number of iterations)
		static float	gradient_norm = 0;					// norm of the gradient
		static float	last_energy = 0;						// energy of the last iteration
		static float	min_energy = 0;							// minimum energy encountered
		static float	energy = 0;									// last calculated energy

		// Checking the minimizer
		if (isValid() == false)
		{
			Log.level(LogStream::ERROR) << "The steepest descent minimizer is not valid!" << endl;
			return false;
		}

		// if there are no atoms to optimize, return immediately - we have found the optimal
		// solution!
		Size number_of_movable_atoms = force_field_->getNumberOfMovableAtoms();
		if (number_of_movable_atoms == 0)
		{
			return true;
		}

		vector<Atom*>::const_iterator it;
		if (!restart)
		{
			// reset the step size to its default value
			step_size = maximal_shift_;

			// calculate initial gradient and gradient norm
			force_field_->updateForces();
			gradient_norm = 0;
			it = force_field_->getAtoms().begin();
			for ( ; it != force_field_->getAtoms().end() ; ++it)
			{
				gradient_norm += (*it)->getForce().getSquareLength();
			}

			// calculate the RMS gradient (termination condition)
			// in units of kJ/(mol A)
			gradient_norm = sqrt(gradient_norm / (3.0 * (float)number_of_movable_atoms));
			gradient_norm *= Constants::AVOGADRO / 1e13;

			// if the gradient norm is zero, return (we are converged)
			if (gradient_norm == 0.0)
			{
				return true;
			}
		}

		float factor;

		// Iterate and minimize
		Size iteration = 0;

		// if no limit to the number of steps is given, ignore it
		if (steps == 0)
		{
			steps = Limits<Size>::max();
		}

		float energy_change = 0.0;
		while ((number_of_iteration_ < maximal_number_of_iterations_) && (iteration < steps))
		{
			// calculate current energy
			energy_change = energy;
			energy = force_field_->updateEnergy();
			energy_change = energy - energy_change;

			// check whether the energy changed
			if (fabs((energy - last_energy) / energy) < 1e-9)
			{
				same_energy_counter++;
				if (same_energy_counter == 20)
				{
					break;
				}
			} else {
				last_energy = energy;
				same_energy_counter = 0;
			}

			// accept a taken step if it results in a lower energy
			if ((energy < min_energy) || (number_of_iteration_ == 0)
					|| ((restart == false) && (iteration == 0))
					|| (last_update > 10))
			{
				// if the last 10 steps didn't improve energy, we're in trouble
				// let's recalculate the gradient and increase the step size to get
				// out of here
				if (last_update > 10)
				{
					step_size *= 500;
				} else {
					min_energy = energy;
				}
				last_update = 0;

				// update gradient and gradient norm
				force_field_->updateForces();
				gradient_norm = 0;
				it = force_field_->getAtoms().begin();
				for ( ; it != force_field_->getAtoms().end() ; ++it)
				{
					gradient_norm += (*it)->getForce().getSquareLength();
				}
				// calculate the RMS gradient (termination condition)
				// in units of kJ/(mol A)
				gradient_norm = sqrt(gradient_norm / (3.0 * (float)number_of_movable_atoms));
				gradient_norm *= Constants::AVOGADRO / 1.0e13;

				// check for convergence
				if (gradient_norm <= max_gradient_)
				{
					break;
				}

				// increase step_size
				step_size *= 1.1;

				// calculate factor for atom displacements
				factor = Constants::AVOGADRO / 1.0e13 * step_size / gradient_norm;

			} else {

				// this step didn't result in a lower energy
				// make half a step back and retry

				// calculate factor for atom displacements
				factor = - Constants::AVOGADRO / 1.0e13 * (step_size * 0.5) / gradient_norm; // half step back

				// reduce step size
				step_size *= 0.5;
				last_update++;
			}

			//iterate over all movable atoms
			it = force_field_->getAtoms().begin();
			for (Size i = 0; i < number_of_movable_atoms ; ++i, ++it)
			{
				(*it)->setPosition((*it)->getPosition() + factor * (*it)->getForce());
			}

			// BAUSTELLE: Trajectory and non-bonded vector
			// Test if the trajectory has to be updated

			if ((number_of_iteration_ % force_field_->getUpdateFrequency()) == 0)
			{
				force_field_->update();
			}

			// Test if the energy has to be written
			if (number_of_iteration_ % energy_output_frequency_ == 0)
			{
				Log.info() << "iteration " << number_of_iteration_
									 << " energy: " << energy << " kJ/mol"
									 << " min_en: " << min_energy << " kJ/mol"
									 << " grad: " << gradient_norm  << " kJ/(mol A)"
									 << " energy_change: " << energy_change << " kJ/mol"
									 << endl;
			}

			// count iterations
			iteration++;
			number_of_iteration_++;
		}

		// test whether convergence was reached
		return (gradient_norm <= max_gradient_) || (same_energy_counter == 20);
	}

} // namespace BALL
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include "Util.h"
#include "Timer.h"

#include "util/usage.hh"

namespace Moses
{

/***
 * Return the total wall time that the timer has been in the "running"
 * state since it was first "started".
 */
double Timer::get_elapsed_time() const
{
  if (stopped) {
    return stop_time - start_time;
  }
  if (running) {
    return util::WallTime() - start_time;
  }
  return 0;
}

/***
 * Start a timer.  If it is already running, let it continue running.
 * Print an optional message.
 */
void Timer::start(const char* msg)
{
  // Print an optional message, something like "Starting timer t";
  if (msg) TRACE_ERR( msg << std::endl);

  // Return immediately if the timer is already running
  if (running && !stopped) return;

  // If stopped, recompute start time
  if (stopped) {
    start_time = util::WallTime() - (stop_time - start_time);
    stopped = false;
  }
  else {
    start_time = util::WallTime();
    running = true;
  }
}

/***
 * Stop a timer.
 * Print an optional message.
 */
void Timer::stop(const char* msg)
{
  // Print an optional message, something like "Stopping timer t";
  if (msg) TRACE_ERR( msg << std::endl);

  // Return immediately if the timer is not running
  if (stopped || !running) return;

  // Record stopped time
  stop_time = util::WallTime();

  // Change timer status to running
  stopped = true;
}

/***
 * Print out an optional message followed by the current timer timing.
 */
void Timer::check(const char* msg)
{
  // Print an optional message, something like "Checking timer t";
  if (msg) TRACE_ERR( msg << " : ");

//  TRACE_ERR( "[" << std::setiosflags(std::ios::fixed) << std::setprecision(2) << (running ? elapsed_time() : 0) << "] seconds\n");
  TRACE_ERR( "[" << (running ? get_elapsed_time() : 0) << "] seconds\n");
}

/***
 * Allow timers to be printed to ostreams using the syntax 'os << t'
 * for an ostream 'os' and a timer 't'.  For example, "cout << t" will
 * print out the total amount of time 't' has been "running".
 */
std::ostream& operator<<(std::ostream& os, Timer& t)
{
  //os << std::setprecision(2) << std::setiosflags(std::ios::fixed) << (t.running ? t.elapsed_time() : 0);
  os << (t.running ? t.get_elapsed_time() : 0);
  return os;
}

}

<commit_msg>Timer: no log output if verbosity parameter is 0<commit_after>#include <iostream>
#include <iomanip>
#include "Util.h"
#include "Timer.h"
#include "StaticData.h"

#include "util/usage.hh"

namespace Moses
{

/***
 * Return the total wall time that the timer has been in the "running"
 * state since it was first "started".
 */
double Timer::get_elapsed_time() const
{
  if (stopped) {
    return stop_time - start_time;
  }
  if (running) {
    return util::WallTime() - start_time;
  }
  return 0;
}

/***
 * Start a timer.  If it is already running, let it continue running.
 * Print an optional message.
 */
void Timer::start(const char* msg)
{
  // Print an optional message, something like "Starting timer t";
  if (msg) VERBOSE(1, msg << std::endl);

  // Return immediately if the timer is already running
  if (running && !stopped) return;

  // If stopped, recompute start time
  if (stopped) {
    start_time = util::WallTime() - (stop_time - start_time);
    stopped = false;
  }
  else {
    start_time = util::WallTime();
    running = true;
  }
}

/***
 * Stop a timer.
 * Print an optional message.
 */
void Timer::stop(const char* msg)
{
  // Print an optional message, something like "Stopping timer t";
  if (msg) VERBOSE(1, msg << std::endl);

  // Return immediately if the timer is not running
  if (stopped || !running) return;

  // Record stopped time
  stop_time = util::WallTime();

  // Change timer status to running
  stopped = true;
}

/***
 * Print out an optional message followed by the current timer timing.
 */
void Timer::check(const char* msg)
{
  // Print an optional message, something like "Checking timer t";
  if (msg) VERBOSE(1, msg << " : ");

//  VERBOSE(1, "[" << std::setiosflags(std::ios::fixed) << std::setprecision(2) << (running ? elapsed_time() : 0) << "] seconds\n");
  VERBOSE(1, "[" << (running ? get_elapsed_time() : 0) << "] seconds\n");
}

/***
 * Allow timers to be printed to ostreams using the syntax 'os << t'
 * for an ostream 'os' and a timer 't'.  For example, "cout << t" will
 * print out the total amount of time 't' has been "running".
 */
std::ostream& operator<<(std::ostream& os, Timer& t)
{
  //os << std::setprecision(2) << std::setiosflags(std::ios::fixed) << (t.running ? t.elapsed_time() : 0);
  os << (t.running ? t.get_elapsed_time() : 0);
  return os;
}

}

<|endoftext|>


<commit_before>#include <sal/net/io_service.hpp>
#include <sal/net/internet.hpp>
#include <sal/common.test.hpp>

#if __sal_os_darwin
  #include <sal/thread.hpp>
  #include <sys/types.h>
  #include <sys/event.h>
  #include <sys/time.h>
  #include <forward_list>
  #include <thread>
  using namespace std::chrono_literals;
#endif

namespace {

struct net_io_service
  : public sal_test::fixture
{
  using datagram_socket_t = sal::net::ip::udp_t::socket_t;
  using stream_socket_t = sal::net::ip::tcp_t::socket_t;
  using acceptor_t = sal::net::ip::tcp_t::acceptor_t;

  sal::net::io_service_t service;
};

TEST_F(net_io_service, make_context)
{
  auto ctx = service.make_context();
  (void)ctx;
}

TEST_F(net_io_service, make_context_too_small_completion_count)
{
  auto ctx = service.make_context(0);
  (void)ctx;
}

TEST_F(net_io_service, make_context_too_big_completion_count)
{
  auto ctx = service.make_context((std::numeric_limits<size_t>::max)());
  (void)ctx;
}

TEST_F(net_io_service, associate_datagram_socket)
{
  datagram_socket_t socket(sal::net::ip::udp_t::v4());
  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_datagram_socket_multiple_times)
{
  datagram_socket_t socket(sal::net::ip::udp_t::v4());

  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);

  service.associate(socket, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_datagram_socket_invalid)
{
  datagram_socket_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_stream_socket)
{
  stream_socket_t socket(sal::net::ip::tcp_t::v4());
  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_stream_socket_multiple_times)
{
  stream_socket_t socket(sal::net::ip::tcp_t::v4());

  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);

  service.associate(socket, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_stream_socket_invalid)
{
  stream_socket_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_acceptor_socket)
{
  acceptor_t acceptor(sal::net::ip::tcp_t::v4());
  std::error_code error;
  service.associate(acceptor, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_acceptor_socket_multiple_times)
{
  acceptor_t acceptor(sal::net::ip::tcp_t::v4());

  std::error_code error;
  service.associate(acceptor, error);
  EXPECT_TRUE(!error);

  service.associate(acceptor, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(acceptor), std::system_error);
}

TEST_F(net_io_service, associate_acceptor_socket_invalid)
{
  acceptor_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

#if __sal_os_darwin

using namespace std::chrono;
using namespace std::chrono_literals;

struct kqueue
  : public sal_test::fixture
{
  int queue;

  using socket_t = sal::net::ip::udp_t::socket_t;
  const socket_t::endpoint_t endpoint{sal::net::ip::address_v4_t::loopback(), 8192};
  socket_t a{endpoint}, b{sal::net::ip::udp_t::v4()};

  void SetUp ()
  {
    queue = ::kqueue();
    if (queue == -1)
    {
      FAIL() << strerror(errno);
    }

    a.non_blocking(true);
  }

  void TearDown ()
  {
    if (queue != -1)
    {
      ::close(queue);
    }
  }

  void send (const std::string &data, bool wait_after_send = true)
  {
    b.send_to(sal::make_buf(data), endpoint);
    if (wait_after_send)
    {
      std::this_thread::sleep_for(1ms);
    }
  }

  std::string recv (std::error_code &error)
  {
    char buf[1024];
    socket_t::endpoint_t remote_endpoint;
    auto size = a.receive_from(sal::make_buf(buf), remote_endpoint, error);
    return std::string(buf, size);
  }

  std::string recv ()
  {
    return recv(sal::net::throw_on_error("recv"));
  }

  using string_list = std::vector<std::string>;

  string_list drain (std::error_code &error)
  {
    string_list result;
    for (;;)
    {
      auto packet = recv(error);
      if (!error)
      {
        result.emplace_back(packet);
      }
      else
      {
        if (error == std::errc::operation_would_block)
        {
          error.clear();
        }
        break;
      }
    }
    return result;
  }

  string_list drain ()
  {
    return drain(sal::net::throw_on_error("drain"));
  }

  void monitor (int filter, int flags)
  {
    struct ::kevent change;
    EV_SET(&change, a.native_handle(), filter, flags, 0, 0, 0);
    if (::kevent(queue, &change, 1, nullptr, 0, nullptr) == -1)
    {
      FAIL() << strerror(errno);
    }
  }

  using event_list = std::vector<struct ::kevent>;

  event_list poll (const milliseconds &timeout, std::error_code &error)
  {
    auto s = duration_cast<seconds>(timeout);
    auto ns = duration_cast<nanoseconds>(timeout - s);
    struct timespec t = { s.count(), ns.count() };

    struct ::kevent events[16];
    auto count = ::kevent(queue, nullptr, 0, events, 16, &t);
    if (count == -1)
    {
      error.assign(errno, std::generic_category());
      return {};
    }

    event_list result;
    for (auto i = 0;  i != count;  ++i)
    {
      result.emplace_back(events[i]);
    }
    return result;
  }

  event_list poll (const milliseconds &timeout = 3s)
  {
    return poll(timeout, sal::net::throw_on_error("poll"));
  }

  sal::net::socket_base_t::native_handle_t handle (struct ::kevent &ev)
    const noexcept
  {
    return ev.ident;
  }

  size_t data_size (struct ::kevent &ev) const noexcept
  {
    return ev.data;
  }
};

TEST_F(kqueue, empty)
{
  monitor(EVFILT_READ, EV_ADD | EV_CLEAR);
  EXPECT_EQ(0U, poll(0ms).size());
}

TEST_F(kqueue, basic)
{
  monitor(EVFILT_READ, EV_ADD | EV_CLEAR);

  send(case_name);
  auto events = poll();
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(a.native_handle(), handle(events[0]));
  EXPECT_EQ(case_name.size(), data_size(events[0]));
  EXPECT_EQ(case_name, recv());
}

TEST_F(kqueue, edge_triggered_no_second_notification)
{
  monitor(EVFILT_READ, EV_ADD | EV_CLEAR);

  send("one");
  auto events = poll();
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(3U, data_size(events[0]));

  events = poll(0ms);
  EXPECT_EQ(0U, events.size());

  EXPECT_EQ("one", recv());
}

TEST_F(kqueue, edge_triggered_second_notification_on_new_send)
{
  monitor(EVFILT_READ, EV_ADD | EV_CLEAR);

  send("one");
  auto events = poll();
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(3U, data_size(events[0]));

  send("two");
  events = poll(0ms);
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(6U, data_size(events[0]));

  string_list packets{"one", "two"};
  EXPECT_EQ(packets, drain());
}

TEST_F(kqueue, level_triggered_second_notification)
{
  monitor(EVFILT_READ, EV_ADD);

  send("one");
  auto events = poll();
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(3U, data_size(events[0]));

  events = poll(0ms);
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(3U, data_size(events[0]));

  EXPECT_EQ("one", recv());
}

TEST_F(kqueue, level_triggered_second_notification_on_new_send)
{
  monitor(EVFILT_READ, EV_ADD);

  send("one");
  auto events = poll();
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(3U, data_size(events[0]));

  send("two");
  events = poll(0ms);
  ASSERT_EQ(1U, events.size());
  EXPECT_EQ(6U, data_size(events[0]));

  string_list packets{"one", "two"};
  EXPECT_EQ(packets, drain());
}

TEST_F(kqueue, single_thread_wakeup)
{
  monitor(EVFILT_READ, EV_ADD | EV_CLEAR);

  send("one", false);
  send("two");

  std::atomic<size_t> event_count{};
  std::forward_list<std::thread> threads;
  for (auto i = 0U;  i < std::thread::hardware_concurrency();  ++i)
  {
    threads.emplace_front([&event_count, this]
    {
      auto events = poll(1ms);
      event_count += events.size();
      if (events.size())
      {
        EXPECT_EQ(6U, data_size(events[0]));
        EXPECT_EQ("one", recv());
        EXPECT_EQ("two", recv());
      }
    });
  }

  for (auto &thread: threads)
  {
    thread.join();
  }

  EXPECT_EQ(1U, event_count);
}

#endif // __sal_os_darwin

} // namespace
<commit_msg>net/async: drop kqueue-specific unittests<commit_after>#include <sal/net/io_service.hpp>
#include <sal/net/internet.hpp>
#include <sal/common.test.hpp>

namespace {

struct net_io_service
  : public sal_test::fixture
{
  using datagram_socket_t = sal::net::ip::udp_t::socket_t;
  using stream_socket_t = sal::net::ip::tcp_t::socket_t;
  using acceptor_t = sal::net::ip::tcp_t::acceptor_t;

  sal::net::io_service_t service;
};

TEST_F(net_io_service, make_context)
{
  auto ctx = service.make_context();
  (void)ctx;
}

TEST_F(net_io_service, make_context_too_small_completion_count)
{
  auto ctx = service.make_context(0);
  (void)ctx;
}

TEST_F(net_io_service, make_context_too_big_completion_count)
{
  auto ctx = service.make_context((std::numeric_limits<size_t>::max)());
  (void)ctx;
}

TEST_F(net_io_service, associate_datagram_socket)
{
  datagram_socket_t socket(sal::net::ip::udp_t::v4());
  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_datagram_socket_multiple_times)
{
  datagram_socket_t socket(sal::net::ip::udp_t::v4());

  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);

  service.associate(socket, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_datagram_socket_invalid)
{
  datagram_socket_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_stream_socket)
{
  stream_socket_t socket(sal::net::ip::tcp_t::v4());
  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_stream_socket_multiple_times)
{
  stream_socket_t socket(sal::net::ip::tcp_t::v4());

  std::error_code error;
  service.associate(socket, error);
  EXPECT_TRUE(!error);

  service.associate(socket, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_stream_socket_invalid)
{
  stream_socket_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

TEST_F(net_io_service, associate_acceptor_socket)
{
  acceptor_t acceptor(sal::net::ip::tcp_t::v4());
  std::error_code error;
  service.associate(acceptor, error);
  EXPECT_TRUE(!error);
}

TEST_F(net_io_service, associate_acceptor_socket_multiple_times)
{
  acceptor_t acceptor(sal::net::ip::tcp_t::v4());

  std::error_code error;
  service.associate(acceptor, error);
  EXPECT_TRUE(!error);

  service.associate(acceptor, error);
  EXPECT_FALSE(!error);
  EXPECT_EQ(sal::net::socket_errc_t::already_associated, error);

  EXPECT_THROW(service.associate(acceptor), std::system_error);
}

TEST_F(net_io_service, associate_acceptor_socket_invalid)
{
  acceptor_t socket;

  std::error_code error;
  service.associate(socket, error);
  EXPECT_FALSE(!error);

  EXPECT_THROW(service.associate(socket), std::system_error);
}

} // namespace
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2002-2003 The Apache Software 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "<WebSig>" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, Institute for
 * Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
 * The development of this software was partly funded by the European
 * Commission in the <WebSig> project in the ISIS Programme.
 * For more information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * XSEC
 *
 * XSECURIResolverGenericWin32 := A URI Resolver that will work "out of
 *                                the box" with Windows.  Re-implements
 *								  much Xerces code, but allows us to
 *								  handle HTTP redirects as is required by
 *								  the DSIG Standard
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 * $Log$
 * Revision 1.7  2003/09/11 11:11:05  blautenb
 * Cleaned up usage of Xerces namespace - no longer inject into global namespace in headers
 *
 * Revision 1.6  2003/07/28 12:52:46  blautenb
 * Fixed a bug with DEBUG_NEW when compiling with Xalan 1.6
 *
 * Revision 1.5  2003/07/05 10:30:38  blautenb
 * Copyright update
 *
 * Revision 1.4  2003/05/22 11:42:06  blautenb
 * Updates so Windows version will compile with Xerces 2.3
 *
 * Revision 1.3  2003/05/10 07:23:36  blautenb
 * Updates to support anonymous references
 *
 * Revision 1.2  2003/02/17 11:21:45  blautenb
 * Work around for Xerces XMLUri bug
 *
 * Revision 1.1  2003/02/12 09:45:29  blautenb
 * Win32 Re-implementation of Xerces URIResolver to support re-directs
 *
 *
 */

#include "XSECURIResolverGenericWin32.hpp"

#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLUri.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/BinFileInputStream.hpp>

XERCES_CPP_NAMESPACE_USE

#include <xsec/framework/XSECError.hpp>
#include <xsec/utils/winutils/XSECBinHTTPURIInputStream.hpp>

static const XMLCh gFileScheme[] = {

	chLatin_f,
	chLatin_i,
	chLatin_l,
	chLatin_e,
	chNull

};

static const XMLCh gHttpScheme[] = {

	chLatin_h,
	chLatin_t,
	chLatin_t,
	chLatin_p,
	chNull

};

#if XERCES_VERSION_MAJOR == 2 && XERCES_VERSION_MINOR < 3

static const XMLCh DOTDOT_SLASH[] = {

	chPeriod,
	chPeriod,
	chForwardSlash,
	chNull

};

#endif

XSECURIResolverGenericWin32::XSECURIResolverGenericWin32() :
mp_baseURI(NULL) {

};

XSECURIResolverGenericWin32::~XSECURIResolverGenericWin32() {

	if (mp_baseURI != NULL)
		delete[] mp_baseURI;

}

// -----------------------------------------------------------------------
//  Resolve a URI that is passed in
// -----------------------------------------------------------------------

BinInputStream * XSECURIResolverGenericWin32::resolveURI(const XMLCh * uri) {

	XSEC_USING_XERCES(BinInputStream);
	XSEC_USING_XERCES(XMLUri);
	XSEC_USING_XERCES(XMLUni);
	XSEC_USING_XERCES(Janitor);
	XSEC_USING_XERCES(BinFileInputStream);

	XMLUri					* xmluri;

	if (uri == NULL) {
		throw XSECException(XSECException::ErrorOpeningURI,
			"XSECURIResolverGenericWin32 - anonymous references not supported in default URI Resolvers");
	}

	// Create the appropriate XMLUri objects
	if (mp_baseURI != NULL) {
		XMLUri	* turi;

#if defined(XSEC_XERCES_BROKEN_XMLURI)

		// XMLUri relative paths are broken, so we need to strip out ".."
		// Doesn't fix the whole problem, but gets us somewhere

		XMLCh * b = XMLString::replicate(mp_baseURI);
		ArrayJanitor<XMLCh> j_b(b);
		XMLCh * r = XMLString::replicate(uri);
		ArrayJanitor<XMLCh> j_r(r);

		int index = 0;
		while (XMLString::startsWith(&(r[index]), DOTDOT_SLASH)) {

			// Strip the last segment of the base

			int lastIndex = XMLString::lastIndexOf(b, XERCES_CPP_NAMESPACE_QUALIFIER chForwardSlash);
			if (lastIndex > 0)
				b[lastIndex] = 0;

			index += 3;

		}

		XSECnew(turi, XMLUri(b));
		Janitor<XMLUri> j_turi(turi);
		XSECnew(xmluri, XMLUri(turi, &(r[index])));

#else
		turi = new XMLUri(mp_baseURI);
		Janitor<XMLUri> j_turi(turi);

		xmluri = new XMLUri(turi, uri);
#endif

	}
	else {
		xmluri = new XMLUri(uri);
	}

	Janitor<XMLUri> j_xmluri(xmluri);

	// Determine what kind of URI this is and how to handle it.

	if (!XMLString::compareIString(xmluri->getScheme(), gFileScheme)) {

		// This is a file.  We only really understand if this is localhost
		// XMLUri has already cleaned of escape characters (%xx)

		if (xmluri->getHost() == NULL ||
			!XMLString::compareIString(xmluri->getHost(), XMLUni::fgLocalHostString)) {

			// Localhost

            BinFileInputStream* retStrm = new BinFileInputStream(xmluri->getPath());
            if (!retStrm->getIsOpen())
            {
                delete retStrm;
                return 0;
            }
            return retStrm;

		}

		else {

			throw XSECException(XSECException::ErrorOpeningURI,
				"XSECURIResolverGenericWin32 - unable to open non-localhost file");

		}

	}

	// Is the scheme a HTTP?
	if (!XMLString::compareIString(xmluri->getScheme(), gHttpScheme)) {

		// Pass straight to our local XSECBinHTTPUriInputStream
		XSECBinHTTPURIInputStream *ret;

		ret = new XSECBinHTTPURIInputStream(*xmluri);

		return ret;

	}

	throw XSECException(XSECException::ErrorOpeningURI,
		"XSECURIResolverGenericWin32 - unknown URI scheme");

}

// -----------------------------------------------------------------------
//  Clone me
// -----------------------------------------------------------------------

XSECURIResolver * XSECURIResolverGenericWin32::clone(void) {

	XSECURIResolverGenericWin32 * ret;

	ret = new XSECURIResolverGenericWin32();

	if (this->mp_baseURI != NULL)
		ret->mp_baseURI = XMLString::replicate(this->mp_baseURI);
	else
		ret->mp_baseURI = NULL;

	return ret;

}

// -----------------------------------------------------------------------
//  Set a base URI to map any incoming files against
// -----------------------------------------------------------------------

void XSECURIResolverGenericWin32::setBaseURI(const XMLCh * uri) {

	if (mp_baseURI != NULL)
		delete[] mp_baseURI;

	mp_baseURI = XMLString::replicate(uri);

}
<commit_msg>Remove escapes from URI before retrieving a path on the file system<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2002-2003 The Apache Software 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "<WebSig>" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, Institute for
 * Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
 * The development of this software was partly funded by the European
 * Commission in the <WebSig> project in the ISIS Programme.
 * For more information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * XSEC
 *
 * XSECURIResolverGenericWin32 := A URI Resolver that will work "out of
 *                                the box" with Windows.  Re-implements
 *								  much Xerces code, but allows us to
 *								  handle HTTP redirects as is required by
 *								  the DSIG Standard
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 * $Log$
 * Revision 1.8  2004/01/26 00:16:04  blautenb
 * Remove escapes from URI before retrieving a path on the file system
 *
 * Revision 1.7  2003/09/11 11:11:05  blautenb
 * Cleaned up usage of Xerces namespace - no longer inject into global namespace in headers
 *
 * Revision 1.6  2003/07/28 12:52:46  blautenb
 * Fixed a bug with DEBUG_NEW when compiling with Xalan 1.6
 *
 * Revision 1.5  2003/07/05 10:30:38  blautenb
 * Copyright update
 *
 * Revision 1.4  2003/05/22 11:42:06  blautenb
 * Updates so Windows version will compile with Xerces 2.3
 *
 * Revision 1.3  2003/05/10 07:23:36  blautenb
 * Updates to support anonymous references
 *
 * Revision 1.2  2003/02/17 11:21:45  blautenb
 * Work around for Xerces XMLUri bug
 *
 * Revision 1.1  2003/02/12 09:45:29  blautenb
 * Win32 Re-implementation of Xerces URIResolver to support re-directs
 *
 *
 */

#include "XSECURIResolverGenericWin32.hpp"

#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLUri.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/BinFileInputStream.hpp>

XERCES_CPP_NAMESPACE_USE

#include <xsec/framework/XSECError.hpp>
#include <xsec/utils/winutils/XSECBinHTTPURIInputStream.hpp>
#include <xsec/utils/XSECDOMUtils.hpp>

static const XMLCh gFileScheme[] = {

	chLatin_f,
	chLatin_i,
	chLatin_l,
	chLatin_e,
	chNull

};

static const XMLCh gHttpScheme[] = {

	chLatin_h,
	chLatin_t,
	chLatin_t,
	chLatin_p,
	chNull

};

#if XERCES_VERSION_MAJOR == 2 && XERCES_VERSION_MINOR < 3

static const XMLCh DOTDOT_SLASH[] = {

	chPeriod,
	chPeriod,
	chForwardSlash,
	chNull

};

#endif

XSECURIResolverGenericWin32::XSECURIResolverGenericWin32() :
mp_baseURI(NULL) {

};

XSECURIResolverGenericWin32::~XSECURIResolverGenericWin32() {

	if (mp_baseURI != NULL)
		delete[] mp_baseURI;

}

// -----------------------------------------------------------------------
//  Resolve a URI that is passed in
// -----------------------------------------------------------------------

BinInputStream * XSECURIResolverGenericWin32::resolveURI(const XMLCh * uri) {

	XSEC_USING_XERCES(BinInputStream);
	XSEC_USING_XERCES(XMLUri);
	XSEC_USING_XERCES(XMLUni);
	XSEC_USING_XERCES(Janitor);
	XSEC_USING_XERCES(BinFileInputStream);

	XMLUri					* xmluri;

	if (uri == NULL) {
		throw XSECException(XSECException::ErrorOpeningURI,
			"XSECURIResolverGenericWin32 - anonymous references not supported in default URI Resolvers");
	}

	// Create the appropriate XMLUri objects
	if (mp_baseURI != NULL) {
		XMLUri	* turi;

#if defined(XSEC_XERCES_BROKEN_XMLURI)

		// XMLUri relative paths are broken, so we need to strip out ".."
		// Doesn't fix the whole problem, but gets us somewhere

		XMLCh * b = XMLString::replicate(mp_baseURI);
		ArrayJanitor<XMLCh> j_b(b);
		XMLCh * r = XMLString::replicate(uri);
		ArrayJanitor<XMLCh> j_r(r);

		int index = 0;
		while (XMLString::startsWith(&(r[index]), DOTDOT_SLASH)) {

			// Strip the last segment of the base

			int lastIndex = XMLString::lastIndexOf(b, XERCES_CPP_NAMESPACE_QUALIFIER chForwardSlash);
			if (lastIndex > 0)
				b[lastIndex] = 0;

			index += 3;

		}

		XSECnew(turi, XMLUri(b));
		Janitor<XMLUri> j_turi(turi);
		XSECnew(xmluri, XMLUri(turi, &(r[index])));

#else
		turi = new XMLUri(mp_baseURI);
		Janitor<XMLUri> j_turi(turi);

		xmluri = new XMLUri(turi, uri);
#endif

	}
	else {
		xmluri = new XMLUri(uri);
	}

	Janitor<XMLUri> j_xmluri(xmluri);

	// Determine what kind of URI this is and how to handle it.

	if (!XMLString::compareIString(xmluri->getScheme(), gFileScheme)) {

		// This is a file.  We only really understand if this is localhost

		if (xmluri->getHost() == NULL || xmluri->getHost()[0] == chNull ||
			!XMLString::compareIString(xmluri->getHost(), XMLUni::fgLocalHostString)) {

			// Clean hex escapes
			XMLCh * realPath = cleanURIEscapes(xmluri->getPath());
			ArrayJanitor<XMLCh> j_realPath(realPath);

			// Localhost

            BinFileInputStream* retStrm = new BinFileInputStream(realPath);
            if (!retStrm->getIsOpen())
            {
                delete retStrm;
                return 0;
            }
            return retStrm;

		}

		else {

			throw XSECException(XSECException::ErrorOpeningURI,
				"XSECURIResolverGenericWin32 - unable to open non-localhost file");

		}

	}

	// Is the scheme a HTTP?
	if (!XMLString::compareIString(xmluri->getScheme(), gHttpScheme)) {

		// Pass straight to our local XSECBinHTTPUriInputStream
		XSECBinHTTPURIInputStream *ret;

		ret = new XSECBinHTTPURIInputStream(*xmluri);

		return ret;

	}

	throw XSECException(XSECException::ErrorOpeningURI,
		"XSECURIResolverGenericWin32 - unknown URI scheme");

}

// -----------------------------------------------------------------------
//  Clone me
// -----------------------------------------------------------------------

XSECURIResolver * XSECURIResolverGenericWin32::clone(void) {

	XSECURIResolverGenericWin32 * ret;

	ret = new XSECURIResolverGenericWin32();

	if (this->mp_baseURI != NULL)
		ret->mp_baseURI = XMLString::replicate(this->mp_baseURI);
	else
		ret->mp_baseURI = NULL;

	return ret;

}

// -----------------------------------------------------------------------
//  Set a base URI to map any incoming files against
// -----------------------------------------------------------------------

void XSECURIResolverGenericWin32::setBaseURI(const XMLCh * uri) {

	if (mp_baseURI != NULL)
		delete[] mp_baseURI;

	mp_baseURI = XMLString::replicate(uri);

}
<|endoftext|>