<commit_before>/*******************************
Copyright (c) 2016-2021 Grégoire Angerand

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 "EngineView.h"
#include "CameraController.h"

#include <editor/widgets/AssetSelector.h>
#include <editor/context/EditorContext.h>
#include <editor/context/Picker.h>

#include <yave/framegraph/FrameGraph.h>
#include <yave/framegraph/FrameGraphPass.h>
#include <yave/framegraph/FrameGraphFrameResources.h>
#include <yave/framegraph/FrameGraphResourcePool.h>
#include <yave/graphics/commands/CmdBufferRecorder.h>
#include <yave/graphics/device/DeviceResources.h>

#include <yave/renderer/DefaultRenderer.h>
#include <yave/utils/color.h>

#include <external/imgui/yave_imgui.h>

namespace editor {

static bool is_clicked() {
    return ImGui::IsMouseClicked(0) || ImGui::IsMouseClicked(1) || ImGui::IsMouseClicked(2);
}

static auto standard_resolutions() {
    static std::array<std::pair<const char*, math::Vec2ui>, 3> resolutions = {{
        {"1080p", {1920, 1080}},
        {"1440p", {2560, 1440}},
        {"4k",    {3840, 2160}},
    }};

    return resolutions;
}

EngineView::EngineView(ContextPtr cptr) :
        Widget(ICON_FA_DESKTOP " Engine View", ImGuiWindowFlags_MenuBar),
        ContextLinked(cptr),
        _resource_pool(std::make_shared<FrameGraphResourcePool>(device())),
        _scene_view(&context()->world()),
        _camera_controller(std::make_unique<HoudiniCameraController>(context())),
        _gizmo(context(), &_scene_view) {
}

EngineView::~EngineView() {
    context()->remove_scene_view(&_scene_view);
}

void EngineView::before_paint() {
    ImGui::PushStyleColor(ImGuiCol_MenuBarBg, math::Vec4(0.0f));
    ImGui::PushStyleColor(ImGuiCol_Border, math::Vec4(0.0f));
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, math::Vec2(2.0f, 0.0f));
}

void EngineView::after_paint() {
    ImGui::PopStyleColor(2);
    // poped during menu rendering
    // ImGui::PopStyleVar(1);
}

void EngineView::draw(CmdBufferRecorder& recorder) {
    TextureView* output = nullptr;
    FrameGraph graph(_resource_pool);

    const math::Vec2ui output_size = _resolution < 0
        ? content_size()
        : standard_resolutions()[_resolution].second;

    const EditorRenderer renderer = EditorRenderer::create(context(), graph, _scene_view, output_size, _settings);

    {
        const Texture& white = *device_resources(graph.device())[DeviceResources::WhiteTexture];

        FrameGraphPassBuilder builder = graph.add_pass("ImGui texture pass");

        const auto output_image = builder.declare_image(VK_FORMAT_R8G8B8A8_UNORM, output_size);
        const auto buffer = builder.declare_typed_buffer<u32>(1);

        const auto gbuffer = renderer.renderer.gbuffer;
        builder.add_image_input_usage(output_image, ImageUsage::TextureBit);
        builder.add_color_output(output_image);
        builder.add_uniform_input(buffer);
        builder.add_uniform_input(renderer.color, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.depth, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.color, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.normal, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input_with_default(renderer.renderer.ssao.ao, Descriptor(white), 0, PipelineStage::FragmentBit);
        builder.map_update(buffer);
        builder.set_render_func([=, index = u32(_view), &output](CmdBufferRecorder& recorder, const FrameGraphPass* self) {
                auto out = std::make_unique<TextureView>(self->resources().image<ImageUsage::TextureBit>(output_image));
                output = out.get();
                recorder.keep_alive(std::move(out));

                TypedMapping<u32> mapping = self->resources().mapped_buffer(buffer);
                mapping[0] = index;

                auto render_pass = recorder.bind_framebuffer(self->framebuffer());
                const auto* material = context()->resources()[EditorResources::EngineViewMaterialTemplate];
                render_pass.bind_material(material, {self->descriptor_sets()[0]});

                VkDrawIndirectCommand command = {};
                {
                    command.vertexCount = 6;
                    command.instanceCount = 1;
                }
                render_pass.draw(command);
            });
    }

    if(!_disable_render) {
        std::move(graph).render(recorder);
    }

    if(output) {
        ImGui::GetWindowDrawList()->AddImage(output,
            position() + math::Vec2(ImGui::GetWindowContentRegionMin()),
            position() + math::Vec2(ImGui::GetWindowContentRegionMax()));
    }

}

void EngineView::paint(CmdBufferRecorder& recorder) {
    y_profile();

    update_proj();

    draw_menu_bar();
    draw(recorder);
    _gizmo.draw();

    update();
}

void EngineView::update_proj() {
    const CameraSettings& settings = context()->settings().camera();
    math::Vec2ui viewport_size = content_size();

    const float fov = math::to_rad(settings.fov);
    const auto proj = math::perspective(fov, float(viewport_size.x()) / float(viewport_size.y()), settings.z_near);
    _scene_view.camera().set_proj(proj);
}

void EngineView::update() {
    _gizmo.set_allow_drag(true);

    const bool hovered = ImGui::IsWindowHovered() && is_mouse_inside();

    bool focussed = ImGui::IsWindowFocused();
    if(hovered && is_clicked()) {
        ImGui::SetWindowFocus();
        update_picking();
        focussed = true;
    }

    if(focussed) {
        context()->set_scene_view(&_scene_view);
    }

    if(hovered && !_gizmo.is_dragging() && _camera_controller) {
        auto& camera = _scene_view.camera();
        _camera_controller->process_generic_shortcuts(camera);
        if(focussed) {
            _camera_controller->update_camera(camera, content_size());
        }
    }
}

void EngineView::update_picking() {
    const math::Vec2ui viewport_size = content_size();
    const math::Vec2 offset = ImGui::GetWindowPos();
    const math::Vec2 mouse = ImGui::GetIO().MousePos;
    const math::Vec2 uv = (mouse - offset - math::Vec2(ImGui::GetWindowContentRegionMin())) / math::Vec2(viewport_size);

    if(uv.x() < 0.0f || uv.y() < 0.0f ||
       uv.x() > 1.0f || uv.y() > 1.0f) {

        return;
    }

    const PickingResult picking_data = Picker(context()).pick_sync(_scene_view, uv, viewport_size);
    if(_camera_controller && _camera_controller->viewport_clicked(picking_data)) {
        // event has been eaten by the camera controller, don't proceed further
        _gizmo.set_allow_drag(false);
        return;
    }

    if(ImGui::IsMouseClicked(0)) {
        if(!_gizmo.is_dragging()) {
            ecs::EntityId picked_id = picking_data.hit() ? context()->world().id_from_index(picking_data.entity_index) : ecs::EntityId();
            context()->selection().set_selected(picked_id);
        }
    }
}

void EngineView::draw_settings_menu() {
     if(ImGui::BeginMenu("Tone mapping")) {
        ToneMappingSettings& settings = _settings.renderer_settings.tone_mapping;
        ImGui::MenuItem("Auto exposure", nullptr, &settings.auto_exposure);

        // https://docs.unrealengine.com/en-US/Engine/Rendering/PostProcessEffects/AutomaticExposure/index.html
        float ev = exposure_to_EV100(settings.exposure);
        if(ImGui::SliderFloat("EV100", &ev, -10.0f, 10.0f)) {
            settings.exposure = EV100_to_exposure(ev);
        }

        if(ImGui::IsItemActive() || ImGui::IsItemHovered()) {
            ImGui::SetTooltip("Exposure scale = %.3f", settings.exposure);
        }

        const char* tone_mappers[] = {"ACES", "Uncharted 2", "Reinhard", "None"};
        if(ImGui::BeginCombo("Tone mapper", tone_mappers[usize(settings.tone_mapper)])) {
            for(usize i = 0; i != sizeof(tone_mappers) / sizeof(tone_mappers[0]); ++i) {
                const bool selected = usize(settings.tone_mapper) == i;
                if(ImGui::Selectable(tone_mappers[i], selected)) {
                    settings.tone_mapper = ToneMappingSettings::ToneMapper(i);
                }
            }
            ImGui::EndCombo();
        }
        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("SSAO")) {
        SSAOSettings& settings = _settings.renderer_settings.ssao;

        bool enabled = settings.method != SSAOSettings::SSAOMethod::None;
        ImGui::Checkbox("Enabled", &enabled);

        int levels = settings.level_count;

        ImGui::SliderInt("Levels", &levels, 2, 8);
        ImGui::SliderFloat("Blur tolerance", &settings.blur_tolerance, 1.0f, 8.0f);
        ImGui::SliderFloat("Upsample tolerance", &settings.upsample_tolerance, 1.0f, 12.0f);
        ImGui::SliderFloat("Noise filter", &settings.noise_filter_tolerance, 0.0f, 8.0f);

        settings.level_count = levels;
        settings.method = enabled ? SSAOSettings::SSAOMethod::MiniEngine : SSAOSettings::SSAOMethod::None;

        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("Bloom")) {
        BloomSettings& settings = _settings.renderer_settings.bloom;

        ImGui::SliderFloat("Power", &settings.bloom_power, 0.0f, 100.0f, "%.3f", 10.0f);
        ImGui::SliderFloat("Threshold", &settings.bloom_threshold, 0.0f, 1.0f);

        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("Lighting")) {
        LightingSettings& settings = _settings.renderer_settings.lighting;

        ImGui::Checkbox("Use compute", &settings.use_compute_for_locals);

        ImGui::EndMenu();
    }
}

void EngineView::draw_menu_bar() {
    if(ImGui::BeginMenuBar()) {
        ImGui::PopStyleVar(1);

        if(ImGui::BeginMenu("Render")) {
            ImGui::MenuItem("Editor entities", nullptr, &_settings.show_editor_entities);

            ImGui::Separator();
            {
                const char* output_names[] = {
                        "Lit", "Albedo", "Normals", "Metallic", "Roughness", "Depth", "AO"
                    };
                for(usize i = 0; i != usize(RenderView::MaxRenderViews); ++i) {
                    bool selected = usize(_view) == i;
                    ImGui::MenuItem(output_names[i], nullptr, &selected);
                    if(selected) {
                        _view = RenderView(i);
                    }
                }
            }

            ImGui::Separator();
            ImGui::MenuItem("Disable render", nullptr, &_disable_render);

            ImGui::Separator();
            if(ImGui::BeginMenu("Rendering Settings")) {
                draw_settings_menu();
                ImGui::EndMenu();
            }

            ImGui::EndMenu();
        }

        if(ImGui::BeginMenu("Camera")) {
            if(ImGui::MenuItem("Reset camera")) {
                _scene_view.camera().set_view(Camera().view_matrix());
            }
            ImGui::EndMenu();
        }

        if(ImGui::BeginMenu("Resolution")) {
            if(ImGui::MenuItem("Viewport", "", _resolution < 0)) {
                _resolution = -1;
            }
            ImGui::Separator();

            const auto resolutions = standard_resolutions();
            for(isize i = 0; i != isize(resolutions.size()); ++i) {
                if(ImGui::MenuItem(resolutions[i].first, "", _resolution == i)) {
                    _resolution = i;
                }
            }

            ImGui::EndMenu();
        }

        draw_gizmo_tool_bar();

        if(_resolution >= 0) {
            ImGui::TextUnformatted(standard_resolutions()[_resolution].first);
        }

        ImGui::EndMenuBar();
    }
}

void EngineView::draw_gizmo_tool_bar() {
    ImGui::Separator();

    auto gizmo_mode = _gizmo.mode();
    auto gizmo_space = _gizmo.space();
    {
        if(ImGui::MenuItem(ICON_FA_ARROWS_ALT, nullptr, false, gizmo_mode != Gizmo::Translate)) {
            gizmo_mode = Gizmo::Translate;
        }
        if(ImGui::MenuItem(ICON_FA_SYNC_ALT, nullptr, false, gizmo_mode != Gizmo::Rotate)) {
            gizmo_mode = Gizmo::Rotate;
        }
    }
    {
        if(ImGui::MenuItem(ICON_FA_MOUNTAIN, nullptr, false, gizmo_space != Gizmo::World)) {
            gizmo_space = Gizmo::World;
        }
        if(ImGui::MenuItem(ICON_FA_CUBE, nullptr, false, gizmo_space != Gizmo::Local)) {
            gizmo_space = Gizmo::Local;
        }
    }

    if(is_focussed()) {
        const UiSettings& settings = context()->settings().ui();
        if(ImGui::IsKeyReleased(int(settings.change_gizmo_mode))) {
            gizmo_mode = Gizmo::Mode(!usize(gizmo_mode));
        }
        if(ImGui::IsKeyReleased(int(settings.change_gizmo_space))) {
            gizmo_space = Gizmo::Space(!usize(gizmo_space));
        }
    }
    _gizmo.set_mode(gizmo_mode);
    _gizmo.set_space(gizmo_space);
}

}

<commit_msg>Fixed crash when putting widget over engine view<commit_after>/*******************************
Copyright (c) 2016-2021 Grégoire Angerand

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 "EngineView.h"
#include "CameraController.h"

#include <editor/widgets/AssetSelector.h>
#include <editor/context/EditorContext.h>
#include <editor/context/Picker.h>

#include <yave/framegraph/FrameGraph.h>
#include <yave/framegraph/FrameGraphPass.h>
#include <yave/framegraph/FrameGraphFrameResources.h>
#include <yave/framegraph/FrameGraphResourcePool.h>
#include <yave/graphics/commands/CmdBufferRecorder.h>
#include <yave/graphics/device/DeviceResources.h>

#include <yave/renderer/DefaultRenderer.h>
#include <yave/utils/color.h>

#include <external/imgui/yave_imgui.h>

namespace editor {

static bool is_clicked() {
    return ImGui::IsMouseClicked(0) || ImGui::IsMouseClicked(1) || ImGui::IsMouseClicked(2);
}

static auto standard_resolutions() {
    static std::array<std::pair<const char*, math::Vec2ui>, 3> resolutions = {{
        {"1080p", {1920, 1080}},
        {"1440p", {2560, 1440}},
        {"4k",    {3840, 2160}},
    }};

    return resolutions;
}

EngineView::EngineView(ContextPtr cptr) :
        Widget(ICON_FA_DESKTOP " Engine View", ImGuiWindowFlags_MenuBar),
        ContextLinked(cptr),
        _resource_pool(std::make_shared<FrameGraphResourcePool>(device())),
        _scene_view(&context()->world()),
        _camera_controller(std::make_unique<HoudiniCameraController>(context())),
        _gizmo(context(), &_scene_view) {
}

EngineView::~EngineView() {
    context()->remove_scene_view(&_scene_view);
}

void EngineView::before_paint() {
    ImGui::PushStyleColor(ImGuiCol_MenuBarBg, math::Vec4(0.0f));
    ImGui::PushStyleColor(ImGuiCol_Border, math::Vec4(0.0f));
}

void EngineView::after_paint() {
    ImGui::PopStyleColor(2);
}

void EngineView::draw(CmdBufferRecorder& recorder) {
    TextureView* output = nullptr;
    FrameGraph graph(_resource_pool);

    const math::Vec2ui output_size = _resolution < 0
        ? content_size()
        : standard_resolutions()[_resolution].second;

    const EditorRenderer renderer = EditorRenderer::create(context(), graph, _scene_view, output_size, _settings);

    {
        const Texture& white = *device_resources(graph.device())[DeviceResources::WhiteTexture];

        FrameGraphPassBuilder builder = graph.add_pass("ImGui texture pass");

        const auto output_image = builder.declare_image(VK_FORMAT_R8G8B8A8_UNORM, output_size);
        const auto buffer = builder.declare_typed_buffer<u32>(1);

        const auto gbuffer = renderer.renderer.gbuffer;
        builder.add_image_input_usage(output_image, ImageUsage::TextureBit);
        builder.add_color_output(output_image);
        builder.add_uniform_input(buffer);
        builder.add_uniform_input(renderer.color, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.depth, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.color, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input(gbuffer.normal, 0, PipelineStage::FragmentBit);
        builder.add_uniform_input_with_default(renderer.renderer.ssao.ao, Descriptor(white), 0, PipelineStage::FragmentBit);
        builder.map_update(buffer);
        builder.set_render_func([=, index = u32(_view), &output](CmdBufferRecorder& recorder, const FrameGraphPass* self) {
                auto out = std::make_unique<TextureView>(self->resources().image<ImageUsage::TextureBit>(output_image));
                output = out.get();
                recorder.keep_alive(std::move(out));

                TypedMapping<u32> mapping = self->resources().mapped_buffer(buffer);
                mapping[0] = index;

                auto render_pass = recorder.bind_framebuffer(self->framebuffer());
                const auto* material = context()->resources()[EditorResources::EngineViewMaterialTemplate];
                render_pass.bind_material(material, {self->descriptor_sets()[0]});

                VkDrawIndirectCommand command = {};
                {
                    command.vertexCount = 6;
                    command.instanceCount = 1;
                }
                render_pass.draw(command);
            });
    }

    if(!_disable_render) {
        std::move(graph).render(recorder);
    }

    if(output) {
        ImGui::GetWindowDrawList()->AddImage(output,
            position() + math::Vec2(ImGui::GetWindowContentRegionMin()),
            position() + math::Vec2(ImGui::GetWindowContentRegionMax()));
    }

}

void EngineView::paint(CmdBufferRecorder& recorder) {
    y_profile();

    update_proj();

    draw_menu_bar();
    draw(recorder);
    _gizmo.draw();

    update();
}

void EngineView::update_proj() {
    const CameraSettings& settings = context()->settings().camera();
    math::Vec2ui viewport_size = content_size();

    const float fov = math::to_rad(settings.fov);
    const auto proj = math::perspective(fov, float(viewport_size.x()) / float(viewport_size.y()), settings.z_near);
    _scene_view.camera().set_proj(proj);
}

void EngineView::update() {
    _gizmo.set_allow_drag(true);

    const bool hovered = ImGui::IsWindowHovered() && is_mouse_inside();

    bool focussed = ImGui::IsWindowFocused();
    if(hovered && is_clicked()) {
        ImGui::SetWindowFocus();
        update_picking();
        focussed = true;
    }

    if(focussed) {
        context()->set_scene_view(&_scene_view);
    }

    if(hovered && !_gizmo.is_dragging() && _camera_controller) {
        auto& camera = _scene_view.camera();
        _camera_controller->process_generic_shortcuts(camera);
        if(focussed) {
            _camera_controller->update_camera(camera, content_size());
        }
    }
}

void EngineView::update_picking() {
    const math::Vec2ui viewport_size = content_size();
    const math::Vec2 offset = ImGui::GetWindowPos();
    const math::Vec2 mouse = ImGui::GetIO().MousePos;
    const math::Vec2 uv = (mouse - offset - math::Vec2(ImGui::GetWindowContentRegionMin())) / math::Vec2(viewport_size);

    if(uv.x() < 0.0f || uv.y() < 0.0f ||
       uv.x() > 1.0f || uv.y() > 1.0f) {

        return;
    }

    const PickingResult picking_data = Picker(context()).pick_sync(_scene_view, uv, viewport_size);
    if(_camera_controller && _camera_controller->viewport_clicked(picking_data)) {
        // event has been eaten by the camera controller, don't proceed further
        _gizmo.set_allow_drag(false);
        return;
    }

    if(ImGui::IsMouseClicked(0)) {
        if(!_gizmo.is_dragging()) {
            ecs::EntityId picked_id = picking_data.hit() ? context()->world().id_from_index(picking_data.entity_index) : ecs::EntityId();
            context()->selection().set_selected(picked_id);
        }
    }
}

void EngineView::draw_settings_menu() {
     if(ImGui::BeginMenu("Tone mapping")) {
        ToneMappingSettings& settings = _settings.renderer_settings.tone_mapping;
        ImGui::MenuItem("Auto exposure", nullptr, &settings.auto_exposure);

        // https://docs.unrealengine.com/en-US/Engine/Rendering/PostProcessEffects/AutomaticExposure/index.html
        float ev = exposure_to_EV100(settings.exposure);
        if(ImGui::SliderFloat("EV100", &ev, -10.0f, 10.0f)) {
            settings.exposure = EV100_to_exposure(ev);
        }

        if(ImGui::IsItemActive() || ImGui::IsItemHovered()) {
            ImGui::SetTooltip("Exposure scale = %.3f", settings.exposure);
        }

        const char* tone_mappers[] = {"ACES", "Uncharted 2", "Reinhard", "None"};
        if(ImGui::BeginCombo("Tone mapper", tone_mappers[usize(settings.tone_mapper)])) {
            for(usize i = 0; i != sizeof(tone_mappers) / sizeof(tone_mappers[0]); ++i) {
                const bool selected = usize(settings.tone_mapper) == i;
                if(ImGui::Selectable(tone_mappers[i], selected)) {
                    settings.tone_mapper = ToneMappingSettings::ToneMapper(i);
                }
            }
            ImGui::EndCombo();
        }
        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("SSAO")) {
        SSAOSettings& settings = _settings.renderer_settings.ssao;

        bool enabled = settings.method != SSAOSettings::SSAOMethod::None;
        ImGui::Checkbox("Enabled", &enabled);

        int levels = settings.level_count;

        ImGui::SliderInt("Levels", &levels, 2, 8);
        ImGui::SliderFloat("Blur tolerance", &settings.blur_tolerance, 1.0f, 8.0f);
        ImGui::SliderFloat("Upsample tolerance", &settings.upsample_tolerance, 1.0f, 12.0f);
        ImGui::SliderFloat("Noise filter", &settings.noise_filter_tolerance, 0.0f, 8.0f);

        settings.level_count = levels;
        settings.method = enabled ? SSAOSettings::SSAOMethod::MiniEngine : SSAOSettings::SSAOMethod::None;

        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("Bloom")) {
        BloomSettings& settings = _settings.renderer_settings.bloom;

        ImGui::SliderFloat("Power", &settings.bloom_power, 0.0f, 100.0f, "%.3f", 10.0f);
        ImGui::SliderFloat("Threshold", &settings.bloom_threshold, 0.0f, 1.0f);

        ImGui::EndMenu();
    }

    if(ImGui::BeginMenu("Lighting")) {
        LightingSettings& settings = _settings.renderer_settings.lighting;

        ImGui::Checkbox("Use compute", &settings.use_compute_for_locals);

        ImGui::EndMenu();
    }
}

void EngineView::draw_menu_bar() {
    if(ImGui::BeginMenuBar()) {
        if(ImGui::BeginMenu("Render")) {
            ImGui::MenuItem("Editor entities", nullptr, &_settings.show_editor_entities);

            ImGui::Separator();
            {
                const char* output_names[] = {
                        "Lit", "Albedo", "Normals", "Metallic", "Roughness", "Depth", "AO"
                    };
                for(usize i = 0; i != usize(RenderView::MaxRenderViews); ++i) {
                    bool selected = usize(_view) == i;
                    ImGui::MenuItem(output_names[i], nullptr, &selected);
                    if(selected) {
                        _view = RenderView(i);
                    }
                }
            }

            ImGui::Separator();
            ImGui::MenuItem("Disable render", nullptr, &_disable_render);

            ImGui::Separator();
            if(ImGui::BeginMenu("Rendering Settings")) {
                draw_settings_menu();
                ImGui::EndMenu();
            }

            ImGui::EndMenu();
        }

        if(ImGui::BeginMenu("Camera")) {
            if(ImGui::MenuItem("Reset camera")) {
                _scene_view.camera().set_view(Camera().view_matrix());
            }
            ImGui::EndMenu();
        }

        if(ImGui::BeginMenu("Resolution")) {
            if(ImGui::MenuItem("Viewport", "", _resolution < 0)) {
                _resolution = -1;
            }
            ImGui::Separator();

            const auto resolutions = standard_resolutions();
            for(isize i = 0; i != isize(resolutions.size()); ++i) {
                if(ImGui::MenuItem(resolutions[i].first, "", _resolution == i)) {
                    _resolution = i;
                }
            }

            ImGui::EndMenu();
        }

        draw_gizmo_tool_bar();

        if(_resolution >= 0) {
            ImGui::TextUnformatted(standard_resolutions()[_resolution].first);
        }

        ImGui::EndMenuBar();
    }
}

void EngineView::draw_gizmo_tool_bar() {
    ImGui::Separator();

    auto gizmo_mode = _gizmo.mode();
    auto gizmo_space = _gizmo.space();
    {
        if(ImGui::MenuItem(ICON_FA_ARROWS_ALT, nullptr, false, gizmo_mode != Gizmo::Translate)) {
            gizmo_mode = Gizmo::Translate;
        }
        if(ImGui::MenuItem(ICON_FA_SYNC_ALT, nullptr, false, gizmo_mode != Gizmo::Rotate)) {
            gizmo_mode = Gizmo::Rotate;
        }
    }
    {
        if(ImGui::MenuItem(ICON_FA_MOUNTAIN, nullptr, false, gizmo_space != Gizmo::World)) {
            gizmo_space = Gizmo::World;
        }
        if(ImGui::MenuItem(ICON_FA_CUBE, nullptr, false, gizmo_space != Gizmo::Local)) {
            gizmo_space = Gizmo::Local;
        }
    }

    if(is_focussed()) {
        const UiSettings& settings = context()->settings().ui();
        if(ImGui::IsKeyReleased(int(settings.change_gizmo_mode))) {
            gizmo_mode = Gizmo::Mode(!usize(gizmo_mode));
        }
        if(ImGui::IsKeyReleased(int(settings.change_gizmo_space))) {
            gizmo_space = Gizmo::Space(!usize(gizmo_space));
        }
    }
    _gizmo.set_mode(gizmo_mode);
    _gizmo.set_space(gizmo_space);
}

}

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "workbooksettings.hxx"

#include <com/sun/star/sheet/XCalculatable.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <unotools/mediadescriptor.hxx>
#include "oox/core/filterbase.hxx"
#include "oox/helper/attributelist.hxx"
#include "oox/helper/propertyset.hxx"
#include "oox/core/xmlfilterbase.hxx"
#include "oox/token/properties.hxx"
#include "biffinputstream.hxx"
#include "unitconverter.hxx"

namespace oox {
namespace xls {

// ============================================================================

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

using ::oox::core::CodecHelper;

// ============================================================================

namespace {

const sal_uInt32 BIFF12_WORKBOOKPR_DATE1904     = 0x00000001;
const sal_uInt32 BIFF12_WORKBOOKPR_STRIPEXT     = 0x00000080;

const sal_uInt16 BIFF12_CALCPR_A1               = 0x0002;
const sal_uInt16 BIFF12_CALCPR_ITERATE          = 0x0004;
const sal_uInt16 BIFF12_CALCPR_FULLPRECISION    = 0x0008;
const sal_uInt16 BIFF12_CALCPR_CALCCOMPLETED    = 0x0010;
const sal_uInt16 BIFF12_CALCPR_CALCONSAVE       = 0x0020;
const sal_uInt16 BIFF12_CALCPR_CONCURRENT       = 0x0040;
const sal_uInt16 BIFF12_CALCPR_MANUALPROC       = 0x0080;

// no predefined constants for show objects mode
const sal_Int16 API_SHOWMODE_SHOW               = 0;        /// Show drawing objects.
const sal_Int16 API_SHOWMODE_HIDE               = 1;        /// Hide drawing objects.
const sal_Int16 API_SHOWMODE_PLACEHOLDER        = 2;        /// Show placeholders for drawing objects.

} // namespace

// ============================================================================

FileSharingModel::FileSharingModel() :
    mnPasswordHash( 0 ),
    mbRecommendReadOnly( false )
{
}

// ============================================================================

WorkbookSettingsModel::WorkbookSettingsModel() :
    mnShowObjectMode( XML_all ),
    mnUpdateLinksMode( XML_userSet ),
    mnDefaultThemeVer( -1 ),
    mbDateMode1904( false ),
    mbSaveExtLinkValues( true )
{
}

void WorkbookSettingsModel::setBiffObjectMode( sal_uInt16 nObjMode )
{
    static const sal_Int32 spnObjModes[] = { XML_all, XML_placeholders, XML_none };
    mnShowObjectMode = STATIC_ARRAY_SELECT( spnObjModes, nObjMode, XML_all );
}

// ============================================================================

CalcSettingsModel::CalcSettingsModel() :
    mfIterateDelta( 0.001 ),
    mnCalcId( -1 ),
    mnRefMode( XML_A1 ),
    mnCalcMode( XML_auto ),
    mnIterateCount( 100 ),
    mnProcCount( -1 ),
    mbCalcOnSave( true ),
    mbCalcCompleted( true ),
    mbFullPrecision( true ),
    mbIterate( false ),
    mbConcurrent( true ),
    mbUseNlr( false )
{
}

// ============================================================================

WorkbookSettings::WorkbookSettings( const WorkbookHelper& rHelper ) :
    WorkbookHelper( rHelper )
{
}

void WorkbookSettings::importFileSharing( const AttributeList& rAttribs )
{
    maFileSharing.maUserName          = rAttribs.getXString( XML_userName, OUString() );
    maFileSharing.mnPasswordHash      = CodecHelper::getPasswordHash( rAttribs, XML_reservationPassword );
    maFileSharing.mbRecommendReadOnly = rAttribs.getBool( XML_readOnlyRecommended, false );
}

void WorkbookSettings::importWorkbookPr( const AttributeList& rAttribs )
{
    maBookSettings.maCodeName          = rAttribs.getString( XML_codeName, OUString() );
    maBookSettings.mnShowObjectMode    = rAttribs.getToken( XML_showObjects, XML_all );
    maBookSettings.mnUpdateLinksMode   = rAttribs.getToken( XML_updateLinks, XML_userSet );
    maBookSettings.mnDefaultThemeVer   = rAttribs.getInteger( XML_defaultThemeVersion, -1 );
    maBookSettings.mbSaveExtLinkValues = rAttribs.getBool( XML_saveExternalLinkValues, true );
    setDateMode( rAttribs.getBool( XML_date1904, false ), rAttribs.getBool( XML_dateCompatibility, true ) );
}

void WorkbookSettings::importCalcPr( const AttributeList& rAttribs )
{
    maCalcSettings.mfIterateDelta  = rAttribs.getDouble( XML_iterateDelta, 0.0001 );
    maCalcSettings.mnCalcId        = rAttribs.getInteger( XML_calcId, -1 );
    maCalcSettings.mnRefMode       = rAttribs.getToken( XML_refMode, XML_A1 );
    maCalcSettings.mnCalcMode      = rAttribs.getToken( XML_calcMode, XML_auto );
    maCalcSettings.mnIterateCount  = rAttribs.getInteger( XML_iterateCount, 100 );
    maCalcSettings.mnProcCount     = rAttribs.getInteger( XML_concurrentManualCount, -1 );
    maCalcSettings.mbCalcOnSave    = rAttribs.getBool( XML_calcOnSave, true );
    maCalcSettings.mbCalcCompleted = rAttribs.getBool( XML_calcCompleted, true );
    maCalcSettings.mbFullPrecision = rAttribs.getBool( XML_fullPrecision, true );
    maCalcSettings.mbIterate       = rAttribs.getBool( XML_iterate, false );
    maCalcSettings.mbConcurrent    = rAttribs.getBool( XML_concurrentCalc, true );
}

void WorkbookSettings::importFileSharing( SequenceInputStream& rStrm )
{
    maFileSharing.mbRecommendReadOnly = rStrm.readuInt16() != 0;
    rStrm >> maFileSharing.mnPasswordHash >> maFileSharing.maUserName;
}

void WorkbookSettings::importWorkbookPr( SequenceInputStream& rStrm )
{
    sal_uInt32 nFlags;
    rStrm >> nFlags >> maBookSettings.mnDefaultThemeVer >> maBookSettings.maCodeName;
    maBookSettings.setBiffObjectMode( extractValue< sal_uInt16 >( nFlags, 13, 2 ) );
    // set flag means: strip external link values
    maBookSettings.mbSaveExtLinkValues = !getFlag( nFlags, BIFF12_WORKBOOKPR_STRIPEXT );
    setDateMode( getFlag( nFlags, BIFF12_WORKBOOKPR_DATE1904 ) );
}

void WorkbookSettings::importCalcPr( SequenceInputStream& rStrm )
{
    sal_Int32 nCalcMode, nProcCount;
    sal_uInt16 nFlags;
    rStrm >> maCalcSettings.mnCalcId >> nCalcMode >> maCalcSettings.mnIterateCount >> maCalcSettings.mfIterateDelta >> nProcCount >> nFlags;

    static const sal_Int32 spnCalcModes[] = { XML_manual, XML_auto, XML_autoNoTable };
    maCalcSettings.mnRefMode       = getFlagValue( nFlags, BIFF12_CALCPR_A1, XML_A1, XML_R1C1 );
    maCalcSettings.mnCalcMode      = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
    maCalcSettings.mnProcCount     = getFlagValue< sal_Int32 >( nFlags, BIFF12_CALCPR_MANUALPROC, nProcCount, -1 );
    maCalcSettings.mbCalcOnSave    = getFlag( nFlags, BIFF12_CALCPR_CALCONSAVE );
    maCalcSettings.mbCalcCompleted = getFlag( nFlags, BIFF12_CALCPR_CALCCOMPLETED );
    maCalcSettings.mbFullPrecision = getFlag( nFlags, BIFF12_CALCPR_FULLPRECISION );
    maCalcSettings.mbIterate       = getFlag( nFlags, BIFF12_CALCPR_ITERATE );
    maCalcSettings.mbConcurrent    = getFlag( nFlags, BIFF12_CALCPR_CONCURRENT );
}

void WorkbookSettings::finalizeImport()
{
    // default settings
    PropertySet aPropSet( getDocument() );
    switch( getFilterType() )
    {
        case FILTER_OOXML:
        case FILTER_BIFF:
            aPropSet.setProperty( PROP_IgnoreCase,          true );     // always in Excel
            aPropSet.setProperty( PROP_RegularExpressions,  false );    // not supported in Excel
        break;
        case FILTER_UNKNOWN:
        break;
    }

    // write protection
    if( maFileSharing.mbRecommendReadOnly || (maFileSharing.mnPasswordHash != 0) ) try
    {
        getBaseFilter().getMediaDescriptor()[ "ReadOnly" ] <<= true;

        Reference< XPropertySet > xDocumentSettings( getBaseFilter().getModelFactory()->createInstance(
            "com.sun.star.document.Settings" ), UNO_QUERY_THROW );
        PropertySet aSettingsProp( xDocumentSettings );
        if( maFileSharing.mbRecommendReadOnly )
            aSettingsProp.setProperty( PROP_LoadReadonly, true );
//        if( maFileSharing.mnPasswordHash != 0 )
//            aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) );
    }
    catch( Exception& )
    {
    }

    // calculation settings
    css::util::Date aNullDate = getNullDate();

    aPropSet.setProperty( PROP_NullDate,           aNullDate );
    aPropSet.setProperty( PROP_IsIterationEnabled, maCalcSettings.mbIterate );
    aPropSet.setProperty( PROP_IterationCount,     maCalcSettings.mnIterateCount );
    aPropSet.setProperty( PROP_IterationEpsilon,   maCalcSettings.mfIterateDelta );
    aPropSet.setProperty( PROP_CalcAsShown,        !maCalcSettings.mbFullPrecision );
    aPropSet.setProperty( PROP_LookUpLabels,       maCalcSettings.mbUseNlr );

    Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY );
    if( xNumFmtsSupp.is() )
    {
        PropertySet aNumFmtProp( xNumFmtsSupp->getNumberFormatSettings() );
        aNumFmtProp.setProperty( PROP_NullDate, aNullDate );
    }

    Reference< XCalculatable > xCalculatable( getDocument(), UNO_QUERY );
    if( xCalculatable.is() )
        xCalculatable->enableAutomaticCalculation( (maCalcSettings.mnCalcMode == XML_auto) || (maCalcSettings.mnCalcMode == XML_autoNoTable) );

    // VBA code name
    aPropSet.setProperty( PROP_CodeName, maBookSettings.maCodeName );
}

sal_Int16 WorkbookSettings::getApiShowObjectMode() const
{
    switch( maBookSettings.mnShowObjectMode )
    {
        case XML_all:           return API_SHOWMODE_SHOW;
        case XML_none:          return API_SHOWMODE_HIDE;
        // #i80528# placeholders not supported anymore, but this is handled internally in Calc
        case XML_placeholders:  return API_SHOWMODE_PLACEHOLDER;
    }
    return API_SHOWMODE_SHOW;
}

css::util::Date WorkbookSettings::getNullDate() const
{
    static const css::util::Date saDate1900                 ( 30, 12, 1899 );
    static const css::util::Date saDate1904                 ( 1, 1, 1904 );
    static const css::util::Date saDateBackCompatibility1900( 31, 12, 1899 );

    if( getOoxFilter().getVersion() == oox::core::ISOIEC_29500_2008 )
    {
        if( !maBookSettings.mbDateCompatibility )
            return saDate1900;

        return maBookSettings.mbDateMode1904 ? saDate1904 :
                                               saDateBackCompatibility1900;
    }

    return maBookSettings.mbDateMode1904 ? saDate1904 : saDate1900;
}

void WorkbookSettings::setDateMode( bool bDateMode1904, bool bDateCompatibility )
{
    maBookSettings.mbDateMode1904      = bDateMode1904;
    maBookSettings.mbDateCompatibility = bDateCompatibility;

    getUnitConverter().finalizeNullDate( getNullDate() );
}

// ============================================================================

} // namespace xls
} // namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#738798 Uninitialized scalar field<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "workbooksettings.hxx"

#include <com/sun/star/sheet/XCalculatable.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <unotools/mediadescriptor.hxx>
#include "oox/core/filterbase.hxx"
#include "oox/helper/attributelist.hxx"
#include "oox/helper/propertyset.hxx"
#include "oox/core/xmlfilterbase.hxx"
#include "oox/token/properties.hxx"
#include "biffinputstream.hxx"
#include "unitconverter.hxx"

namespace oox {
namespace xls {

// ============================================================================

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

using ::oox::core::CodecHelper;

// ============================================================================

namespace {

const sal_uInt32 BIFF12_WORKBOOKPR_DATE1904     = 0x00000001;
const sal_uInt32 BIFF12_WORKBOOKPR_STRIPEXT     = 0x00000080;

const sal_uInt16 BIFF12_CALCPR_A1               = 0x0002;
const sal_uInt16 BIFF12_CALCPR_ITERATE          = 0x0004;
const sal_uInt16 BIFF12_CALCPR_FULLPRECISION    = 0x0008;
const sal_uInt16 BIFF12_CALCPR_CALCCOMPLETED    = 0x0010;
const sal_uInt16 BIFF12_CALCPR_CALCONSAVE       = 0x0020;
const sal_uInt16 BIFF12_CALCPR_CONCURRENT       = 0x0040;
const sal_uInt16 BIFF12_CALCPR_MANUALPROC       = 0x0080;

// no predefined constants for show objects mode
const sal_Int16 API_SHOWMODE_SHOW               = 0;        /// Show drawing objects.
const sal_Int16 API_SHOWMODE_HIDE               = 1;        /// Hide drawing objects.
const sal_Int16 API_SHOWMODE_PLACEHOLDER        = 2;        /// Show placeholders for drawing objects.

} // namespace

// ============================================================================

FileSharingModel::FileSharingModel() :
    mnPasswordHash( 0 ),
    mbRecommendReadOnly( false )
{
}

// ============================================================================

WorkbookSettingsModel::WorkbookSettingsModel() :
    mnShowObjectMode( XML_all ),
    mnUpdateLinksMode( XML_userSet ),
    mnDefaultThemeVer( -1 ),
    mbDateMode1904( false ),
    mbDateCompatibility ( false ),
    mbSaveExtLinkValues( true )
{
}

void WorkbookSettingsModel::setBiffObjectMode( sal_uInt16 nObjMode )
{
    static const sal_Int32 spnObjModes[] = { XML_all, XML_placeholders, XML_none };
    mnShowObjectMode = STATIC_ARRAY_SELECT( spnObjModes, nObjMode, XML_all );
}

// ============================================================================

CalcSettingsModel::CalcSettingsModel() :
    mfIterateDelta( 0.001 ),
    mnCalcId( -1 ),
    mnRefMode( XML_A1 ),
    mnCalcMode( XML_auto ),
    mnIterateCount( 100 ),
    mnProcCount( -1 ),
    mbCalcOnSave( true ),
    mbCalcCompleted( true ),
    mbFullPrecision( true ),
    mbIterate( false ),
    mbConcurrent( true ),
    mbUseNlr( false )
{
}

// ============================================================================

WorkbookSettings::WorkbookSettings( const WorkbookHelper& rHelper ) :
    WorkbookHelper( rHelper )
{
}

void WorkbookSettings::importFileSharing( const AttributeList& rAttribs )
{
    maFileSharing.maUserName          = rAttribs.getXString( XML_userName, OUString() );
    maFileSharing.mnPasswordHash      = CodecHelper::getPasswordHash( rAttribs, XML_reservationPassword );
    maFileSharing.mbRecommendReadOnly = rAttribs.getBool( XML_readOnlyRecommended, false );
}

void WorkbookSettings::importWorkbookPr( const AttributeList& rAttribs )
{
    maBookSettings.maCodeName          = rAttribs.getString( XML_codeName, OUString() );
    maBookSettings.mnShowObjectMode    = rAttribs.getToken( XML_showObjects, XML_all );
    maBookSettings.mnUpdateLinksMode   = rAttribs.getToken( XML_updateLinks, XML_userSet );
    maBookSettings.mnDefaultThemeVer   = rAttribs.getInteger( XML_defaultThemeVersion, -1 );
    maBookSettings.mbSaveExtLinkValues = rAttribs.getBool( XML_saveExternalLinkValues, true );
    setDateMode( rAttribs.getBool( XML_date1904, false ), rAttribs.getBool( XML_dateCompatibility, true ) );
}

void WorkbookSettings::importCalcPr( const AttributeList& rAttribs )
{
    maCalcSettings.mfIterateDelta  = rAttribs.getDouble( XML_iterateDelta, 0.0001 );
    maCalcSettings.mnCalcId        = rAttribs.getInteger( XML_calcId, -1 );
    maCalcSettings.mnRefMode       = rAttribs.getToken( XML_refMode, XML_A1 );
    maCalcSettings.mnCalcMode      = rAttribs.getToken( XML_calcMode, XML_auto );
    maCalcSettings.mnIterateCount  = rAttribs.getInteger( XML_iterateCount, 100 );
    maCalcSettings.mnProcCount     = rAttribs.getInteger( XML_concurrentManualCount, -1 );
    maCalcSettings.mbCalcOnSave    = rAttribs.getBool( XML_calcOnSave, true );
    maCalcSettings.mbCalcCompleted = rAttribs.getBool( XML_calcCompleted, true );
    maCalcSettings.mbFullPrecision = rAttribs.getBool( XML_fullPrecision, true );
    maCalcSettings.mbIterate       = rAttribs.getBool( XML_iterate, false );
    maCalcSettings.mbConcurrent    = rAttribs.getBool( XML_concurrentCalc, true );
}

void WorkbookSettings::importFileSharing( SequenceInputStream& rStrm )
{
    maFileSharing.mbRecommendReadOnly = rStrm.readuInt16() != 0;
    rStrm >> maFileSharing.mnPasswordHash >> maFileSharing.maUserName;
}

void WorkbookSettings::importWorkbookPr( SequenceInputStream& rStrm )
{
    sal_uInt32 nFlags;
    rStrm >> nFlags >> maBookSettings.mnDefaultThemeVer >> maBookSettings.maCodeName;
    maBookSettings.setBiffObjectMode( extractValue< sal_uInt16 >( nFlags, 13, 2 ) );
    // set flag means: strip external link values
    maBookSettings.mbSaveExtLinkValues = !getFlag( nFlags, BIFF12_WORKBOOKPR_STRIPEXT );
    setDateMode( getFlag( nFlags, BIFF12_WORKBOOKPR_DATE1904 ) );
}

void WorkbookSettings::importCalcPr( SequenceInputStream& rStrm )
{
    sal_Int32 nCalcMode, nProcCount;
    sal_uInt16 nFlags;
    rStrm >> maCalcSettings.mnCalcId >> nCalcMode >> maCalcSettings.mnIterateCount >> maCalcSettings.mfIterateDelta >> nProcCount >> nFlags;

    static const sal_Int32 spnCalcModes[] = { XML_manual, XML_auto, XML_autoNoTable };
    maCalcSettings.mnRefMode       = getFlagValue( nFlags, BIFF12_CALCPR_A1, XML_A1, XML_R1C1 );
    maCalcSettings.mnCalcMode      = STATIC_ARRAY_SELECT( spnCalcModes, nCalcMode, XML_auto );
    maCalcSettings.mnProcCount     = getFlagValue< sal_Int32 >( nFlags, BIFF12_CALCPR_MANUALPROC, nProcCount, -1 );
    maCalcSettings.mbCalcOnSave    = getFlag( nFlags, BIFF12_CALCPR_CALCONSAVE );
    maCalcSettings.mbCalcCompleted = getFlag( nFlags, BIFF12_CALCPR_CALCCOMPLETED );
    maCalcSettings.mbFullPrecision = getFlag( nFlags, BIFF12_CALCPR_FULLPRECISION );
    maCalcSettings.mbIterate       = getFlag( nFlags, BIFF12_CALCPR_ITERATE );
    maCalcSettings.mbConcurrent    = getFlag( nFlags, BIFF12_CALCPR_CONCURRENT );
}

void WorkbookSettings::finalizeImport()
{
    // default settings
    PropertySet aPropSet( getDocument() );
    switch( getFilterType() )
    {
        case FILTER_OOXML:
        case FILTER_BIFF:
            aPropSet.setProperty( PROP_IgnoreCase,          true );     // always in Excel
            aPropSet.setProperty( PROP_RegularExpressions,  false );    // not supported in Excel
        break;
        case FILTER_UNKNOWN:
        break;
    }

    // write protection
    if( maFileSharing.mbRecommendReadOnly || (maFileSharing.mnPasswordHash != 0) ) try
    {
        getBaseFilter().getMediaDescriptor()[ "ReadOnly" ] <<= true;

        Reference< XPropertySet > xDocumentSettings( getBaseFilter().getModelFactory()->createInstance(
            "com.sun.star.document.Settings" ), UNO_QUERY_THROW );
        PropertySet aSettingsProp( xDocumentSettings );
        if( maFileSharing.mbRecommendReadOnly )
            aSettingsProp.setProperty( PROP_LoadReadonly, true );
//        if( maFileSharing.mnPasswordHash != 0 )
//            aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) );
    }
    catch( Exception& )
    {
    }

    // calculation settings
    css::util::Date aNullDate = getNullDate();

    aPropSet.setProperty( PROP_NullDate,           aNullDate );
    aPropSet.setProperty( PROP_IsIterationEnabled, maCalcSettings.mbIterate );
    aPropSet.setProperty( PROP_IterationCount,     maCalcSettings.mnIterateCount );
    aPropSet.setProperty( PROP_IterationEpsilon,   maCalcSettings.mfIterateDelta );
    aPropSet.setProperty( PROP_CalcAsShown,        !maCalcSettings.mbFullPrecision );
    aPropSet.setProperty( PROP_LookUpLabels,       maCalcSettings.mbUseNlr );

    Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY );
    if( xNumFmtsSupp.is() )
    {
        PropertySet aNumFmtProp( xNumFmtsSupp->getNumberFormatSettings() );
        aNumFmtProp.setProperty( PROP_NullDate, aNullDate );
    }

    Reference< XCalculatable > xCalculatable( getDocument(), UNO_QUERY );
    if( xCalculatable.is() )
        xCalculatable->enableAutomaticCalculation( (maCalcSettings.mnCalcMode == XML_auto) || (maCalcSettings.mnCalcMode == XML_autoNoTable) );

    // VBA code name
    aPropSet.setProperty( PROP_CodeName, maBookSettings.maCodeName );
}

sal_Int16 WorkbookSettings::getApiShowObjectMode() const
{
    switch( maBookSettings.mnShowObjectMode )
    {
        case XML_all:           return API_SHOWMODE_SHOW;
        case XML_none:          return API_SHOWMODE_HIDE;
        // #i80528# placeholders not supported anymore, but this is handled internally in Calc
        case XML_placeholders:  return API_SHOWMODE_PLACEHOLDER;
    }
    return API_SHOWMODE_SHOW;
}

css::util::Date WorkbookSettings::getNullDate() const
{
    static const css::util::Date saDate1900                 ( 30, 12, 1899 );
    static const css::util::Date saDate1904                 ( 1, 1, 1904 );
    static const css::util::Date saDateBackCompatibility1900( 31, 12, 1899 );

    if( getOoxFilter().getVersion() == oox::core::ISOIEC_29500_2008 )
    {
        if( !maBookSettings.mbDateCompatibility )
            return saDate1900;

        return maBookSettings.mbDateMode1904 ? saDate1904 :
                                               saDateBackCompatibility1900;
    }

    return maBookSettings.mbDateMode1904 ? saDate1904 : saDate1900;
}

void WorkbookSettings::setDateMode( bool bDateMode1904, bool bDateCompatibility )
{
    maBookSettings.mbDateMode1904      = bDateMode1904;
    maBookSettings.mbDateCompatibility = bDateCompatibility;

    getUnitConverter().finalizeNullDate( getNullDate() );
}

// ============================================================================

} // namespace xls
} // namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.

#include "caf/message.hpp"

#include <utility>

#include "caf/actor_system.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/meta_object.hpp"
#include "caf/detail/type_id_list_builder.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_handler.hpp"
#include "caf/serializer.hpp"
#include "caf/string_algorithms.hpp"

#define GUARDED(statement)                                                     \
  if (!(statement))                                                            \
  return false

#define STOP(...)                                                              \
  do {                                                                         \
    source.emplace_error(__VA_ARGS__);                                         \
    return false;                                                              \
  } while (false)

namespace caf {

namespace {

bool load(const detail::meta_object& meta, caf::deserializer& source,
          void* obj) {
  return meta.load(source, obj);
}

bool load(const detail::meta_object& meta, caf::binary_deserializer& source,
          void* obj) {
  return meta.load_binary(source, obj);
}

template <class Deserializer>
bool load_data(Deserializer& source, message::data_ptr& data) {
  // For machine-to-machine data formats, we prefix the type information.
  if (!source.has_human_readable_format()) {
    GUARDED(source.begin_object(type_id_v<message>, "message"));
    GUARDED(source.begin_field("types"));
    size_t msg_size = 0;
    GUARDED(source.begin_sequence(msg_size));
    if (msg_size > std::numeric_limits<uint16_t>::max() - 1)
      STOP(sec::invalid_argument, "too many types for message");
    if (msg_size == 0) {
      data.reset();
      return source.end_sequence()           //
             && source.end_field()           //
             && source.begin_field("values") //
             && source.end_field()           //
             && source.end_object();
    }
    detail::type_id_list_builder ids;
    ids.reserve(msg_size);
    for (size_t i = 0; i < msg_size; ++i) {
      type_id_t id = 0;
      GUARDED(source.value(id));
      ids.push_back(id);
    }
    GUARDED(source.end_sequence());
    CAF_ASSERT(ids.size() == msg_size);
    size_t data_size = 0;
    for (auto id : ids) {
      if (auto meta_obj = detail::global_meta_object(id))
        data_size += meta_obj->padded_size;
      else
        STOP(sec::unknown_type);
    }
    intrusive_ptr<detail::message_data> ptr;
    if (auto vptr = malloc(sizeof(detail::message_data) + data_size)) {
      // We don't need to worry about exceptions here: the message_data
      // constructor as well as `move_to_list` are `noexcept`.
      ptr.reset(new (vptr) detail::message_data(ids.move_to_list()), false);
    } else {
      STOP(sec::runtime_error, "unable to allocate memory");
    }
    auto pos = ptr->storage();
    auto types = ptr->types();
    auto gmos = detail::global_meta_objects();
    GUARDED(source.begin_field("values"));
    GUARDED(source.begin_tuple(msg_size));
    for (size_t i = 0; i < msg_size; ++i) {
      auto& meta = gmos[types[i]];
      meta.default_construct(pos);
      ptr->inc_constructed_elements();
      if (!load(meta, source, pos))
        return false;
      pos += meta.padded_size;
    }
    data.reset(ptr.release(), false);
    return source.end_tuple() && source.end_field() && source.end_object();
  }
  // For human-readable data formats, we serialize messages as a single list of
  // dynamically-typed objects. This is more expensive, because we first need
  // the full type information before we can allocate the storage. Hence, we
  // must deserialize each element into a separate memory block first and then
  // move them to their final destination later.
  struct object_ptr {
    void* obj;
    const detail::meta_object* meta;
    object_ptr(void* obj, const detail::meta_object* meta) noexcept
      : obj(obj), meta(meta) {
      // nop
    }
    object_ptr(object_ptr&& other) noexcept : obj(nullptr), meta(nullptr) {
      using std::swap;
      swap(obj, other.obj);
      swap(meta, other.meta);
    }
    object_ptr& operator=(object_ptr&& other) noexcept {
      if (this != &other) {
        if (obj) {
          meta->destroy(obj);
          free(obj);
          obj = nullptr;
          meta = nullptr;
        }
        using std::swap;
        swap(obj, other.obj);
        swap(meta, other.meta);
      }
      return *this;
    }
    ~object_ptr() noexcept {
      if (obj) {
        meta->destroy(obj);
        free(obj);
      }
    }
  };
  struct free_t {
    void operator()(void* ptr) const noexcept {
      return free(ptr);
    }
  };
  using unique_void_ptr = std::unique_ptr<void, free_t>;
  auto msg_size = size_t{0};
  std::vector<object_ptr> objects;
  GUARDED(source.begin_sequence(msg_size));
  if (msg_size > 0) {
    // Deserialize message elements individually.
    detail::type_id_list_builder ids;
    objects.reserve(msg_size);
    auto data_size = size_t{0};
    for (size_t i = 0; i < msg_size; ++i) {
      auto type = type_id_t{0};
      GUARDED(source.fetch_next_object_type(type));
      if (auto meta_obj = detail::global_meta_object(type)) {
        ids.push_back(type);
        auto obj_size = meta_obj->padded_size;
        data_size += obj_size;
        unique_void_ptr vptr{malloc(obj_size)};
        if (vptr == nullptr)
          STOP(sec::runtime_error, "unable to allocate memory");
        meta_obj->default_construct(vptr.get());
        objects.emplace_back(vptr.release(), meta_obj);
        if (!load(*meta_obj, source, objects.back().obj))
          return false;
      } else {
        STOP(sec::unknown_type);
      }
    }
    GUARDED(source.end_sequence());
    // Merge elements into a single message data object.
    intrusive_ptr<detail::message_data> ptr;
    if (auto vptr = malloc(sizeof(detail::message_data) + data_size)) {
      // We don't need to worry about exceptions here: the message_data
      // constructor as well as `move_to_list` are `noexcept`.
      ptr.reset(new (vptr) detail::message_data(ids.move_to_list()), false);
    } else {
      STOP(sec::runtime_error, "unable to allocate memory");
    }
    auto pos = ptr->storage();
    for (auto& x : objects) {
      // TODO: avoid extra copy by adding move_construct to meta objects
      x.meta->copy_construct(pos, x.obj);
      ptr->inc_constructed_elements();
      pos += x.meta->padded_size;
    }
    data.reset(ptr.release(), false);
    return true;
  } else {
    data.reset();
    return source.end_sequence();
  }
}

} // namespace

bool message::load(deserializer& source) {
  return load_data(source, data_);
}

bool message::load(binary_deserializer& source) {
  return load_data(source, data_);
}

namespace {

bool save(const detail::meta_object& meta, caf::serializer& sink,
          const void* obj) {
  return meta.save(sink, obj);
}

bool save(const detail::meta_object& meta, caf::binary_serializer& sink,
          const void* obj) {
  return meta.save_binary(sink, obj);
}

template <class Serializer>
typename Serializer::result_type
save_data(Serializer& sink, const message::data_ptr& data) {
  auto gmos = detail::global_meta_objects();
  // For machine-to-machine data formats, we prefix the type information.
  if (!sink.has_human_readable_format()) {
    if (data == nullptr) {
      // Short-circuit empty tuples.
      return sink.begin_object(type_id_v<message>, "message") //
             && sink.begin_field("types")                     //
             && sink.begin_sequence(0)                        //
             && sink.end_sequence()                           //
             && sink.end_field()                              //
             && sink.begin_field("values")                    //
             && sink.begin_tuple(0)                           //
             && sink.end_tuple()                              //
             && sink.end_field()                              //
             && sink.end_object();
    }
    GUARDED(sink.begin_object(type_id_v<message>, "message"));
    auto type_ids = data->types();
    // Write type information.
    GUARDED(sink.begin_field("types") && sink.begin_sequence(type_ids.size()));
    for (auto id : type_ids)
      GUARDED(sink.value(id));
    GUARDED(sink.end_sequence() && sink.end_field());
    // Write elements.
    auto storage = data->storage();
    GUARDED(sink.begin_field("values") && sink.begin_tuple(type_ids.size()));
    for (auto id : type_ids) {
      auto& meta = gmos[id];
      GUARDED(save(meta, sink, storage));
      storage += meta.padded_size;
    }
    return sink.end_tuple() && sink.end_field() && sink.end_object();
  }
  // For human-readable data formats, we serialize messages as a single list of
  // dynamically-typed objects.
  if (data == nullptr) {
    // Short-circuit empty tuples.
    return sink.begin_sequence(0) && sink.end_sequence();
  }
  auto type_ids = data->types();
  GUARDED(sink.begin_sequence(type_ids.size()));
  auto storage = data->storage();
  for (auto id : type_ids) {
    auto& meta = gmos[id];
    GUARDED(save(meta, sink, storage));
    storage += meta.padded_size;
  }
  return sink.end_sequence();
}

} // namespace

bool message::save(serializer& sink) const {
  return save_data(sink, data_);
}

bool message::save(binary_serializer& sink) const {
  return save_data(sink, data_);
}

// -- related non-members ------------------------------------------------------

std::string to_string(const message& msg) {
  if (msg.empty())
    return "message()";
  std::string result;
  result += "message(";
  auto types = msg.types();
  if (!types.empty()) {
    auto ptr = msg.cdata().storage();
    auto meta = detail::global_meta_object(types[0]);
    CAF_ASSERT(meta != nullptr);
    meta->stringify(result, ptr);
    ptr += meta->padded_size;
    for (size_t index = 1; index < types.size(); ++index) {
      result += ", ";
      meta = detail::global_meta_object(types[index]);
      CAF_ASSERT(meta != nullptr);
      meta->stringify(result, ptr);
      ptr += meta->padded_size;
    }
  }
  result += ')';
  return result;
}

} // namespace caf
<commit_msg>Fix sign-compare warning on GCC<commit_after>// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.

#include "caf/message.hpp"

#include <utility>

#include "caf/actor_system.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/meta_object.hpp"
#include "caf/detail/type_id_list_builder.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_handler.hpp"
#include "caf/serializer.hpp"
#include "caf/string_algorithms.hpp"

#define GUARDED(statement)                                                     \
  if (!(statement))                                                            \
  return false

#define STOP(...)                                                              \
  do {                                                                         \
    source.emplace_error(__VA_ARGS__);                                         \
    return false;                                                              \
  } while (false)

namespace caf {

namespace {

bool load(const detail::meta_object& meta, caf::deserializer& source,
          void* obj) {
  return meta.load(source, obj);
}

bool load(const detail::meta_object& meta, caf::binary_deserializer& source,
          void* obj) {
  return meta.load_binary(source, obj);
}

template <class Deserializer>
bool load_data(Deserializer& source, message::data_ptr& data) {
  // For machine-to-machine data formats, we prefix the type information.
  if (!source.has_human_readable_format()) {
    GUARDED(source.begin_object(type_id_v<message>, "message"));
    GUARDED(source.begin_field("types"));
    size_t msg_size = 0;
    GUARDED(source.begin_sequence(msg_size));
    using uint16_limits = std::numeric_limits<uint16_t>;
    if (msg_size > static_cast<size_t>(uint16_limits::max() - 1))
      STOP(sec::invalid_argument, "too many types for message");
    if (msg_size == 0) {
      data.reset();
      return source.end_sequence()           //
             && source.end_field()           //
             && source.begin_field("values") //
             && source.end_field()           //
             && source.end_object();
    }
    detail::type_id_list_builder ids;
    ids.reserve(msg_size);
    for (size_t i = 0; i < msg_size; ++i) {
      type_id_t id = 0;
      GUARDED(source.value(id));
      ids.push_back(id);
    }
    GUARDED(source.end_sequence());
    CAF_ASSERT(ids.size() == msg_size);
    size_t data_size = 0;
    for (auto id : ids) {
      if (auto meta_obj = detail::global_meta_object(id))
        data_size += meta_obj->padded_size;
      else
        STOP(sec::unknown_type);
    }
    intrusive_ptr<detail::message_data> ptr;
    if (auto vptr = malloc(sizeof(detail::message_data) + data_size)) {
      // We don't need to worry about exceptions here: the message_data
      // constructor as well as `move_to_list` are `noexcept`.
      ptr.reset(new (vptr) detail::message_data(ids.move_to_list()), false);
    } else {
      STOP(sec::runtime_error, "unable to allocate memory");
    }
    auto pos = ptr->storage();
    auto types = ptr->types();
    auto gmos = detail::global_meta_objects();
    GUARDED(source.begin_field("values"));
    GUARDED(source.begin_tuple(msg_size));
    for (size_t i = 0; i < msg_size; ++i) {
      auto& meta = gmos[types[i]];
      meta.default_construct(pos);
      ptr->inc_constructed_elements();
      if (!load(meta, source, pos))
        return false;
      pos += meta.padded_size;
    }
    data.reset(ptr.release(), false);
    return source.end_tuple() && source.end_field() && source.end_object();
  }
  // For human-readable data formats, we serialize messages as a single list of
  // dynamically-typed objects. This is more expensive, because we first need
  // the full type information before we can allocate the storage. Hence, we
  // must deserialize each element into a separate memory block first and then
  // move them to their final destination later.
  struct object_ptr {
    void* obj;
    const detail::meta_object* meta;
    object_ptr(void* obj, const detail::meta_object* meta) noexcept
      : obj(obj), meta(meta) {
      // nop
    }
    object_ptr(object_ptr&& other) noexcept : obj(nullptr), meta(nullptr) {
      using std::swap;
      swap(obj, other.obj);
      swap(meta, other.meta);
    }
    object_ptr& operator=(object_ptr&& other) noexcept {
      if (this != &other) {
        if (obj) {
          meta->destroy(obj);
          free(obj);
          obj = nullptr;
          meta = nullptr;
        }
        using std::swap;
        swap(obj, other.obj);
        swap(meta, other.meta);
      }
      return *this;
    }
    ~object_ptr() noexcept {
      if (obj) {
        meta->destroy(obj);
        free(obj);
      }
    }
  };
  struct free_t {
    void operator()(void* ptr) const noexcept {
      return free(ptr);
    }
  };
  using unique_void_ptr = std::unique_ptr<void, free_t>;
  auto msg_size = size_t{0};
  std::vector<object_ptr> objects;
  GUARDED(source.begin_sequence(msg_size));
  if (msg_size > 0) {
    // Deserialize message elements individually.
    detail::type_id_list_builder ids;
    objects.reserve(msg_size);
    auto data_size = size_t{0};
    for (size_t i = 0; i < msg_size; ++i) {
      auto type = type_id_t{0};
      GUARDED(source.fetch_next_object_type(type));
      if (auto meta_obj = detail::global_meta_object(type)) {
        ids.push_back(type);
        auto obj_size = meta_obj->padded_size;
        data_size += obj_size;
        unique_void_ptr vptr{malloc(obj_size)};
        if (vptr == nullptr)
          STOP(sec::runtime_error, "unable to allocate memory");
        meta_obj->default_construct(vptr.get());
        objects.emplace_back(vptr.release(), meta_obj);
        if (!load(*meta_obj, source, objects.back().obj))
          return false;
      } else {
        STOP(sec::unknown_type);
      }
    }
    GUARDED(source.end_sequence());
    // Merge elements into a single message data object.
    intrusive_ptr<detail::message_data> ptr;
    if (auto vptr = malloc(sizeof(detail::message_data) + data_size)) {
      // We don't need to worry about exceptions here: the message_data
      // constructor as well as `move_to_list` are `noexcept`.
      ptr.reset(new (vptr) detail::message_data(ids.move_to_list()), false);
    } else {
      STOP(sec::runtime_error, "unable to allocate memory");
    }
    auto pos = ptr->storage();
    for (auto& x : objects) {
      // TODO: avoid extra copy by adding move_construct to meta objects
      x.meta->copy_construct(pos, x.obj);
      ptr->inc_constructed_elements();
      pos += x.meta->padded_size;
    }
    data.reset(ptr.release(), false);
    return true;
  } else {
    data.reset();
    return source.end_sequence();
  }
}

} // namespace

bool message::load(deserializer& source) {
  return load_data(source, data_);
}

bool message::load(binary_deserializer& source) {
  return load_data(source, data_);
}

namespace {

bool save(const detail::meta_object& meta, caf::serializer& sink,
          const void* obj) {
  return meta.save(sink, obj);
}

bool save(const detail::meta_object& meta, caf::binary_serializer& sink,
          const void* obj) {
  return meta.save_binary(sink, obj);
}

template <class Serializer>
typename Serializer::result_type
save_data(Serializer& sink, const message::data_ptr& data) {
  auto gmos = detail::global_meta_objects();
  // For machine-to-machine data formats, we prefix the type information.
  if (!sink.has_human_readable_format()) {
    if (data == nullptr) {
      // Short-circuit empty tuples.
      return sink.begin_object(type_id_v<message>, "message") //
             && sink.begin_field("types")                     //
             && sink.begin_sequence(0)                        //
             && sink.end_sequence()                           //
             && sink.end_field()                              //
             && sink.begin_field("values")                    //
             && sink.begin_tuple(0)                           //
             && sink.end_tuple()                              //
             && sink.end_field()                              //
             && sink.end_object();
    }
    GUARDED(sink.begin_object(type_id_v<message>, "message"));
    auto type_ids = data->types();
    // Write type information.
    GUARDED(sink.begin_field("types") && sink.begin_sequence(type_ids.size()));
    for (auto id : type_ids)
      GUARDED(sink.value(id));
    GUARDED(sink.end_sequence() && sink.end_field());
    // Write elements.
    auto storage = data->storage();
    GUARDED(sink.begin_field("values") && sink.begin_tuple(type_ids.size()));
    for (auto id : type_ids) {
      auto& meta = gmos[id];
      GUARDED(save(meta, sink, storage));
      storage += meta.padded_size;
    }
    return sink.end_tuple() && sink.end_field() && sink.end_object();
  }
  // For human-readable data formats, we serialize messages as a single list of
  // dynamically-typed objects.
  if (data == nullptr) {
    // Short-circuit empty tuples.
    return sink.begin_sequence(0) && sink.end_sequence();
  }
  auto type_ids = data->types();
  GUARDED(sink.begin_sequence(type_ids.size()));
  auto storage = data->storage();
  for (auto id : type_ids) {
    auto& meta = gmos[id];
    GUARDED(save(meta, sink, storage));
    storage += meta.padded_size;
  }
  return sink.end_sequence();
}

} // namespace

bool message::save(serializer& sink) const {
  return save_data(sink, data_);
}

bool message::save(binary_serializer& sink) const {
  return save_data(sink, data_);
}

// -- related non-members ------------------------------------------------------

std::string to_string(const message& msg) {
  if (msg.empty())
    return "message()";
  std::string result;
  result += "message(";
  auto types = msg.types();
  if (!types.empty()) {
    auto ptr = msg.cdata().storage();
    auto meta = detail::global_meta_object(types[0]);
    CAF_ASSERT(meta != nullptr);
    meta->stringify(result, ptr);
    ptr += meta->padded_size;
    for (size_t index = 1; index < types.size(); ++index) {
      result += ", ";
      meta = detail::global_meta_object(types[index]);
      CAF_ASSERT(meta != nullptr);
      meta->stringify(result, ptr);
      ptr += meta->padded_size;
    }
  }
  result += ')';
  return result;
}

} // namespace caf
<|endoftext|>


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

#include "ReprojectionFilter.hpp"

#include <memory>

#include <pdal/PointBuffer.hpp>

#pragma GCC diagnostic ignored "-Wfloat-equal"
#include <gdal.h>
#include <ogr_spatialref.h>
#include <pdal/GDALUtils.hpp>

namespace pdal
{

struct OGRSpatialReferenceDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::OSRDestroySpatialReference(ptr);
    }
};

struct OSRTransformDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::OCTDestroyCoordinateTransformation(ptr);
    }
};

struct GDALSourceDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::GDALClose(ptr);
    }
};

void ReprojectionFilter::processOptions(const Options& options)
{
    m_outSRS = options.getValueOrThrow<pdal::SpatialReference>("out_srs");
    if (options.hasOption("in_srs"))
    {
        m_inSRS = options.getValueOrThrow<pdal::SpatialReference>("in_srs");
        m_inferInputSRS = false;
    }
}

void ReprojectionFilter::ready(PointContext ctx)
{
    if (m_inferInputSRS)
        m_inSRS = ctx.spatialRef();

    m_gdal_debug = std::shared_ptr<pdal::gdal::Debug>(
        new pdal::gdal::Debug(isDebug(), log()));

    m_in_ref_ptr = ReferencePtr(OSRNewSpatialReference(0),
        OGRSpatialReferenceDeleter());
    m_out_ref_ptr = ReferencePtr(OSRNewSpatialReference(0),
        OGRSpatialReferenceDeleter());

    int result =
        OSRSetFromUserInput(m_in_ref_ptr.get(),
            m_inSRS.getWKT(pdal::SpatialReference::eCompoundOK).c_str());
    if (result != OGRERR_NONE)
    {
        std::ostringstream msg;
        msg << "Could not import input spatial reference for "
            "ReprojectionFilter:: " << CPLGetLastErrorMsg() << " code: " <<
            result << " wkt: '" << m_inSRS.getWKT() << "'";
        throw std::runtime_error(msg.str());
    }

    result = OSRSetFromUserInput(m_out_ref_ptr.get(),
        m_outSRS.getWKT(pdal::SpatialReference::eCompoundOK).c_str());
    if (result != OGRERR_NONE)
    {
        std::ostringstream msg;
        msg << "Could not import output spatial reference for "
            "ReprojectionFilter:: " << CPLGetLastErrorMsg() << " code: " <<
            result << " wkt: '" << m_outSRS.getWKT() << "'";
        std::string message(msg.str());
        throw std::runtime_error(message);
    }
    m_transform_ptr = TransformPtr(
        OCTNewCoordinateTransformation(m_in_ref_ptr.get(),
            m_out_ref_ptr.get()), OSRTransformDeleter());

    if (!m_transform_ptr.get())
    {
        std::string msg = "Could not construct CoordinateTransformation in "
            "ReprojectionFilter:: ";
        throw std::runtime_error(msg);
    }

    setSpatialReference(m_outSRS);
}

void ReprojectionFilter::transform(double& x, double& y, double& z)
{
    int ret = OCTTransform(m_transform_ptr.get(), 1, &x, &y, &z);
    if (ret == 0)
    {
        std::ostringstream msg;
        msg << "Could not project point for ReprojectionTransform::" <<
            CPLGetLastErrorMsg() << ret;
        throw pdal_error(msg.str());
    }
}

void ReprojectionFilter::filter(PointBuffer& data)
{
    for (PointId id = 0; id < data.size(); ++id)
    {
        double x = data.getFieldAs<double>(Dimension::Id::X, id);
        double y = data.getFieldAs<double>(Dimension::Id::Y, id);
        double z = data.getFieldAs<double>(Dimension::Id::Z, id);

        transform(x, y, z);

        data.setField(Dimension::Id::X, id, x);
        data.setField(Dimension::Id::Y, id, y);
        data.setField(Dimension::Id::Z, id, z);
    }
}

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

#include "ReprojectionFilter.hpp"

#include <memory>

#include <pdal/PointBuffer.hpp>

#pragma GCC diagnostic ignored "-Wfloat-equal"
#include <gdal.h>
#include <ogr_spatialref.h>
#include <pdal/GDALUtils.hpp>

namespace pdal
{

struct OGRSpatialReferenceDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::OSRDestroySpatialReference(ptr);
    }
};

struct OSRTransformDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::OCTDestroyCoordinateTransformation(ptr);
    }
};

struct GDALSourceDeleter
{
    template <typename T>
    void operator()(T* ptr)
    {
        ::GDALClose(ptr);
    }
};

void ReprojectionFilter::processOptions(const Options& options)
{
    try
    {
       m_outSRS = options.getValueOrThrow<pdal::SpatialReference>("out_srs");
    }
    catch (std::invalid_argument)
    {
        std::string srs = options.getValueOrDefault<std::string>("out_srs", "");
        std::ostringstream oss;
        oss << "Stage " << getName() << " has invalid spatial reference "
            "specification for 'out_srs' option: '" << srs << "'.";
        throw pdal_error(oss.str());
    }
    catch (option_not_found)
    {
        std::ostringstream oss;
        oss << "Stage " << getName() << " missing required option 'out_srs'.";
        throw pdal_error(oss.str());
    }

    if (options.hasOption("in_srs"))
    {
        try
        {
            m_inSRS = options.getValueOrThrow<pdal::SpatialReference>("in_srs");
        }
        catch (std::invalid_argument)
        {
            std::string srs =
                options.getValueOrDefault<std::string>("in_srs", "");
            std::ostringstream oss;
            oss << "Stage " << getName() << " has invalid spatial reference "
                "specification for 'in_srs' option: '" << srs << "'.";
            throw pdal_error(oss.str());
        }
        m_inferInputSRS = false;
    }
}

void ReprojectionFilter::ready(PointContext ctx)
{
    if (m_inferInputSRS)
    {
        m_inSRS = ctx.spatialRef();
        if (m_inSRS.getWKT().empty())
            throw pdal_error("Source data has no spatial reference and none "
                "is specified with the 'in_srs' option.");
    }

    m_gdal_debug = std::shared_ptr<pdal::gdal::Debug>(
        new pdal::gdal::Debug(isDebug(), log()));

    m_in_ref_ptr = ReferencePtr(OSRNewSpatialReference(0),
        OGRSpatialReferenceDeleter());
    m_out_ref_ptr = ReferencePtr(OSRNewSpatialReference(0),
        OGRSpatialReferenceDeleter());

    int result =
        OSRSetFromUserInput(m_in_ref_ptr.get(),
            m_inSRS.getWKT(pdal::SpatialReference::eCompoundOK).c_str());
    if (result != OGRERR_NONE)
    {
        std::ostringstream msg;
        msg << "Invalid input spatial reference '" << m_inSRS.getWKT() <<
            "'.  This is usually caused by a bad value for the 'in_srs'"
            "option or an invalid spatial reference in the source file.";
        throw pdal_error(msg.str());
    }

    result = OSRSetFromUserInput(m_out_ref_ptr.get(),
        m_outSRS.getWKT(pdal::SpatialReference::eCompoundOK).c_str());
    if (result != OGRERR_NONE)
    {
        std::ostringstream msg;
        msg << "Invalid output spatial reference '" << m_outSRS.getWKT() <<
            "'.  This is usually caused by a bad value for the 'out_srs'"
            "option.";
        throw pdal_error(msg.str());
    }
    m_transform_ptr = TransformPtr(
        OCTNewCoordinateTransformation(m_in_ref_ptr.get(),
            m_out_ref_ptr.get()), OSRTransformDeleter());

    if (!m_transform_ptr.get())
    {
        std::string msg = "Could not construct CoordinateTransformation in "
            "ReprojectionFilter:: ";
        throw std::runtime_error(msg);
    }

    setSpatialReference(m_outSRS);
}

void ReprojectionFilter::transform(double& x, double& y, double& z)
{
    int ret = OCTTransform(m_transform_ptr.get(), 1, &x, &y, &z);
    if (ret == 0)
    {
        std::ostringstream msg;
        msg << "Could not project point for ReprojectionTransform::" <<
            CPLGetLastErrorMsg() << ret;
        throw pdal_error(msg.str());
    }
}

void ReprojectionFilter::filter(PointBuffer& data)
{
    for (PointId id = 0; id < data.size(); ++id)
    {
        double x = data.getFieldAs<double>(Dimension::Id::X, id);
        double y = data.getFieldAs<double>(Dimension::Id::Y, id);
        double z = data.getFieldAs<double>(Dimension::Id::Z, id);

        transform(x, y, z);

        data.setField(Dimension::Id::X, id, x);
        data.setField(Dimension::Id::Y, id, y);
        data.setField(Dimension::Id::Z, id, z);
    }
}

} // namespace pdal
<|endoftext|>


<commit_before>/*
 * tcp_epoll.cpp
 *
 *  Created on: Nov 10, 2014
 *      Author: liao
 */
