<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <GL/glew.h>

#include <visionaray/math/forward.h>
#include <visionaray/math/project.h>
#include <visionaray/math/quaternion.h>
#include <visionaray/pinhole_camera.h>

#include "rotate_manipulator.h"

using namespace visionaray;

namespace circle
{

//-------------------------------------------------------------------------------------------------
// circle in the plane
//

template <typename F>
static void for_each_line(F func, float radius = 1.0f, vec2 center = { 0.0f, 0.0f } )
{
    for (int i = 0; i < 360; ++i)
    {
        auto rad1 = i * constants::degrees_to_radians<float>();
        auto x1 = center.x + cos(rad1) * radius;
        auto y1 = center.y + sin(rad1) * radius;

        auto rad2 = (i + 1) * constants::degrees_to_radians<float>();
        auto x2 = center.x + cos(rad2) * radius;
        auto y2 = center.y + sin(rad2) * radius;

        func(x1, y1, x2, y2);
    }
}

//-------------------------------------------------------------------------------------------------
// circle in space
//

template <typename F>
static void for_each_line(F func, vec3 vx, vec3 vy, vec3 center = { 0.0f, 0.0f, 0.0f } )
{
    for (int i = 0; i < 360; ++i)
    {
        auto rad1 = i * constants::degrees_to_radians<float>();
        auto v1 = center + cos(rad1) * vx + sin(rad1) * vy;

        auto rad2 = (i + 1) * constants::degrees_to_radians<float>();
        auto v2 = center + cos(rad2) * vx + sin(rad2) * vy;

        func(v1, v2);
    }
}

} // circle

//-------------------------------------------------------------------------------------------------
// Convert from Visionaray / GL window coordinates to left/upper origin coordinates
//

static disci flip(disci const& d, recti const& viewport)
{
    disci result = d;
    result.center.y = viewport.h - d.center.y - 1;
    return result;
}

static recti flip(recti const& r, recti const& viewport)
{
    recti result = r;
    result.y = viewport.h - r.h - r.y - 1;
    return result;
}

//-------------------------------------------------------------------------------------------------
//
//

rotate_manipulator::rotate_manipulator(
        pinhole_camera const& cam,
        mat4& model_matrix,
        vec3 size,
        mouse::buttons buttons,
        int line_width
        )
    : model_manipulator(cam, model_matrix, size)
    , buttons_(buttons)
    , ball_(1.1f)
    , line_width_(line_width)
{
}