#include <cstdlib>
#include <climits>
#include <cstdio>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sys/fcntl.h>

#include "simple_log.h"
#include "epoll_socket.h"

int EpollSocket::setNonblocking(int fd) {
	int flags;

	if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
		flags = 0;
	return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
};

int EpollSocket::listen_on(int port, int backlog) {
	int sockfd; /* listen on sock_fd, new connection on new_fd */

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	struct sockaddr_in my_addr; /* my address information */
	memset (&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = AF_INET; /* host byte order */
	my_addr.sin_port = htons(port); /* short, network byte order */
	my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */

	int opt = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
		perror("bind");
		exit(1);
	}

	if (listen(sockfd, backlog) == -1) {
		perror("listen");
		exit(1);
	}

	LOG_INFO("start Server Socket on port : %d", port);
	return sockfd;
}

int EpollSocket::accept_socket(int sockfd) {
	int new_fd;
	struct sockaddr_in their_addr; /* connector's address information */
	socklen_t sin_size = sizeof(struct sockaddr_in);

	if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size)) == -1) {
		perror("accept");
		return -1;
	}

	LOG_DEBUG("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
	return new_fd;
}

int EpollSocket::start_epoll(int port, EpollSocketWatcher &socket_handler, int backlog) {
	int sockfd = this->listen_on(port, backlog);

	struct epoll_event ev;
	int epollfd = epoll_create(1024);
	if (epollfd == -1) {
		perror("epoll_create");
		exit(EXIT_FAILURE);
	}

	ev.events = EPOLLIN;
	ev.data.fd = sockfd;
	if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
		perror("epoll_ctl: listen_sock");
		exit(EXIT_FAILURE);
	}

	epoll_event events[10];

	while(1) {
		int fds_num = epoll_wait(epollfd, events, backlog, -1); // FIXME add a arg to controll __maxevents
		if(fds_num == -1) {
			perror("epoll_pwait");
			exit(EXIT_FAILURE);
		}

		for (int i = 0; i < fds_num; i++) {
			if(events[i].data.fd == sockfd) {
				int conn_sock = accept_socket(sockfd);
				setNonblocking(conn_sock);
				LOG_DEBUG("get accept socket which listen fd:%d, conn_sock_fd:%d", sockfd, conn_sock);

				EpollContext *epoll_context = new EpollContext();
				epoll_context->fd = conn_sock;

				socket_handler.on_accept(*epoll_context);

				epoll_event conn_sock_ev;
				conn_sock_ev.events = EPOLLIN | EPOLLET;
				conn_sock_ev.data.ptr = epoll_context;

				if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &conn_sock_ev) == -1) {
				   perror("epoll_ctl: conn_sock");
				   exit(EXIT_FAILURE);
				}

			} else if(events[i].events & EPOLLIN ){ // readable
				EpollContext *epoll_context = (EpollContext *) events[i].data.ptr;
				int fd = epoll_context->fd;

				int buffer_size = SS_READ_BUFFER_SIZE;
				char read_buffer[buffer_size];
				memset(read_buffer, 0, buffer_size);

				int read_size = recv(fd, read_buffer, buffer_size, 0);

				int handle_ret = 0;
                if(read_size > 0) {
					LOG_DEBUG("read success which read size:%d", read_size);
					handle_ret = socket_handler.on_readable(*epoll_context, read_buffer, buffer_size, read_size);
				}

				if(read_size <= 0 /* connect close or io error*/ || handle_ret != 0) {
					close_and_release(epollfd, events[i], socket_handler);
					continue;
				}

				events[i].events = EPOLLOUT | EPOLLET;
				epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &events[i]);

			} else if(events[i].events & EPOLLOUT) { // writeable
				EpollContext *epoll_context = (EpollContext *) events[i].data.ptr;
				int fd = epoll_context->fd;
				LOG_DEBUG("start write data");

				int ret = socket_handler.on_writeable(*epoll_context);
				if(ret == WRITE_CONN_CLOSE) {
					close_and_release(epollfd, events[i], socket_handler);
					continue;
				}

				if (ret == WRITE_CONN_CONTINUE) {
				    events[i].events = EPOLLOUT | EPOLLET;
				} else {
				    events[i].events = EPOLLIN | EPOLLET;
				}
				epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &events[i]);
			} else {
				LOG_INFO("unkonw events :%d", events[i].events);
				continue;
			}
		}
	}
}

int EpollSocket::close_and_release(int &epollfd, epoll_event &epoll_event, EpollSocketWatcher &socket_handler) {
	if(epoll_event.data.ptr == NULL) {
	    return 0;
	}
    LOG_INFO("connect close");

	EpollContext *hc = (EpollContext *) epoll_event.data.ptr;

	socket_handler.on_close(*hc);

	int fd = hc->fd;
	epoll_event.events = EPOLLIN | EPOLLOUT | EPOLLET;
	epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &epoll_event);

    delete (EpollContext *) epoll_event.data.ptr;
    epoll_event.data.ptr = NULL;

	int ret = close(fd);
	LOG_DEBUG("connect close complete which fd:%d, ret:%d", fd, ret);
	return ret;
}
<commit_msg>epoll size unlimit<commit_after>/*
 * tcp_epoll.cpp
 *
 *  Created on: Nov 10, 2014
 *      Author: liao
 */
#include <cstdlib>
#include <climits>
#include <cstdio>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sys/fcntl.h>

#include "simple_log.h"
#include "epoll_socket.h"

int EpollSocket::setNonblocking(int fd) {
	int flags;

	if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
		flags = 0;
	return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
};

int EpollSocket::listen_on(int port, int backlog) {
	int sockfd; /* listen on sock_fd, new connection on new_fd */

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	struct sockaddr_in my_addr; /* my address information */
	memset (&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = AF_INET; /* host byte order */
	my_addr.sin_port = htons(port); /* short, network byte order */
	my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */

	int opt = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
		perror("bind");
		exit(1);
	}

	if (listen(sockfd, backlog) == -1) {
		perror("listen");
		exit(1);
	}

	LOG_INFO("start Server Socket on port : %d", port);
	return sockfd;
}