void rotate_manipulator::render()
{
    glPushAttrib(GL_CURRENT_BIT | GL_TRANSFORM_BIT);

    auto scaling = get_scaling(model_matrix_);
    auto radius = (length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f) * ball_.radius;
    vec3 center(model_matrix_(0, 3), model_matrix_(1, 3), model_matrix_(2, 3));

    mat3 mm3(model_matrix_(0).xyz(), model_matrix_(1).xyz(), model_matrix_(2).xyz());
    auto X = normalize(mm3 * vec3(1.0f, 0.0f, 0.0f));
    auto Y = normalize(mm3 * vec3(0.0f, 1.0f, 0.0f));
    auto Z = normalize(mm3 * vec3(0.0f, 0.0f, 1.0f));

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadMatrixf(camera_.get_proj_matrix().data());

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadMatrixf((camera_.get_view_matrix() * mat4::translation(vec3(center))).data());

    // parallel to screen

    auto dir   = normalize(center - camera_.eye());
    auto right = normalize(cross(dir, vec3(0.0f, 1.0f, 0.0f)));
    auto up    = cross(dir, right);

    GLint prev_line_width = 1;
    glGetIntegerv(GL_LINE_WIDTH, &prev_line_width);

    glLineWidth(line_width_);

    glBegin(GL_LINES);
    glColor3f(0.5f, 0.5f, 0.5f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            glVertex3f(v1.x, v1.y, v1.z);
            glVertex3f(v2.x, v2.y, v2.z);
        },
        up * radius,
        right * radius
        );
    glEnd();

    // X

    right      = normalize(cross(dir, X));
    auto front = normalize(cross(right, X));

    glBegin(GL_LINES);
    glColor3f(1.0f, 0.0f, 0.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    // Y

    right = normalize(cross(dir, Y));
    front = normalize(cross(right, Y));

    glBegin(GL_LINES);
    glColor3f(0.0f, 1.0f, 0.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    // Z

    right = normalize(cross(dir, Z));
    front = normalize(cross(right, Z));

    glBegin(GL_LINES);
    glColor3f(0.0f, 0.0f, 1.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    glLineWidth(prev_line_width);

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glPopAttrib();
}

bool rotate_manipulator::handle_mouse_down(visionaray::mouse_event const& event)
{
    auto bdisc = flip( bounding_disc(), camera_.get_viewport() );

    if (bdisc.contains(event.pos()) && event.buttons() & buttons_)
    {
        dragging_ = true;

        auto brect = flip( bounding_rect(), camera_.get_viewport() );

        ball_.down_pos = ball_.project(
            event.pos().x,
            event.pos().y,
            brect
            );
        ball_.down_rotation = ball_.rotation;
        down_pos_ = event.pos();
//      selected_ = select_from_mouse_pointer(event);

        return true;
    }
    else
    {
        return false;
    }
}

bool rotate_manipulator::handle_mouse_up(visionaray::mouse_event const& event)
{
    VSNRAY_UNUSED(event);

    dragging_ = false;
    selected_ = -1;
    return false;
}

bool rotate_manipulator::handle_mouse_move(visionaray::mouse_event const& event)
{
    auto bdisc = flip( bounding_disc(), camera_.get_viewport() );

    mouse_over_ = bdisc.contains(event.pos());

    if (dragging_ && event.buttons() & buttons_)
    {
        auto brect = flip( bounding_rect(), camera_.get_viewport() );

        vec3 curr_pos = ball_.project(
                event.pos().x,
                event.pos().y,
                brect
                );

        auto last_vsr = rotation(ball_.rotation);
        ball_.rotation = quat::rotation(ball_.down_pos, curr_pos) * ball_.down_rotation;

        auto vsr = rotation(ball_.rotation);

        auto trans = model_matrix_(3);

        model_matrix_.col3 = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        auto vm = camera_.get_view_matrix();
        vm.col3 = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        model_matrix_ = inverse(vm) * vsr * inverse(last_vsr) * vm * model_matrix_;
        model_matrix_.col3 = trans;

        return true;
    }
    else
    {
        hovered_ = select_from_mouse_pointer(event);
        return false;
    }
}

int rotate_manipulator::select_from_mouse_pointer(visionaray::mouse_event const& event)
{
    auto scaling = get_scaling(model_matrix_);
    auto radius = length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f;
    vec2i pos(
            event.pos().x,
            camera_.get_viewport().h - 1 - event.pos().y
            );

    int result = -1;

    for (int i = 0; i < 3; ++i)
    {
        auto modelview = camera_.get_view_matrix() * model_matrix_ * inverse(scaling);

        circle::for_each_line(
            [&](float x1, float y1, float x2, float y2)
            {
                auto v1 = rotate( vec3(0.0f, x1, y1), i );
                auto v2 = rotate( vec3(0.0f, x2, y2), i );

                vec3 win1;
                project(win1, v1, modelview, camera_.get_proj_matrix(), camera_.get_viewport());

                vec3 win2;
                project(win2, v2, modelview, camera_.get_proj_matrix(), camera_.get_viewport());

                auto minx = min(win1.x, win2.x);
                auto maxx = max(win1.x, win2.x);
                auto miny = min(win1.y, win2.y);
                auto maxy = max(win1.y, win2.y);

                minx -= 2;
                miny -= 2;
                maxx += 2;
                maxy += 2;

                recti bounds(
                        static_cast<int>(floor(minx)),
                        static_cast<int>(floor(miny)),
                        static_cast<int>(ceil(abs(maxx - minx))),
                        static_cast<int>(ceil(abs(maxy - miny)))
                        );

                if (bounds.contains(pos))
                {
                    result = i;
                    return;
                }

            },
            radius * ball_.radius
            );
    }

    return result;

}

disci rotate_manipulator::bounding_disc()
{
    auto scaling = get_scaling(model_matrix_);
    auto radius = length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f;

    vec3 win_center(0.0f);
    vec3 win_right(0.0f);

    project(
            win_center,
            vec3(0.0f),
            camera_.get_view_matrix() * model_matrix_,
            camera_.get_proj_matrix(),
            camera_.get_viewport()
            );

    project(
            win_right,
            vec3(0.0f),
            mat4::translation(radius * ball_.radius, 0.0f, 0.0f) * camera_.get_view_matrix() * model_matrix_,
            camera_.get_proj_matrix(),
            camera_.get_viewport()
            );

    disci result;
    result.center = vec2i(win_center.xy());
    result.radius = round(abs(win_right.x - win_center.x)) + 0;
    return result;
}

recti rotate_manipulator::bounding_rect()
{
    auto disc = bounding_disc();

    return recti(
            disc.center.x - disc.radius,
            disc.center.y - disc.radius,
            disc.radius + disc.radius,
            disc.radius + disc.radius
            );
}
<commit_msg>Mind position when drawing rotate manip<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <GL/glew.h>

#include <visionaray/math/forward.h>
#include <visionaray/math/project.h>
#include <visionaray/math/quaternion.h>
#include <visionaray/pinhole_camera.h>

#include "rotate_manipulator.h"

using namespace visionaray;

namespace circle
{

//-------------------------------------------------------------------------------------------------
// circle in the plane
//

template <typename F>
static void for_each_line(F func, float radius = 1.0f, vec2 center = { 0.0f, 0.0f } )
{
    for (int i = 0; i < 360; ++i)
    {
        auto rad1 = i * constants::degrees_to_radians<float>();
        auto x1 = center.x + cos(rad1) * radius;
        auto y1 = center.y + sin(rad1) * radius;

        auto rad2 = (i + 1) * constants::degrees_to_radians<float>();
        auto x2 = center.x + cos(rad2) * radius;
        auto y2 = center.y + sin(rad2) * radius;

        func(x1, y1, x2, y2);
    }
}

//-------------------------------------------------------------------------------------------------
// circle in space
//

template <typename F>
static void for_each_line(F func, vec3 vx, vec3 vy, vec3 center = { 0.0f, 0.0f, 0.0f } )
{
    for (int i = 0; i < 360; ++i)
    {
        auto rad1 = i * constants::degrees_to_radians<float>();
        auto v1 = center + cos(rad1) * vx + sin(rad1) * vy;

        auto rad2 = (i + 1) * constants::degrees_to_radians<float>();
        auto v2 = center + cos(rad2) * vx + sin(rad2) * vy;

        func(v1, v2);
    }
}

} // circle

//-------------------------------------------------------------------------------------------------
// Convert from Visionaray / GL window coordinates to left/upper origin coordinates
//

static disci flip(disci const& d, recti const& viewport)
{
    disci result = d;
    result.center.y = viewport.h - d.center.y - 1;
    return result;
}

static recti flip(recti const& r, recti const& viewport)
{
    recti result = r;
    result.y = viewport.h - r.h - r.y - 1;
    return result;
}

//-------------------------------------------------------------------------------------------------
//
//

rotate_manipulator::rotate_manipulator(
        pinhole_camera const& cam,
        mat4& model_matrix,
        vec3 size,
        mouse::buttons buttons,
        int line_width
        )
    : model_manipulator(cam, model_matrix, size)
    , buttons_(buttons)
    , ball_(1.1f)
    , line_width_(line_width)
{
}

void rotate_manipulator::render()
{
    glPushAttrib(GL_CURRENT_BIT | GL_TRANSFORM_BIT);

    auto scaling = get_scaling(model_matrix_);
    auto radius = (length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f) * ball_.radius;
    vec3 center(model_matrix_(0, 3), model_matrix_(1, 3), model_matrix_(2, 3));
    center += pos_;

    mat3 mm3(model_matrix_(0).xyz(), model_matrix_(1).xyz(), model_matrix_(2).xyz());
    auto X = normalize(mm3 * vec3(1.0f, 0.0f, 0.0f));
    auto Y = normalize(mm3 * vec3(0.0f, 1.0f, 0.0f));
    auto Z = normalize(mm3 * vec3(0.0f, 0.0f, 1.0f));

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadMatrixf(camera_.get_proj_matrix().data());

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadMatrixf((camera_.get_view_matrix() * mat4::translation(vec3(center))).data());

    // parallel to screen

    auto dir   = normalize(center - camera_.eye());
    auto right = normalize(cross(dir, vec3(0.0f, 1.0f, 0.0f)));
    auto up    = cross(dir, right);

    GLint prev_line_width = 1;
    glGetIntegerv(GL_LINE_WIDTH, &prev_line_width);

    glLineWidth(line_width_);

    glBegin(GL_LINES);
    glColor3f(0.5f, 0.5f, 0.5f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            glVertex3f(v1.x, v1.y, v1.z);
            glVertex3f(v2.x, v2.y, v2.z);
        },
        up * radius,
        right * radius
        );
    glEnd();

    // X

    right      = normalize(cross(dir, X));
    auto front = normalize(cross(right, X));

    glBegin(GL_LINES);
    glColor3f(1.0f, 0.0f, 0.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    // Y

    right = normalize(cross(dir, Y));
    front = normalize(cross(right, Y));

    glBegin(GL_LINES);
    glColor3f(0.0f, 1.0f, 0.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    // Z

    right = normalize(cross(dir, Z));
    front = normalize(cross(right, Z));

    glBegin(GL_LINES);
    glColor3f(0.0f, 0.0f, 1.0f);
    circle::for_each_line([&](vec3 const& v1, vec3 const& v2)
        {
            if (dot(v2, normalize(camera_.eye() - center)) > 0.0f)
            {
                glVertex3f(v1.x, v1.y, v1.z);
                glVertex3f(v2.x, v2.y, v2.z);
            }
        },
        right * radius,
        front * radius
        );
    glEnd();

    glLineWidth(prev_line_width);

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glPopAttrib();
}

bool rotate_manipulator::handle_mouse_down(visionaray::mouse_event const& event)
{
    auto bdisc = flip( bounding_disc(), camera_.get_viewport() );

    if (bdisc.contains(event.pos()) && event.buttons() & buttons_)
    {
        dragging_ = true;

        auto brect = flip( bounding_rect(), camera_.get_viewport() );

        ball_.down_pos = ball_.project(
            event.pos().x,
            event.pos().y,
            brect
            );
        ball_.down_rotation = ball_.rotation;
        down_pos_ = event.pos();
//      selected_ = select_from_mouse_pointer(event);

        return true;
    }
    else
    {
        return false;
    }
}

bool rotate_manipulator::handle_mouse_up(visionaray::mouse_event const& event)
{
    VSNRAY_UNUSED(event);

    dragging_ = false;
    selected_ = -1;
    return false;
}

bool rotate_manipulator::handle_mouse_move(visionaray::mouse_event const& event)
{
    auto bdisc = flip( bounding_disc(), camera_.get_viewport() );

    mouse_over_ = bdisc.contains(event.pos());

    if (dragging_ && event.buttons() & buttons_)
    {
        auto brect = flip( bounding_rect(), camera_.get_viewport() );

        vec3 curr_pos = ball_.project(
                event.pos().x,
                event.pos().y,
                brect
                );

        auto last_vsr = rotation(ball_.rotation);
        ball_.rotation = quat::rotation(ball_.down_pos, curr_pos) * ball_.down_rotation;

        auto vsr = rotation(ball_.rotation);

        auto trans = model_matrix_(3);

        model_matrix_.col3 = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        auto vm = camera_.get_view_matrix();
        vm.col3 = vec4(0.0f, 0.0f, 0.0f, 1.0f);

        model_matrix_ = inverse(vm) * vsr * inverse(last_vsr) * vm * model_matrix_;
        model_matrix_.col3 = trans;

        return true;
    }
    else
    {
        hovered_ = select_from_mouse_pointer(event);
        return false;
    }
}

int rotate_manipulator::select_from_mouse_pointer(visionaray::mouse_event const& event)
{
    auto scaling = get_scaling(model_matrix_);
    auto radius = length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f;
    vec2i pos(
            event.pos().x,
            camera_.get_viewport().h - 1 - event.pos().y
            );

    int result = -1;

    for (int i = 0; i < 3; ++i)
    {
        auto modelview = camera_.get_view_matrix() * model_matrix_ * inverse(scaling);

        circle::for_each_line(
            [&](float x1, float y1, float x2, float y2)
            {
                auto v1 = rotate( vec3(0.0f, x1, y1), i );
                auto v2 = rotate( vec3(0.0f, x2, y2), i );

                vec3 win1;
                project(win1, v1, modelview, camera_.get_proj_matrix(), camera_.get_viewport());

                vec3 win2;
                project(win2, v2, modelview, camera_.get_proj_matrix(), camera_.get_viewport());

                auto minx = min(win1.x, win2.x);
                auto maxx = max(win1.x, win2.x);
                auto miny = min(win1.y, win2.y);
                auto maxy = max(win1.y, win2.y);

                minx -= 2;
                miny -= 2;
                maxx += 2;
                maxy += 2;

                recti bounds(
                        static_cast<int>(floor(minx)),
                        static_cast<int>(floor(miny)),
                        static_cast<int>(ceil(abs(maxx - minx))),
                        static_cast<int>(ceil(abs(maxy - miny)))
                        );

                if (bounds.contains(pos))
                {
                    result = i;
                    return;
                }

            },
            radius * ball_.radius
            );
    }

    return result;

}

disci rotate_manipulator::bounding_disc()
{
    auto scaling = get_scaling(model_matrix_);
    auto radius = length((scaling * vec4(size_, 1.0f)).xyz()) / 2.0f;

    vec3 win_center(0.0f);
    vec3 win_right(0.0f);

    project(
            win_center,
            vec3(0.0f),
            camera_.get_view_matrix() * mat4::translation(pos_) * model_matrix_,
            camera_.get_proj_matrix(),
            camera_.get_viewport()
            );

    project(
            win_right,
            vec3(0.0f),
            mat4::translation(radius * ball_.radius, 0.0f, 0.0f) * camera_.get_view_matrix() * mat4::translation(pos_) * model_matrix_,
            camera_.get_proj_matrix(),
            camera_.get_viewport()
            );

    disci result;
    result.center = vec2i(win_center.xy());
    result.radius = round(abs(win_right.x - win_center.x)) + 0;
    return result;
}

recti rotate_manipulator::bounding_rect()
{
    auto disc = bounding_disc();

    return recti(
            disc.center.x - disc.radius,
            disc.center.y - disc.radius,
            disc.radius + disc.radius,
            disc.radius + disc.radius
            );
}
<|endoftext|>


<commit_before>#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "IOLogWrapper.hpp"
#include "PressDownKeys.hpp"

namespace org_pqrs_Karabiner {
  List PressDownKeys::list_;

  void
  PressDownKeys::initialize(void)
  {}

  void
  PressDownKeys::terminate(void)
  {
    list_.clear();
  }

  void
  PressDownKeys::add(KeyCode key, KeyboardType keyboardType)
  {
    if (key == KeyCode::VK_NONE) return;

    list_.push_back(new Item(key, keyboardType));

    IOLOG_DEVEL("PressDownKeys::add key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::remove(KeyCode key, KeyboardType keyboardType)
  {
    Item* p = static_cast<Item*>(list_.safe_front());
    for (;;) {
      if (! p) break;

      if (p->key == key &&
          p->keyboardType == keyboardType) {
        p = static_cast<Item*>(list_.erase_and_delete(p));
      } else {
        p = static_cast<Item*>(p->getnext());
      }
    }

    IOLOG_DEVEL("PressDownKeys::remove key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::clear(void)
  {
    IOLOG_DEVEL("PressDownKeys::clear list_.size = %d\n", static_cast<int>(list_.size()));

    Item* p = static_cast<Item*>(list_.safe_front());
    for (;;) {
      if (! p) break;

      Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(EventType::UP, Flags(0), p->key, p->keyboardType, false));
      if (! ptr) break;

      EventOutputQueue::push(*ptr);
      IOLOG_DEVEL("PressDownKeys::clear key:%d, keyboardType:%d\n", (p->key).get(), (p->keyboardType).get());

      p = static_cast<Item*>(list_.erase_and_delete(p));
    }
  }
}
<commit_msg>alloc -> constructor<commit_after>#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "IOLogWrapper.hpp"
#include "PressDownKeys.hpp"

namespace org_pqrs_Karabiner {
  List PressDownKeys::list_;

  void
  PressDownKeys::initialize(void)
  {}

  void
  PressDownKeys::terminate(void)
  {
    list_.clear();
  }

  void
  PressDownKeys::add(KeyCode key, KeyboardType keyboardType)
  {
    if (key == KeyCode::VK_NONE) return;

    list_.push_back(new Item(key, keyboardType));

    IOLOG_DEVEL("PressDownKeys::add key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::remove(KeyCode key, KeyboardType keyboardType)
  {
    Item* p = static_cast<Item*>(list_.safe_front());
    for (;;) {
      if (! p) break;

      if (p->key == key &&
          p->keyboardType == keyboardType) {
        p = static_cast<Item*>(list_.erase_and_delete(p));
      } else {
        p = static_cast<Item*>(p->getnext());
      }
    }

    IOLOG_DEVEL("PressDownKeys::remove key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::clear(void)
  {
    IOLOG_DEVEL("PressDownKeys::clear list_.size = %d\n", static_cast<int>(list_.size()));

    Item* p = static_cast<Item*>(list_.safe_front());
    for (;;) {
      if (! p) break;

      Params_KeyboardEventCallBack params(EventType::UP, Flags(0), p->key, p->keyboardType, false);

      EventOutputQueue::push(params);
      IOLOG_DEVEL("PressDownKeys::clear key:%d, keyboardType:%d\n", params.key.get(), params.keyboardType.get());

      p = static_cast<Item*>(list_.erase_and_delete(p));
    }
  }
}
<|endoftext|>


<commit_before>/*
 * ServerSessionManager.cpp
 *
 * Copyright (C) 2009-19 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <server/ServerSessionManager.hpp>

#include <boost/foreach.hpp>
#include <boost/format.hpp>

#include <core/SafeConvert.hpp>
#include <core/system/PosixUser.hpp>
#include <core/system/Environment.hpp>
#include <core/json/JsonRpc.hpp>

#include <monitor/MonitorClient.hpp>
#include <session/SessionConstants.hpp>

#include <server/ServerOptions.hpp>

#include <server/ServerErrorCategory.hpp>

#include <server/auth/ServerValidateUser.hpp>

#include "ServerREnvironment.hpp"
#include "server-config.h"

using namespace rstudio::core;

namespace rstudio {
namespace server {

namespace {

static std::string s_launcherToken;

void readRequestArgs(const core::http::Request& request, core::system::Options *pArgs)
{
   // we only do this when establishing new sessions via client_init
   if (!boost::algorithm::ends_with(request.uri(), "client_init"))
      return;

   // parse the request (okay if it fails, none of the below is critical)
   json::JsonRpcRequest clientInit;
   Error error = json::parseJsonRpcRequest(request.body(), &clientInit);
   if (error)
      return;

   // read parameters from the request if present
   int restoreWorkspace = -1;
   json::getOptionalParam<int>(clientInit.kwparams, "restore_workspace", -1, &restoreWorkspace);
   if (restoreWorkspace != -1)
      pArgs->push_back(std::make_pair("--r-restore-workspace",
               safe_convert::numberToString(restoreWorkspace)));
   int runRprofile = -1;
   json::getOptionalParam<int>(clientInit.kwparams, "run_rprofile", -1, &runRprofile);
   if (runRprofile != -1)
      pArgs->push_back(std::make_pair("--r-run-rprofile",
            safe_convert::numberToString(runRprofile)));
}

core::system::ProcessConfig sessionProcessConfig(
         r_util::SessionContext context,
         const core::system::Options& extraArgs = core::system::Options())
{
   // prepare command line arguments
   server::Options& options = server::options();
   core::system::Options args ;

   // check for options-specified config file and add to command
   // line if specified
   std::string rsessionConfigFile(options.rsessionConfigFile());
   if (!rsessionConfigFile.empty())
      args.push_back(std::make_pair("--config-file", rsessionConfigFile));

   // pass the user-identity
   args.push_back(std::make_pair("-" kUserIdentitySessionOptionShort,
                                 context.username));

   // pass the project if specified
   if (!context.scope.project().empty())
   {
      args.push_back(std::make_pair("-" kProjectSessionOptionShort,
                                    context.scope.project()));
   }

   // pass the scope id if specified
   if (!context.scope.id().empty())
   {
      args.push_back(std::make_pair("-" kScopeSessionOptionShort,
                                    context.scope.id()));
   }

   // create launch token if we haven't already
   if (s_launcherToken.empty())
      s_launcherToken = core::system::generateShortenedUuid();
   args.push_back(std::make_pair("--launcher-token", s_launcherToken));

   // allow session timeout to be overridden via environment variable
   std::string timeout = core::system::getenv("RSTUDIO_SESSION_TIMEOUT");
   if (!timeout.empty())
      args.push_back(std::make_pair("--" kTimeoutSessionOption, timeout));

   // pass our uid to instruct rsession to limit rpc clients to us and itself
   core::system::Options environment;
   uid_t uid = core::system::user::currentUserIdentity().userId;
   environment.push_back(std::make_pair(
                           kRStudioLimitRpcClientUid,
                           safe_convert::numberToString(uid)));

   // set session scope project if we have one
   if (!context.scope.project().empty())
   {
      environment.push_back(std::make_pair(
                              kRStudioSessionScopeProject,
                              context.scope.project()));
   }

   // set session scope id if we have one
   if (!context.scope.id().empty())
   {
      environment.push_back(std::make_pair(
                              kRStudioSessionScopeId,
                              context.scope.id()));
   }

   sessionProcessConfigOverlay(&args, &environment);

   // pass extra params
   std::copy(extraArgs.begin(), extraArgs.end(), std::back_inserter(args));

   // append R environment variables
   r_util::RVersion rVersion = r_environment::rVersion();
   core::system::Options rEnvVars = rVersion.environment();
   environment.insert(environment.end(), rEnvVars.begin(), rEnvVars.end());

   // mark this as the system default R version
   core::system::setenv(&environment,
                        kRStudioDefaultRVersion,
                        rVersion.number());
   core::system::setenv(&environment,
                        kRStudioDefaultRVersionHome,
                        rVersion.homeDir().absolutePath());

   // forward the auth options
   core::system::setenv(&environment,
                        kRStudioRequiredUserGroup,
                        options.authRequiredUserGroup());
   core::system::setenv(&environment,
                        kRStudioMinimumUserId,
                        safe_convert::numberToString(
                                 options.authMinimumUserId()));

   // add monitor shared secret
   environment.push_back(std::make_pair(kMonitorSharedSecretEnvVar,
                                        options.monitorSharedSecret()));

   // stamp the version number of the rserver process that is launching this session
   // the session should log an error if its version does not match, as that is
   // likely an unsupported configuration
   environment.push_back({kRStudioVersion, RSTUDIO_VERSION});

   // build the config object and return it
   core::system::ProcessConfig config;
   config.args = args;
   config.environment = environment;
   config.stdStreamBehavior = core::system::StdStreamInherit;
   return config;
}

void onProcessExit(const std::string& username, PidType pid)
{
}

} // anonymous namespace

SessionManager& sessionManager()
{
   static SessionManager instance;
   return instance;
}

SessionManager::SessionManager()
{
   // set default session launcher
   sessionLaunchFunction_ = boost::bind(&SessionManager::launchAndTrackSession,
                                           this, _1, _2);
}

Error SessionManager::launchSession(boost::asio::io_service& ioService,
                                    const r_util::SessionContext& context,
                                    const http::Request& request,
                                    const http::ResponseHandler& onLaunch,
                                    const http::ErrorHandler& onError)
{
   using namespace boost::posix_time;
   LOCK_MUTEX(launchesMutex_)
   {
      // check whether we already have a launch pending
      LaunchMap::const_iterator pos = pendingLaunches_.find(context);
      if (pos != pendingLaunches_.end())
      {
         // if the launch is less than one minute old then return success
         if ( (pos->second + boost::posix_time::minutes(1))
               > microsec_clock::universal_time() )
         {
            return Success();
         }
         // otherwise erase it from pending launches and then
         // re-launch (immediately below)
         else
         {
            // very unexpected condition
            LOG_WARNING_MESSAGE("Very long session launch delay for "
                                "user " + context.username +" (aborting wait)");

            pendingLaunches_.erase(context);
         }
      }

      // record the launch
      pendingLaunches_[context] =  microsec_clock::universal_time();
   }
   END_LOCK_MUTEX

   // translate querystring arguments into extra session args
   core::system::Options args;
   readRequestArgs(request, &args);
   std::cerr << "process launch request " << request << std::endl;

   // determine launch options
   r_util::SessionLaunchProfile profile;
   profile.context = context;
   profile.executablePath = server::options().rsessionPath();
   profile.config = sessionProcessConfig(context, args);

   // pass the profile to any filters we have
   BOOST_FOREACH(SessionLaunchProfileFilter f, sessionLaunchProfileFilters_)
   {
      f(&profile);
   }

   // launch the session
   Error error = sessionLaunchFunction_(ioService, profile, request, onLaunch, onError);
   if (error)
   {
      removePendingLaunch(context);
      return error;
   }

   return Success();
}

namespace {

boost::mutex s_configFilterMutex;
core::system::ProcessConfigFilter s_processConfigFilter;

} // anonymous namespace

void setProcessConfigFilter(const core::system::ProcessConfigFilter& filter)
{
   LOCK_MUTEX(s_configFilterMutex)
   {
      s_processConfigFilter = filter;
   }
   END_LOCK_MUTEX
}

// default session launcher -- does the launch then tracks the pid
// for later reaping
Error SessionManager::launchAndTrackSession(
                           boost::asio::io_service&,
                           const core::r_util::SessionLaunchProfile& profile)
{
   // if we are root then assume the identity of the user
   using namespace rstudio::core::system;
   std::string runAsUser = realUserIsRoot() ? profile.context.username : "";

   core::system::ProcessConfigFilter configFilter;
   LOCK_MUTEX(s_configFilterMutex)
   {
      configFilter = s_processConfigFilter;
   }
   END_LOCK_MUTEX

   // launch the session
   PidType pid = 0;
   Error error = launchChildProcess(profile.executablePath,
                                    runAsUser,
                                    profile.config,
                                    configFilter,
                                    &pid);
   if (error)
      return error;

   // track it for subsequent reaping
   processTracker_.addProcess(pid, boost::bind(onProcessExit,
                                               profile.context.username,
                                               pid));

   // return success
   return Success();
}

void SessionManager::setSessionLaunchFunction(
                           const SessionLaunchFunction& launchFunction)
{
   sessionLaunchFunction_ = launchFunction;
}

void SessionManager::addSessionLaunchProfileFilter(
                              const SessionLaunchProfileFilter& filter)
{
   sessionLaunchProfileFilters_.push_back(filter);
}

void SessionManager::removePendingLaunch(const r_util::SessionContext& context)
{
   LOCK_MUTEX(launchesMutex_)
   {
      pendingLaunches_.erase(context);
   }
   END_LOCK_MUTEX
}

void SessionManager::notifySIGCHLD()
{
   processTracker_.notifySIGCHILD();
}

// helper function for verify-installation
Error launchSession(const r_util::SessionContext& context,
                    const core::system::Options& extraArgs,
                    PidType* pPid)
{
   // launch the session
   std::string username = context.username;
   std::string rsessionPath = server::options().rsessionPath();
   std::string runAsUser = core::system::realUserIsRoot() ? username : "";
   core::system::ProcessConfig config = sessionProcessConfig(context,
                                                             extraArgs);

   *pPid = -1;
   return core::system::launchChildProcess(rsessionPath,
                                           runAsUser,
                                           config,
                                           core::system::ProcessConfigFilter(),
                                           pPid);
}

} // namespace server
} // namespace rstudio

<commit_msg>remove debug logging<commit_after>/*
 * ServerSessionManager.cpp
 *
 * Copyright (C) 2009-19 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <server/ServerSessionManager.hpp>

#include <boost/foreach.hpp>
#include <boost/format.hpp>

#include <core/SafeConvert.hpp>
#include <core/system/PosixUser.hpp>
#include <core/system/Environment.hpp>
#include <core/json/JsonRpc.hpp>

#include <monitor/MonitorClient.hpp>
#include <session/SessionConstants.hpp>

#include <server/ServerOptions.hpp>

#include <server/ServerErrorCategory.hpp>

#include <server/auth/ServerValidateUser.hpp>

#include "ServerREnvironment.hpp"
#include "server-config.h"

using namespace rstudio::core;

namespace rstudio {
namespace server {

namespace {

static std::string s_launcherToken;

void readRequestArgs(const core::http::Request& request, core::system::Options *pArgs)
{
   // we only do this when establishing new sessions via client_init
   if (!boost::algorithm::ends_with(request.uri(), "client_init"))
      return;

   // parse the request (okay if it fails, none of the below is critical)
   json::JsonRpcRequest clientInit;
   Error error = json::parseJsonRpcRequest(request.body(), &clientInit);
   if (error)
      return;

   // read parameters from the request if present
   int restoreWorkspace = -1;
   json::getOptionalParam<int>(clientInit.kwparams, "restore_workspace", -1, &restoreWorkspace);
   if (restoreWorkspace != -1)
      pArgs->push_back(std::make_pair("--r-restore-workspace",
               safe_convert::numberToString(restoreWorkspace)));
   int runRprofile = -1;
   json::getOptionalParam<int>(clientInit.kwparams, "run_rprofile", -1, &runRprofile);
   if (runRprofile != -1)
      pArgs->push_back(std::make_pair("--r-run-rprofile",
            safe_convert::numberToString(runRprofile)));
}

core::system::ProcessConfig sessionProcessConfig(
         r_util::SessionContext context,
         const core::system::Options& extraArgs = core::system::Options())
{
   // prepare command line arguments
   server::Options& options = server::options();
   core::system::Options args ;

   // check for options-specified config file and add to command
   // line if specified
   std::string rsessionConfigFile(options.rsessionConfigFile());
   if (!rsessionConfigFile.empty())
      args.push_back(std::make_pair("--config-file", rsessionConfigFile));

   // pass the user-identity
   args.push_back(std::make_pair("-" kUserIdentitySessionOptionShort,
                                 context.username));

   // pass the project if specified
   if (!context.scope.project().empty())
   {
      args.push_back(std::make_pair("-" kProjectSessionOptionShort,
                                    context.scope.project()));
   }

   // pass the scope id if specified
   if (!context.scope.id().empty())
   {
      args.push_back(std::make_pair("-" kScopeSessionOptionShort,
                                    context.scope.id()));
   }

   // create launch token if we haven't already
   if (s_launcherToken.empty())
      s_launcherToken = core::system::generateShortenedUuid();
   args.push_back(std::make_pair("--launcher-token", s_launcherToken));

   // allow session timeout to be overridden via environment variable
   std::string timeout = core::system::getenv("RSTUDIO_SESSION_TIMEOUT");
   if (!timeout.empty())
      args.push_back(std::make_pair("--" kTimeoutSessionOption, timeout));

   // pass our uid to instruct rsession to limit rpc clients to us and itself
   core::system::Options environment;
   uid_t uid = core::system::user::currentUserIdentity().userId;
   environment.push_back(std::make_pair(
                           kRStudioLimitRpcClientUid,
                           safe_convert::numberToString(uid)));

   // set session scope project if we have one
   if (!context.scope.project().empty())
   {
      environment.push_back(std::make_pair(
                              kRStudioSessionScopeProject,
                              context.scope.project()));
   }

   // set session scope id if we have one
   if (!context.scope.id().empty())
   {
      environment.push_back(std::make_pair(
                              kRStudioSessionScopeId,
                              context.scope.id()));
   }

   sessionProcessConfigOverlay(&args, &environment);

   // pass extra params
   std::copy(extraArgs.begin(), extraArgs.end(), std::back_inserter(args));

   // append R environment variables
   r_util::RVersion rVersion = r_environment::rVersion();
   core::system::Options rEnvVars = rVersion.environment();
   environment.insert(environment.end(), rEnvVars.begin(), rEnvVars.end());

   // mark this as the system default R version
   core::system::setenv(&environment,
                        kRStudioDefaultRVersion,
                        rVersion.number());
   core::system::setenv(&environment,
                        kRStudioDefaultRVersionHome,
                        rVersion.homeDir().absolutePath());

   // forward the auth options
   core::system::setenv(&environment,
                        kRStudioRequiredUserGroup,
                        options.authRequiredUserGroup());
   core::system::setenv(&environment,
                        kRStudioMinimumUserId,
                        safe_convert::numberToString(
                                 options.authMinimumUserId()));

   // add monitor shared secret
   environment.push_back(std::make_pair(kMonitorSharedSecretEnvVar,
                                        options.monitorSharedSecret()));

   // stamp the version number of the rserver process that is launching this session
   // the session should log an error if its version does not match, as that is
   // likely an unsupported configuration
   environment.push_back({kRStudioVersion, RSTUDIO_VERSION});

   // build the config object and return it
   core::system::ProcessConfig config;
   config.args = args;
   config.environment = environment;
   config.stdStreamBehavior = core::system::StdStreamInherit;
   return config;
}

void onProcessExit(const std::string& username, PidType pid)
{
}

} // anonymous namespace

SessionManager& sessionManager()
{
   static SessionManager instance;
   return instance;
}

SessionManager::SessionManager()
{
   // set default session launcher
   sessionLaunchFunction_ = boost::bind(&SessionManager::launchAndTrackSession,
                                           this, _1, _2);
}

Error SessionManager::launchSession(boost::asio::io_service& ioService,
                                    const r_util::SessionContext& context,
                                    const http::Request& request,
                                    const http::ResponseHandler& onLaunch,
                                    const http::ErrorHandler& onError)
{
   using namespace boost::posix_time;
   LOCK_MUTEX(launchesMutex_)
   {
      // check whether we already have a launch pending
      LaunchMap::const_iterator pos = pendingLaunches_.find(context);
      if (pos != pendingLaunches_.end())
      {
         // if the launch is less than one minute old then return success
         if ( (pos->second + boost::posix_time::minutes(1))
               > microsec_clock::universal_time() )
         {
            return Success();
         }
         // otherwise erase it from pending launches and then
         // re-launch (immediately below)
         else
         {
            // very unexpected condition
            LOG_WARNING_MESSAGE("Very long session launch delay for "
                                "user " + context.username +" (aborting wait)");

            pendingLaunches_.erase(context);
         }
      }

      // record the launch
      pendingLaunches_[context] =  microsec_clock::universal_time();
   }
   END_LOCK_MUTEX

   // translate querystring arguments into extra session args
   core::system::Options args;
   readRequestArgs(request, &args);

   // determine launch options
   r_util::SessionLaunchProfile profile;
   profile.context = context;
   profile.executablePath = server::options().rsessionPath();
   profile.config = sessionProcessConfig(context, args);

   // pass the profile to any filters we have
   BOOST_FOREACH(SessionLaunchProfileFilter f, sessionLaunchProfileFilters_)
   {
      f(&profile);
   }

   // launch the session
   Error error = sessionLaunchFunction_(ioService, profile, request, onLaunch, onError);
   if (error)
   {
      removePendingLaunch(context);
      return error;
   }

   return Success();
}

namespace {

boost::mutex s_configFilterMutex;
core::system::ProcessConfigFilter s_processConfigFilter;

} // anonymous namespace

void setProcessConfigFilter(const core::system::ProcessConfigFilter& filter)
{
   LOCK_MUTEX(s_configFilterMutex)
   {
      s_processConfigFilter = filter;
   }
   END_LOCK_MUTEX
}

// default session launcher -- does the launch then tracks the pid
// for later reaping
Error SessionManager::launchAndTrackSession(
                           boost::asio::io_service&,
                           const core::r_util::SessionLaunchProfile& profile)
{
   // if we are root then assume the identity of the user
   using namespace rstudio::core::system;
   std::string runAsUser = realUserIsRoot() ? profile.context.username : "";

   core::system::ProcessConfigFilter configFilter;
   LOCK_MUTEX(s_configFilterMutex)
   {
      configFilter = s_processConfigFilter;
   }
   END_LOCK_MUTEX

   // launch the session
   PidType pid = 0;
   Error error = launchChildProcess(profile.executablePath,
                                    runAsUser,
                                    profile.config,
                                    configFilter,
                                    &pid);
   if (error)
      return error;

   // track it for subsequent reaping
   processTracker_.addProcess(pid, boost::bind(onProcessExit,
                                               profile.context.username,
                                               pid));

   // return success
   return Success();
}

void SessionManager::setSessionLaunchFunction(
                           const SessionLaunchFunction& launchFunction)
{
   sessionLaunchFunction_ = launchFunction;
}

void SessionManager::addSessionLaunchProfileFilter(
                              const SessionLaunchProfileFilter& filter)
{
   sessionLaunchProfileFilters_.push_back(filter);
}

void SessionManager::removePendingLaunch(const r_util::SessionContext& context)
{
   LOCK_MUTEX(launchesMutex_)
   {
      pendingLaunches_.erase(context);
   }
   END_LOCK_MUTEX
}

void SessionManager::notifySIGCHLD()
{
   processTracker_.notifySIGCHILD();
}

// helper function for verify-installation
Error launchSession(const r_util::SessionContext& context,
                    const core::system::Options& extraArgs,
                    PidType* pPid)
{
   // launch the session
   std::string username = context.username;
   std::string rsessionPath = server::options().rsessionPath();
   std::string runAsUser = core::system::realUserIsRoot() ? username : "";
   core::system::ProcessConfig config = sessionProcessConfig(context,
                                                             extraArgs);

   *pPid = -1;
   return core::system::launchChildProcess(rsessionPath,
                                           runAsUser,
                                           config,
                                           core::system::ProcessConfigFilter(),
                                           pPid);
}

} // namespace server
} // namespace rstudio

<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2022 Ryo Suzuki
//	Copyright (c) 2016-2022 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <Siv3D/ImageDecoder.hpp>
# include <Siv3D/BinaryReader.hpp>
# include "IImageDecoder.hpp"
# include <Siv3D/Common/Siv3DEngine.hpp>

namespace s3d
{
	namespace ImageDecoder
	{
		Optional<ImageInfo> GetImageInfo(const FilePathView path, const ImageFormat imageFormat)
		{
			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->getImageInfo(reader, path, imageFormat);
		}

		Optional<ImageInfo> GetImageInfo(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->getImageInfo(reader, {}, imageFormat);
		}

		Image Decode(const FilePathView path, const ImageFormat imageFormat)
		{
			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->decode(reader, path, imageFormat);
		}

		Image Decode(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->decode(reader, {}, imageFormat);
		}

		Grid<uint16> DecodeGray16(FilePathView path, const ImageFormat imageFormat)
		{
			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->decodeGray16(reader, path, imageFormat);
		}

		Grid<uint16> DecodeGray16(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->decodeGray16(reader, {}, imageFormat);
		}

		bool Add(std::unique_ptr<IImageDecoder>&& decoder)
		{
			return SIV3D_ENGINE(ImageDecoder)->add(std::move(decoder));
		}

		void Remove(const StringView name)
		{
			return SIV3D_ENGINE(ImageDecoder)->remove(name);
		}

		const Array<std::unique_ptr<IImageDecoder>>& Enum()
		{
			return SIV3D_ENGINE(ImageDecoder)->enumDecoder();
		}
	}
}
<commit_msg>[Web] Use FetchFileIfNotExists in Image Decode<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2022 Ryo Suzuki
//	Copyright (c) 2016-2022 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <Siv3D/ImageDecoder.hpp>
# include <Siv3D/BinaryReader.hpp>
# include "IImageDecoder.hpp"
# include <Siv3D/Common/Siv3DEngine.hpp>
# include <Siv3D/FileSystem.hpp>

namespace s3d
{
	namespace ImageDecoder
	{
		Optional<ImageInfo> GetImageInfo(const FilePathView path, const ImageFormat imageFormat)
		{
			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->getImageInfo(reader, path, imageFormat);
		}

		Optional<ImageInfo> GetImageInfo(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->getImageInfo(reader, {}, imageFormat);
		}

		Image Decode(const FilePathView path, const ImageFormat imageFormat)
		{
		# if SIV3D_PLATFORM(WEB)
			Platform::Web::FileSystem::FetchFileIfNotExists(path);
		# endif

			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->decode(reader, path, imageFormat);
		}

		Image Decode(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->decode(reader, {}, imageFormat);
		}

		Grid<uint16> DecodeGray16(FilePathView path, const ImageFormat imageFormat)
		{
			BinaryReader reader(path);

			if (not reader)
			{
				return{};
			}

			return SIV3D_ENGINE(ImageDecoder)->decodeGray16(reader, path, imageFormat);
		}

		Grid<uint16> DecodeGray16(IReader& reader, const ImageFormat imageFormat)
		{
			return SIV3D_ENGINE(ImageDecoder)->decodeGray16(reader, {}, imageFormat);
		}

		bool Add(std::unique_ptr<IImageDecoder>&& decoder)
		{
			return SIV3D_ENGINE(ImageDecoder)->add(std::move(decoder));
		}

		void Remove(const StringView name)
		{
			return SIV3D_ENGINE(ImageDecoder)->remove(name);
		}

		const Array<std::unique_ptr<IImageDecoder>>& Enum()
		{
			return SIV3D_ENGINE(ImageDecoder)->enumDecoder();
		}
	}
}
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2016 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "BinaryLogSinkWrapper.h"

#include "storage/DRTupleStream.h"
#include "storage/CompatibleDRTupleStream.h"
#include "common/serializeio.h"

using namespace std;
using namespace voltdb;

int64_t BinaryLogSinkWrapper::apply(const char* taskParams, boost::unordered_map<int64_t, PersistentTable*> &tables,
                                    Pool *pool, VoltDBEngine *engine, int32_t remoteClusterId)
{
    ReferenceSerializeInputLE taskInfo(taskParams + 4, ntohl(*reinterpret_cast<const int32_t*>(taskParams)));

    int64_t __attribute__ ((unused)) uniqueId = 0;
    int64_t __attribute__ ((unused)) sequenceNumber = -1;

    int64_t rowCount = 0;
    while (taskInfo.hasRemaining()) {
        pool->purge();
        const char* recordStart = taskInfo.getRawPointer();
        const uint8_t drVersion = taskInfo.readByte();
        if (drVersion == DRTupleStream::PROTOCOL_VERSION) { // currently 4
            rowCount += m_sink.applyTxn(&taskInfo, tables, pool, engine, remoteClusterId,
                                        recordStart);
        } else if (drVersion == CompatibleDRTupleStream::COMPATIBLE_PROTOCOL_VERSION) {
            rowCount += m_compatibleSink.apply(&taskInfo, tables, pool, engine, remoteClusterId,
                                               recordStart, &uniqueId, &sequenceNumber);
        } else {
            throwFatalException("Unsupported DR version %d", drVersion);
        }
    }
    return rowCount;
}
<commit_msg>ENG-10641: Populate and use fragment parameters as before when replaying ApplyBinaryLogMP on cluster recover, use only invocation parameters for normal execution<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2016 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "BinaryLogSinkWrapper.h"

#include "storage/DRTupleStream.h"
#include "storage/CompatibleDRTupleStream.h"
#include "common/serializeio.h"

using namespace std;
using namespace voltdb;

int64_t BinaryLogSinkWrapper::apply(const char* taskParams, boost::unordered_map<int64_t, PersistentTable*> &tables,
                                    Pool *pool, VoltDBEngine *engine, int32_t remoteClusterId)
{
    ReferenceSerializeInputLE taskInfo(taskParams + 4, ntohl(*reinterpret_cast<const int32_t*>(taskParams)));

    int64_t __attribute__ ((unused)) uniqueId = 0;
    int64_t __attribute__ ((unused)) sequenceNumber = -1;

    int64_t rowCount = 0;
    while (taskInfo.hasRemaining()) {
        pool->purge();
        const char* recordStart = taskInfo.getRawPointer();
        const uint8_t drVersion = taskInfo.readByte();
        if (drVersion == DRTupleStream::PROTOCOL_VERSION) {
            rowCount += m_sink.applyTxn(&taskInfo, tables, pool, engine, remoteClusterId,
                                        recordStart);
        } else if (drVersion == CompatibleDRTupleStream::COMPATIBLE_PROTOCOL_VERSION) {
            rowCount += m_compatibleSink.apply(&taskInfo, tables, pool, engine, remoteClusterId,
                                               recordStart, &uniqueId, &sequenceNumber);
        } else {
            throwFatalException("Unsupported DR version %d", drVersion);
        }
    }
    return rowCount;
}
<|endoftext|>


<commit_before>#include "LIBCD.H"

#include "EMULATOR_SETUP.H"
#include "EMULATOR.H"

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

enum ReadMode
{
	RM_DATA,
	RM_XA_AUDIO
};

enum ReadMode readMode = RM_DATA;

int CD_Debug = 0;

FILE* openFile = NULL;

typedef struct commandQueue
{
	unsigned int mode;
	unsigned char* p;
	unsigned int processed;
	unsigned int count;
}commandQueue_s, *commandQueue_p;

#define COMMAND_QUEUE_SIZE 128

struct commandQueue comQueue[COMMAND_QUEUE_SIZE];
int comQueueIndex = 0;
int comQueueCount = 0;
int currentSector = 0;
int sectorSize = 0;
int currentTrack = 0;
int numFrames = 0;
int CD_com = 0;

#pragma pack(push, 1)
struct TOC
{
	unsigned char tocEntryLength;
	unsigned char extEntryLength;
	unsigned int sectorPosition[2];
	unsigned int fileSize[2];
	unsigned char date[7];
	unsigned char flags;
	unsigned char fileUnitSize;
	unsigned char interleaveGapSize;
	unsigned short volSeqNum[2];
	unsigned char nameLength;
};

struct Sector
{
	unsigned char	sync[12];	/// Sync pattern (usually 00 FF FF FF FF FF FF FF FF FF FF 00)
	unsigned char	addr[3];	/// Sector address (see below for encoding details)
	unsigned char	mode;		/// Mode (usually 2 for Mode 2 Form 1/2 sectors)
	unsigned char	subHead[8];	/// Sub-header (00 00 08 00 00 00 08 00 for Form 1 data sectors)
	unsigned char	data[2048];	/// Data (form 1)
	unsigned char	edc[4];		/// Error-detection code (CRC32 of data area)
	unsigned char	ecc[276];	/// Error-correction code (uses Reed-Solomon ECC algorithm)
};

struct AudioSector
{
	unsigned char	sync[12];	/// Sync pattern (usually 00 FF FF FF FF FF FF FF FF FF FF 00)
	unsigned char	addr[3];	/// Sector address (a 24-bit big-endian integer. starts at 200, 201 an onwards)
	unsigned char	mode;		/// Mode (usually 2 for Mode 2 Form 1/2 sectors)
	unsigned char	data[2336];	/// 8 bytes Subheader, 2324 bytes Data (form 2), and 4 bytes ECC
};
#pragma pack(pop)

CdlFILE* CdSearchFile(CdlFILE* fp, char* name)
{
	SDL_memset(fp, 0, sizeof(CdlFILE));

	if (name[0] == '\\')
	{
		name++;
	}

	if (openFile != NULL)
	{
		fseek(openFile, 22 * sectorSize, SEEK_SET);

		int tocLocalOffset = 0;
        struct Sector sector;
		fread(&sector, sizeof(struct Sector), 1, openFile);
        struct TOC* toc = (struct TOC*)&sector.data[0];
		while (toc->tocEntryLength != 0)
		{
			if (strcmp((char*)&sector.data[tocLocalOffset + sizeof(struct TOC)], name) == 0)
			{
				memcpy(&fp->name[0], (char*)&sector.data[tocLocalOffset + sizeof(struct TOC)], strlen(name));
				fp->size = toc->fileSize[0];
				fseek(openFile, toc->sectorPosition[0] * sectorSize, SEEK_SET);
				fread(&sector, sizeof(struct Sector), 1, openFile);
				fp->pos.minute = sector.addr[0];
				fp->pos.second = sector.addr[1];
				fp->pos.sector = sector.addr[2];

#if _DEBUG
				eprintf("Found %s\n", name);
#endif
				return fp;
			}
			tocLocalOffset += toc->tocEntryLength;
			toc = (struct TOC*)&sector.data[tocLocalOffset];
		}
	}

	return NULL;
}

CdlLOC* CdIntToPos(int i, CdlLOC* p)
{
	i += 150;
	p->sector = ENCODE_BCD(i % 75);
	int rem = i / 75;
	p->second = ENCODE_BCD(rem % 60);
	p->minute = ENCODE_BCD(rem / 60);
	return p;
}

int CdControl(u_char com, u_char * param, u_char * result)
{
	CdlLOC* cd = (CdlLOC*)param;

	CD_com = com;

	switch (com)
	{
	case CdlSetloc:
		fseek(openFile, CdPosToInt(cd)*sectorSize, SEEK_SET);
		break;
	case CdlReadS:
	{
		unsigned int filePos = ftell(openFile);
		CdlLOC currentLoc;
		CdIntToPos(filePos, &currentLoc);
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		currentSector = CdPosToInt(cd);
		if (cd->sector != currentLoc.sector)
		{
			return 1;
		}
		break;
	}
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdControlB(u_char com, u_char* param, u_char* result)
{
	CD_com = com;

	switch (com)
	{
	case CdlSetloc:
	{
		CdlLOC* cd = (CdlLOC*)param;
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		readMode = RM_DATA;
		break;
	}
	case CdlSetfilter:
	{
		CdlFILTER* cdf = (CdlFILTER*)param;
		//TODO Set channel
		break;
	}
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdControlF(u_char com, u_char * param)
{
	CD_com = com;

	switch (com)
	{
	case CdlSetloc:
	{
		CdlLOC* cd = (CdlLOC*)param;
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		break;
	}
	case CdlSetfilter:
	{
		CdlFILTER* cdf = (CdlFILTER*)param;
		//TODO Set channel
		break;
	}
	case CdlGetlocP:
		readMode = RM_XA_AUDIO;
		break;
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdPosToInt(CdlLOC* p)
{
	return (75 * (60 * DECODE_BCD(p->minute) + DECODE_BCD(p->second))) + DECODE_BCD(p->sector) - 150;
}

int CdRead(int sectors, u_long* buf, int mode)
{
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		if (comQueue[i].processed == 1)
		{
			comQueue[i].mode = CdlReadS;///@TODO really mode
			comQueue[i].p = (unsigned char*)buf;
			comQueue[i].processed = 0;
			comQueue[i].count = sectors;
			break;
		}
	}
	return 0;
}

int CdReadSync(int mode, u_char* result)
{
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		if (comQueue[i].processed == 0)
		{
			if (readMode == RM_DATA)
			{
				struct Sector sector;
				fread(&sector, sizeof(struct Sector), 1, openFile);

				memcpy(comQueue[i].p, &sector.data[0], sizeof(sector.data));
				comQueue[i].p += sizeof(sector.data);
			}
			else if (readMode == RM_XA_AUDIO)
			{
				struct AudioSector sector;
				fread(&sector, sizeof(struct AudioSector), 1, openFile);

				memcpy(comQueue[i].p, &sector.data[0], sizeof(sector.data));
				comQueue[i].p += sizeof(sector.data);
			}
			else
			{
				assert(FALSE);
			}

			if (--comQueue[i].count == 0)
			{
				comQueue[i].processed = 1;
				break;
			}

			return 1;
		}
	}
	return 0;
}

int CdSetDebug(int level)
{
	int lastLevel = CD_Debug;
	CD_Debug = level;
	return lastLevel;
}

int CdSync(int mode, u_char * result)
{
	CdlLOC* loc = (CdlLOC*)result;
	switch (mode)
	{
	case 0:
		UNIMPLEMENTED();
		assert(FALSE);
		break;
	case 1:

		switch (CdLastCom())
		{
		case CdlGetlocP:
			CdlLOC locP;
			CdIntToPos(currentSector+=20, &locP);
			result[0] = currentTrack;
			result[1] = 1;//index, usually 1
			result[2] = locP.minute;
			result[3] = locP.second;
			result[4] = locP.sector;
			result[5] = locP.minute + ENCODE_BCD(numFrames);
			result[6] = locP.second + ENCODE_BCD(numFrames);
			result[7] = locP.sector + ENCODE_BCD(numFrames);

			//Dirty, for now read the audio data
			if (readMode == RM_XA_AUDIO)
			{
				char xaAudioData[2336];
				CdRead(1, (unsigned long*)&xaAudioData[0], CdlReadS);
				CdReadSync(CdlReadS, NULL);

				//Sector should be read now
				xaAudioData[0] = 0;
			}

			break;
		}
		return CdlComplete;
		break;
	}

	return 0;
}

int ParseCueSheet()
{
	char* binFileName = NULL;
	openFile = fopen(DISC_IMAGE_FILENAME, "rb");

	if (openFile == NULL)
	{
		eprinterr("Failed to open disc image file! %s\n", DISC_IMAGE_FILENAME);
		return 0;
	}

	fseek(openFile, 0, SEEK_END);
	unsigned int cueSheetFileLength = ftell(openFile);
	char* cueSheet = (char*)malloc(cueSheetFileLength);
	fseek(openFile, 0, SEEK_SET);
	fread(cueSheet, cueSheetFileLength, 1, openFile);

	//Null terminated
	char* string = &cueSheet[0];
	if (!strncmp(string, "FILE", 4))
	{
		//Read the binary name since it's a file
		string += 5;
		if (isspace(string[0]))
		{
			string++;
		}

		//Get file name length
		char* afterFileName = string;
		char fileNameLength = 0;
		//While
		while (!isspace(afterFileName[0]))
		{
			afterFileName++;
			fileNameLength++;
		}

		if (string[0] == '"')
		{
			string[fileNameLength - 1] = 0;
			string++;
		}

		binFileName = string;
		string = afterFileName;

		if (isspace(string[0]))
			string++;

		/* Get Type of BIN file */
		assert(!strncmp(string, "BINARY", 6));
		string += 6;

		while (isspace(string[0]))
			string++;

		/* Get Track of BIN file */
		assert(!strncmp(string, "TRACK", 5));
		string += 5;

		while (isspace(string[0]))
			string++;

		currentTrack = atoi(string);

		string += 2;

		while (isspace(string[0]))
			string++;

		assert(!strncmp(string, "MODE1", 5));
		string += 5;

		assert(string[0] == '/');
		string++;

		sectorSize = atoi(string);

		assert(sectorSize == 2352);

		fclose(openFile);
		openFile = fopen(binFileName, "rb");
		fseek(openFile, 0, SEEK_END);
		unsigned int binFileLength = ftell(openFile);
		numFrames = binFileLength / sectorSize;
		assert(numFrames != 0);
		fseek(openFile, 0, SEEK_SET);
		free(cueSheet);
	}

	return 1;
}

int CdInit(void)
{
	currentSector = 0;

	//Read the cue sheet and obtain properties from it.
	if (!ParseCueSheet())
	{
		eprinterr("Failed to read cue sheet!");
		return 0;
	}

	SDL_memset(&comQueue, 0, sizeof(comQueue));
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		comQueue[i].processed = 1;
	}

	return 1;
}

int CdLastCom(void)
{
	return CD_com;
}
<commit_msg>[Emu]: Return if no CD image file detected.<commit_after>#include "LIBCD.H"

#include "EMULATOR_SETUP.H"
#include "EMULATOR.H"

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

enum ReadMode
{
	RM_DATA,
	RM_XA_AUDIO
};

enum ReadMode readMode = RM_DATA;

int CD_Debug = 0;

FILE* openFile = NULL;

typedef struct commandQueue
{
	unsigned int mode;
	unsigned char* p;
	unsigned int processed;
	unsigned int count;
}commandQueue_s, *commandQueue_p;

#define COMMAND_QUEUE_SIZE 128

struct commandQueue comQueue[COMMAND_QUEUE_SIZE];
int comQueueIndex = 0;
int comQueueCount = 0;
int currentSector = 0;
int sectorSize = 0;
int currentTrack = 0;
int numFrames = 0;
int CD_com = 0;

#pragma pack(push, 1)
struct TOC
{
	unsigned char tocEntryLength;
	unsigned char extEntryLength;
	unsigned int sectorPosition[2];
	unsigned int fileSize[2];
	unsigned char date[7];
	unsigned char flags;
	unsigned char fileUnitSize;
	unsigned char interleaveGapSize;
	unsigned short volSeqNum[2];
	unsigned char nameLength;
};

struct Sector
{
	unsigned char	sync[12];	/// Sync pattern (usually 00 FF FF FF FF FF FF FF FF FF FF 00)
	unsigned char	addr[3];	/// Sector address (see below for encoding details)
	unsigned char	mode;		/// Mode (usually 2 for Mode 2 Form 1/2 sectors)
	unsigned char	subHead[8];	/// Sub-header (00 00 08 00 00 00 08 00 for Form 1 data sectors)
	unsigned char	data[2048];	/// Data (form 1)
	unsigned char	edc[4];		/// Error-detection code (CRC32 of data area)
	unsigned char	ecc[276];	/// Error-correction code (uses Reed-Solomon ECC algorithm)
};

struct AudioSector
{
	unsigned char	sync[12];	/// Sync pattern (usually 00 FF FF FF FF FF FF FF FF FF FF 00)
	unsigned char	addr[3];	/// Sector address (a 24-bit big-endian integer. starts at 200, 201 an onwards)
	unsigned char	mode;		/// Mode (usually 2 for Mode 2 Form 1/2 sectors)
	unsigned char	data[2336];	/// 8 bytes Subheader, 2324 bytes Data (form 2), and 4 bytes ECC
};
#pragma pack(pop)

CdlFILE* CdSearchFile(CdlFILE* fp, char* name)
{
	SDL_memset(fp, 0, sizeof(CdlFILE));

	if (name[0] == '\\')
	{
		name++;
	}

	if (openFile != NULL)
	{
		fseek(openFile, 22 * sectorSize, SEEK_SET);

		int tocLocalOffset = 0;
        struct Sector sector;
		fread(&sector, sizeof(struct Sector), 1, openFile);
        struct TOC* toc = (struct TOC*)&sector.data[0];
		while (toc->tocEntryLength != 0)
		{
			if (strcmp((char*)&sector.data[tocLocalOffset + sizeof(struct TOC)], name) == 0)
			{
				memcpy(&fp->name[0], (char*)&sector.data[tocLocalOffset + sizeof(struct TOC)], strlen(name));
				fp->size = toc->fileSize[0];
				fseek(openFile, toc->sectorPosition[0] * sectorSize, SEEK_SET);
				fread(&sector, sizeof(struct Sector), 1, openFile);
				fp->pos.minute = sector.addr[0];
				fp->pos.second = sector.addr[1];
				fp->pos.sector = sector.addr[2];

#if _DEBUG
				eprintf("Found %s\n", name);
#endif
				return fp;
			}
			tocLocalOffset += toc->tocEntryLength;
			toc = (struct TOC*)&sector.data[tocLocalOffset];
		}
	}

	return NULL;
}

CdlLOC* CdIntToPos(int i, CdlLOC* p)
{
	i += 150;
	p->sector = ENCODE_BCD(i % 75);
	int rem = i / 75;
	p->second = ENCODE_BCD(rem % 60);
	p->minute = ENCODE_BCD(rem / 60);
	return p;
}

int CdControl(u_char com, u_char * param, u_char * result)
{
	CdlLOC* cd = (CdlLOC*)param;

	CD_com = com;

	if (openFile == NULL)
	{
		return 0;
	}

	switch (com)
	{
	case CdlSetloc:
		fseek(openFile, CdPosToInt(cd)*sectorSize, SEEK_SET);
		break;
	case CdlReadS:
	{
		unsigned int filePos = ftell(openFile);
		CdlLOC currentLoc;
		CdIntToPos(filePos, &currentLoc);
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		currentSector = CdPosToInt(cd);
		if (cd->sector != currentLoc.sector)
		{
			return 1;
		}
		break;
	}
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdControlB(u_char com, u_char* param, u_char* result)
{
	CD_com = com;

	switch (com)
	{
	case CdlSetloc:
	{
		CdlLOC* cd = (CdlLOC*)param;
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		readMode = RM_DATA;
		break;
	}
	case CdlSetfilter:
	{
		CdlFILTER* cdf = (CdlFILTER*)param;
		//TODO Set channel
		break;
	}
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdControlF(u_char com, u_char * param)
{
	CD_com = com;

	switch (com)
	{
	case CdlSetloc:
	{
		CdlLOC* cd = (CdlLOC*)param;
		fseek(openFile, CdPosToInt(cd) * sectorSize, SEEK_SET);
		break;
	}
	case CdlSetfilter:
	{
		CdlFILTER* cdf = (CdlFILTER*)param;
		//TODO Set channel
		break;
	}
	case CdlGetlocP:
		readMode = RM_XA_AUDIO;
		break;
	default:
		eprinterr("Unhandled command 0x%02X!\n", com);
		break;
	}

	return 0;
}

int CdPosToInt(CdlLOC* p)
{
	return (75 * (60 * DECODE_BCD(p->minute) + DECODE_BCD(p->second))) + DECODE_BCD(p->sector) - 150;
}

int CdRead(int sectors, u_long* buf, int mode)
{
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		if (comQueue[i].processed == 1)
		{
			comQueue[i].mode = CdlReadS;///@TODO really mode
			comQueue[i].p = (unsigned char*)buf;
			comQueue[i].processed = 0;
			comQueue[i].count = sectors;
			break;
		}
	}
	return 0;
}

int CdReadSync(int mode, u_char* result)
{
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		if (comQueue[i].processed == 0)
		{
			if (readMode == RM_DATA)
			{
				struct Sector sector;
				fread(&sector, sizeof(struct Sector), 1, openFile);

				memcpy(comQueue[i].p, &sector.data[0], sizeof(sector.data));
				comQueue[i].p += sizeof(sector.data);
			}
			else if (readMode == RM_XA_AUDIO)
			{
				struct AudioSector sector;
				fread(&sector, sizeof(struct AudioSector), 1, openFile);

				memcpy(comQueue[i].p, &sector.data[0], sizeof(sector.data));
				comQueue[i].p += sizeof(sector.data);
			}
			else
			{
				assert(FALSE);
			}

			if (--comQueue[i].count == 0)
			{
				comQueue[i].processed = 1;
				break;
			}

			return 1;
		}
	}
	return 0;
}

int CdSetDebug(int level)
{
	int lastLevel = CD_Debug;
	CD_Debug = level;
	return lastLevel;
}

int CdSync(int mode, u_char * result)
{
	CdlLOC* loc = (CdlLOC*)result;
	switch (mode)
	{
	case 0:
		UNIMPLEMENTED();
		assert(FALSE);
		break;
	case 1:

		switch (CdLastCom())
		{
		case CdlGetlocP:
			CdlLOC locP;
			CdIntToPos(currentSector+=20, &locP);
			result[0] = currentTrack;
			result[1] = 1;//index, usually 1
			result[2] = locP.minute;
			result[3] = locP.second;
			result[4] = locP.sector;
			result[5] = locP.minute + ENCODE_BCD(numFrames);
			result[6] = locP.second + ENCODE_BCD(numFrames);
			result[7] = locP.sector + ENCODE_BCD(numFrames);

			//Dirty, for now read the audio data
			if (readMode == RM_XA_AUDIO)
			{
				char xaAudioData[2336];
				CdRead(1, (unsigned long*)&xaAudioData[0], CdlReadS);
				CdReadSync(CdlReadS, NULL);

				//Sector should be read now
				xaAudioData[0] = 0;
			}

			break;
		}
		return CdlComplete;
		break;
	}

	return 0;
}

int ParseCueSheet()
{
	char* binFileName = NULL;
	openFile = fopen(DISC_IMAGE_FILENAME, "rb");

	if (openFile == NULL)
	{
		eprinterr("Failed to open disc image file! %s\n", DISC_IMAGE_FILENAME);
		return 0;
	}

	fseek(openFile, 0, SEEK_END);
	unsigned int cueSheetFileLength = ftell(openFile);
	char* cueSheet = (char*)malloc(cueSheetFileLength);
	fseek(openFile, 0, SEEK_SET);
	fread(cueSheet, cueSheetFileLength, 1, openFile);

	//Null terminated
	char* string = &cueSheet[0];
	if (!strncmp(string, "FILE", 4))
	{
		//Read the binary name since it's a file
		string += 5;
		if (isspace(string[0]))
		{
			string++;
		}

		//Get file name length
		char* afterFileName = string;
		char fileNameLength = 0;
		//While
		while (!isspace(afterFileName[0]))
		{
			afterFileName++;
			fileNameLength++;
		}

		if (string[0] == '"')
		{
			string[fileNameLength - 1] = 0;
			string++;
		}

		binFileName = string;
		string = afterFileName;

		if (isspace(string[0]))
			string++;

		/* Get Type of BIN file */
		assert(!strncmp(string, "BINARY", 6));
		string += 6;

		while (isspace(string[0]))
			string++;

		/* Get Track of BIN file */
		assert(!strncmp(string, "TRACK", 5));
		string += 5;

		while (isspace(string[0]))
			string++;

		currentTrack = atoi(string);

		string += 2;

		while (isspace(string[0]))
			string++;

		assert(!strncmp(string, "MODE1", 5));
		string += 5;

		assert(string[0] == '/');
		string++;

		sectorSize = atoi(string);

		assert(sectorSize == 2352);

		fclose(openFile);
		openFile = fopen(binFileName, "rb");
		fseek(openFile, 0, SEEK_END);
		unsigned int binFileLength = ftell(openFile);
		numFrames = binFileLength / sectorSize;
		assert(numFrames != 0);
		fseek(openFile, 0, SEEK_SET);
		free(cueSheet);
	}

	return 1;
}

int CdInit(void)
{
	currentSector = 0;

	//Read the cue sheet and obtain properties from it.
	if (!ParseCueSheet())
	{
		eprinterr("Failed to read cue sheet!");
		return 0;
	}

	SDL_memset(&comQueue, 0, sizeof(comQueue));
	for (int i = 0; i < COMMAND_QUEUE_SIZE; i++)
	{
		comQueue[i].processed = 1;
	}

	return 1;
}

int CdLastCom(void)
{
	return CD_com;
}
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#if FMI4CPP_DEBUG_LOGGING_ENABLED
#include <iostream>
#endif

#include <fmi4cpp/fmi2/import/FmuResource.hpp>

#include "../../tools/os_util.hpp"

using namespace fmi4cpp::fmi2;

FmuResource::FmuResource(fs::path &path): path_(path){}

const std::string FmuResource::getModelDescriptionPath() const {
    return path_.string() + "/modelDescription.xml";
}

const std::string FmuResource::getResourcePath() const {
    return "file:/" + path_.string() + "/resources/" + getOs() + "/" + getLibExt();
}

const std::string FmuResource::getAbsoluteLibraryPath(const std::string &modelIdentifier) const {
    return path_.string() + "/binaries/" + getOs() + "/" + modelIdentifier + getLibExt();
}

FmuResource::~FmuResource() {

    std::error_code success {};
    fs::remove_all(path_, success);
#if FMI4CPP_DEBUG_LOGGING_ENABLED
    if (!success) {
        std::cout << "Deleted temporal folder '" << path_.string() << "'" <<  std::endl;
    } else {
        std::cout << "Unable to delete temporal folder '" <<  path_.string() << "'" <<  std::endl;
    }
#endif

}<commit_msg>error should be printed with cerr<commit_after>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#if FMI4CPP_DEBUG_LOGGING_ENABLED
#include <iostream>
#endif

#include <fmi4cpp/fmi2/import/FmuResource.hpp>

#include "../../tools/os_util.hpp"

using namespace fmi4cpp::fmi2;

FmuResource::FmuResource(fs::path &path): path_(path){}

const std::string FmuResource::getModelDescriptionPath() const {
    return path_.string() + "/modelDescription.xml";
}

const std::string FmuResource::getResourcePath() const {
    return "file:/" + path_.string() + "/resources/" + getOs() + "/" + getLibExt();
}

const std::string FmuResource::getAbsoluteLibraryPath(const std::string &modelIdentifier) const {
    return path_.string() + "/binaries/" + getOs() + "/" + modelIdentifier + getLibExt();
}

FmuResource::~FmuResource() {

    std::error_code success {};
    fs::remove_all(path_, success);
#if FMI4CPP_DEBUG_LOGGING_ENABLED
    if (!success) {
        std::cout << "Deleted temporal folder '" << path_.string() << "'" <<  std::endl;
    } else {
        std::cerr << "Unable to delete temporal folder '" <<  path_.string() << "'" <<  std::endl;
    }
#endif

}<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <fmi4cpp/logger.hpp>
#include <fmi4cpp/fmi2/import/FmuResource.hpp>

#include "../../tools/os_util.hpp"

using namespace fmi4cpp::fmi2;

FmuResource::FmuResource(fs::path &path): path_(path){}

const std::string FmuResource::getModelDescriptionPath() const {
    return path_.string() + "/modelDescription.xml";
}

const std::string FmuResource::getResourcePath() const {
    return "file:///" + path_.string() + "/resources/" + getOs() + "/" + getLibExt();
}

const std::string FmuResource::getAbsoluteLibraryPath(const std::string &modelIdentifier) const {
    return path_.string() + "/binaries/" + getOs() + "/" + modelIdentifier + getLibExt();
}

FmuResource::~FmuResource() {

    std::error_code success {};
    fs::remove_all(path_, success);

    if (!success) {
        fmi4cpp::logger::debug("Deleted temporal folder '{}", path_.string());
    } else {
        fmi4cpp::logger::debug("Unable to delete temporal folder '{}", path_.string());
    }

}<commit_msg>add missing character<commit_after>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <fmi4cpp/logger.hpp>
#include <fmi4cpp/fmi2/import/FmuResource.hpp>

#include "../../tools/os_util.hpp"

using namespace fmi4cpp::fmi2;

FmuResource::FmuResource(fs::path &path): path_(path){}

const std::string FmuResource::getModelDescriptionPath() const {
    return path_.string() + "/modelDescription.xml";
}

const std::string FmuResource::getResourcePath() const {
    return "file:///" + path_.string() + "/resources/" + getOs() + "/" + getLibExt();
}

const std::string FmuResource::getAbsoluteLibraryPath(const std::string &modelIdentifier) const {
    return path_.string() + "/binaries/" + getOs() + "/" + modelIdentifier + getLibExt();
}

FmuResource::~FmuResource() {

    std::error_code success {};
    fs::remove_all(path_, success);

    if (!success) {
        fmi4cpp::logger::debug("Deleted temporal folder '{}'", path_.string());
    } else {
        fmi4cpp::logger::debug("Unable to delete temporal folder '{}'", path_.string());
    }

}<|endoftext|>