int EpollSocket::accept_socket(int sockfd) {
	int new_fd;
	struct sockaddr_in their_addr; /* connector's address information */
	socklen_t sin_size = sizeof(struct sockaddr_in);

	if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size)) == -1) {
		perror("accept");
		return -1;
	}

	LOG_DEBUG("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
	return new_fd;
}

int EpollSocket::start_epoll(int port, EpollSocketWatcher &socket_handler, int backlog) {
	int sockfd = this->listen_on(port, backlog);

	struct epoll_event ev;
	int epollfd = epoll_create(1024);
	if (epollfd == -1) {
		perror("epoll_create");
		exit(EXIT_FAILURE);
	}

	ev.events = EPOLLIN;
	ev.data.fd = sockfd;
	if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
		perror("epoll_ctl: listen_sock");
		exit(EXIT_FAILURE);
	}

	int max_events = backlog; // FIXME add a arg to controll __maxevents
	epoll_event *events = new epoll_event[max_events];

	while(1) {
		int fds_num = epoll_wait(epollfd, events, max_events, -1);
		if(fds_num == -1) {
			perror("epoll_pwait");
			exit(EXIT_FAILURE);
		}

		for (int i = 0; i < fds_num; i++) {
			if(events[i].data.fd == sockfd) {
				int conn_sock = accept_socket(sockfd);
				setNonblocking(conn_sock);
				LOG_DEBUG("get accept socket which listen fd:%d, conn_sock_fd:%d", sockfd, conn_sock);

				EpollContext *epoll_context = new EpollContext();
				epoll_context->fd = conn_sock;

				socket_handler.on_accept(*epoll_context);

				epoll_event conn_sock_ev;
				conn_sock_ev.events = EPOLLIN | EPOLLET;
				conn_sock_ev.data.ptr = epoll_context;

				if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &conn_sock_ev) == -1) {
				   perror("epoll_ctl: conn_sock");
				   exit(EXIT_FAILURE);
				}

			} else if(events[i].events & EPOLLIN ){ // readable
				EpollContext *epoll_context = (EpollContext *) events[i].data.ptr;
				int fd = epoll_context->fd;

				int buffer_size = SS_READ_BUFFER_SIZE;
				char read_buffer[buffer_size];
				memset(read_buffer, 0, buffer_size);

				int read_size = recv(fd, read_buffer, buffer_size, 0);

				int handle_ret = 0;
                if(read_size > 0) {
					LOG_DEBUG("read success which read size:%d", read_size);
					handle_ret = socket_handler.on_readable(*epoll_context, read_buffer, buffer_size, read_size);
				}

				if(read_size <= 0 /* connect close or io error*/ || handle_ret != 0) {
					close_and_release(epollfd, events[i], socket_handler);
					continue;
				}

				events[i].events = EPOLLOUT | EPOLLET;
				epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &events[i]);

			} else if(events[i].events & EPOLLOUT) { // writeable
				EpollContext *epoll_context = (EpollContext *) events[i].data.ptr;
				int fd = epoll_context->fd;
				LOG_DEBUG("start write data");

				int ret = socket_handler.on_writeable(*epoll_context);
				if(ret == WRITE_CONN_CLOSE) {
					close_and_release(epollfd, events[i], socket_handler);
					continue;
				}

				if (ret == WRITE_CONN_CONTINUE) {
				    events[i].events = EPOLLOUT | EPOLLET;
				} else {
				    events[i].events = EPOLLIN | EPOLLET;
				}
				epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &events[i]);
			} else {
				LOG_INFO("unkonw events :%d", events[i].events);
				continue;
			}
		}
	}

	if (events != NULL) {
	    delete events;
	    events = NULL;
	}
}

int EpollSocket::close_and_release(int &epollfd, epoll_event &epoll_event, EpollSocketWatcher &socket_handler) {
	if(epoll_event.data.ptr == NULL) {
	    return 0;
	}
    LOG_INFO("connect close");

	EpollContext *hc = (EpollContext *) epoll_event.data.ptr;

	socket_handler.on_close(*hc);

	int fd = hc->fd;
	epoll_event.events = EPOLLIN | EPOLLOUT | EPOLLET;
	epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &epoll_event);

    delete (EpollContext *) epoll_event.data.ptr;
    epoll_event.data.ptr = NULL;

	int ret = close(fd);
	LOG_DEBUG("connect close complete which fd:%d, ret:%d", fd, ret);
	return ret;
}
<|endoftext|>


<commit_before><commit_msg>Update: add RX72T<commit_after><|endoftext|>


<commit_before><commit_msg>update: manage mesure, trigger<commit_after><|endoftext|>