<commit_before>
#include "PreCompiled.h"

#include <Base/VectorPy.h>
#include <Base/GeometryPyCXX.h>

#include "Mod/Fem/Gui/ViewProviderFemMesh.h"

// inclusion of the generated files (generated out of ViewProviderFemMeshPy.xml)
#include "ViewProviderFemMeshPy.h"
#include "ViewProviderFemMeshPy.cpp"

using namespace FemGui;

// returns a string which represents the object e.g. when printed in python
std::string ViewProviderFemMeshPy::representation(void) const
{
    return std::string("<ViewProviderFemMesh object>");
}

PyObject* ViewProviderFemMeshPy::animate(PyObject * args)
{
    double factor;
    if (!PyArg_ParseTuple(args, "d", &factor))
        return 0;

    this->getViewProviderFemMeshPtr()->animateNodes(factor);

    Py_Return;
}

Py::Dict ViewProviderFemMeshPy::getNodeColor(void) const
{
    //return Py::List();
    throw Py::AttributeError("Not yet implemented");
}

void ViewProviderFemMeshPy::setNodeColor(Py::Dict arg)
{
    if(arg.size() == 0)
        this->getViewProviderFemMeshPtr()->resetColorByNodeId();
    else {
        std::map<long,App::Color> NodeColorMap;

        for( Py::Dict::iterator it = arg.begin(); it!= arg.end();++it){
            Py::Int id((*it).first);
            Py::Tuple color((*it).second);
            NodeColorMap[id] = App::Color(Py::Float(color[0]),Py::Float(color[1]),Py::Float(color[2]),0);
        }
        this->getViewProviderFemMeshPtr()->setColorByNodeId(NodeColorMap);
	}
}

Py::Dict ViewProviderFemMeshPy::getNodeDisplacement(void) const
{
    //return Py::Dict();
    throw Py::AttributeError("Not yet implemented");
}

void  ViewProviderFemMeshPy::setNodeDisplacement(Py::Dict arg)
{
    if(arg.size() == 0)
        this->getViewProviderFemMeshPtr()->resetColorByNodeId();
    else {
        std::map<long,Base::Vector3d> NodeDispMap;
        union PyType_Object pyType = {&(Base::VectorPy::Type)};
        Py::Type vType(pyType.o);

        for( Py::Dict::iterator it = arg.begin(); it!= arg.end();++it){
            Py::Int id((*it).first);
            if ((*it).second.isType(vType)) {
                Py::Vector p((*it).second);
                NodeDispMap[id] = p.toVector();
            }
        }
        this->getViewProviderFemMeshPtr()->setDisplacementByNodeId(NodeDispMap);
	}
}

Py::List ViewProviderFemMeshPy::getHighlightedNodes(void) const
{
    //return Py::List();
    throw Py::AttributeError("Not yet implemented");
}

void  ViewProviderFemMeshPy::setHighlightedNodes(Py::List arg)
{
 /*   std::set<long>& nodeSet;
    for (Py::List::iterator it = arg.begin(); it != arg.end() && index < 16; ++it) {
        nodeSet.i (double)Py::Int(*it);
    }
    setHighlightNodes*/
    throw Py::AttributeError("Not yet implemented");

}

Py::List ViewProviderFemMeshPy::getVisibleElementFaces(void) const
{
    const std::vector<unsigned long> & visElmFc = this->getViewProviderFemMeshPtr()->getVisibleElementFaces();
    Py::List result( visElmFc.size() );

    int i = 0;
    for (std::vector<unsigned long>::const_iterator it = visElmFc.begin();it!=visElmFc.end();++it,i++){
        Py::Tuple tup(2);

        tup.setItem( 0,Py::Int((long)*it>>3) );
        tup.setItem( 1,Py::Int((long)(*it&7)+1) );
        result.setItem(i,tup);
    }

    return result;
}

PyObject *ViewProviderFemMeshPy::getCustomAttributes(const char* /*attr*/) const
{
    return 0;
}

int ViewProviderFemMeshPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0;
}

<commit_msg>fix in get visible faces<commit_after>
#include "PreCompiled.h"

#include <Base/VectorPy.h>
#include <Base/GeometryPyCXX.h>

#include "Mod/Fem/Gui/ViewProviderFemMesh.h"

// inclusion of the generated files (generated out of ViewProviderFemMeshPy.xml)
#include "ViewProviderFemMeshPy.h"
#include "ViewProviderFemMeshPy.cpp"

using namespace FemGui;

// returns a string which represents the object e.g. when printed in python
std::string ViewProviderFemMeshPy::representation(void) const
{
    return std::string("<ViewProviderFemMesh object>");
}

PyObject* ViewProviderFemMeshPy::animate(PyObject * args)
{
    double factor;
    if (!PyArg_ParseTuple(args, "d", &factor))
        return 0;

    this->getViewProviderFemMeshPtr()->animateNodes(factor);

    Py_Return;
}

Py::Dict ViewProviderFemMeshPy::getNodeColor(void) const
{
    //return Py::List();
    throw Py::AttributeError("Not yet implemented");
}

void ViewProviderFemMeshPy::setNodeColor(Py::Dict arg)
{
    if(arg.size() == 0)
        this->getViewProviderFemMeshPtr()->resetColorByNodeId();
    else {
        std::map<long,App::Color> NodeColorMap;

        for( Py::Dict::iterator it = arg.begin(); it!= arg.end();++it){
            Py::Int id((*it).first);
            Py::Tuple color((*it).second);
            NodeColorMap[id] = App::Color(Py::Float(color[0]),Py::Float(color[1]),Py::Float(color[2]),0);
        }
        this->getViewProviderFemMeshPtr()->setColorByNodeId(NodeColorMap);
	}
}

Py::Dict ViewProviderFemMeshPy::getNodeDisplacement(void) const
{
    //return Py::Dict();
    throw Py::AttributeError("Not yet implemented");
}

void  ViewProviderFemMeshPy::setNodeDisplacement(Py::Dict arg)
{
    if(arg.size() == 0)
        this->getViewProviderFemMeshPtr()->resetColorByNodeId();
    else {
        std::map<long,Base::Vector3d> NodeDispMap;
        union PyType_Object pyType = {&(Base::VectorPy::Type)};
        Py::Type vType(pyType.o);

        for( Py::Dict::iterator it = arg.begin(); it!= arg.end();++it){
            Py::Int id((*it).first);
            if ((*it).second.isType(vType)) {
                Py::Vector p((*it).second);
                NodeDispMap[id] = p.toVector();
            }
        }
        this->getViewProviderFemMeshPtr()->setDisplacementByNodeId(NodeDispMap);
	}
}

Py::List ViewProviderFemMeshPy::getHighlightedNodes(void) const
{
    //return Py::List();
    throw Py::AttributeError("Not yet implemented");
}

void  ViewProviderFemMeshPy::setHighlightedNodes(Py::List arg)
{
 /*   std::set<long>& nodeSet;
    for (Py::List::iterator it = arg.begin(); it != arg.end() && index < 16; ++it) {
        nodeSet.i (double)Py::Int(*it);
    }
    setHighlightNodes*/
    throw Py::AttributeError("Not yet implemented");

}

Py::List ViewProviderFemMeshPy::getVisibleElementFaces(void) const
{
    const std::vector<unsigned long> & visElmFc = this->getViewProviderFemMeshPtr()->getVisibleElementFaces();
    std::vector<unsigned long> trans;

    // sorting out double faces through higer order elements and null entries
    long elementOld =0, faceOld=0;
    for (std::vector<unsigned long>::const_iterator it = visElmFc.begin();it!=visElmFc.end();++it){
        if(*it == 0)
            continue;

        long element = *it>>3;
        long face    = (*it&7)+1;
        if(element == elementOld && face==faceOld)
            continue;

        trans.push_back(*it);
        elementOld = element;
        faceOld    = face;
    }

    Py::List result( trans.size() );
    int i = 0;
    for (std::vector<unsigned long>::const_iterator it = trans.begin();it!=trans.end();++it,i++){
        Py::Tuple tup(2);
        long element = *it>>3;
        long face    = (*it&7)+1;
        tup.setItem( 0,Py::Int( element ) );
        tup.setItem( 1,Py::Int( face ) );
        result.setItem(i,tup);
    }

    return result;
}

PyObject *ViewProviderFemMeshPy::getCustomAttributes(const char* /*attr*/) const
{
    return 0;
}

int ViewProviderFemMeshPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0;
}

<|endoftext|>


<commit_before>/*********************************************************************************
*
* Inviwo - Interactive Visualization Workshop
*
* Copyright (c) 2013-2015 Inviwo Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*********************************************************************************/

#include <modules/basecl/processors/volumemaxclprocessor.h>
#include <inviwo/core/datastructures/buffer/buffer.h>
#include <modules/opencl/syncclgl.h>
#include <modules/opencl/buffer/buffercl.h>
#include <modules/opencl/buffer/bufferclgl.h>
#include <modules/opencl/volume/volumecl.h>
#include <modules/opencl/volume/volumeclgl.h>

namespace inviwo {

ProcessorClassIdentifier(VolumeMaxCLProcessor, "org.inviwo.VolumeMaxCL");
ProcessorDisplayName(VolumeMaxCLProcessor, "Volume Max");
ProcessorTags(VolumeMaxCLProcessor, Tags::CL);
ProcessorCategory(VolumeMaxCLProcessor, "Volume Operation");
ProcessorCodeState(VolumeMaxCLProcessor, CODE_STATE_EXPERIMENTAL);

VolumeMaxCLProcessor::VolumeMaxCLProcessor()
    : Processor()
    , ProcessorKernelOwner(this)
    , inport_("volume")
    , outport_("volume")
    , volumeRegionSize_("region", "Region size", 8, 1, 100)
    , workGroupSize_("wgsize", "Work group size", ivec3(8), ivec3(0), ivec3(256))
    , useGLSharing_("glsharing", "Use OpenGL sharing", true)
    , supportsVolumeWrite_(false)
    , tmpVolume_(nullptr)
    , kernel_(nullptr) {
    addPort(inport_);
    addPort(outport_);

    addProperty(volumeRegionSize_);
    addProperty(workGroupSize_);
    addProperty(useGLSharing_);
}

VolumeMaxCLProcessor::~VolumeMaxCLProcessor() {}

void VolumeMaxCLProcessor::initialize() {
    Processor::initialize();
    buildKernel();
}

void VolumeMaxCLProcessor::deinitialize() {
    Processor::deinitialize();
    delete tmpVolume_;
    tmpVolume_ = nullptr;
}

void VolumeMaxCLProcessor::process() {
    if (kernel_ == nullptr) {
        return;
    }
    const Volume* volume = inport_.getData();

    const size3_t dim{volume->getDimensions()};
    const size3_t outDim{glm::ceil(vec3(dim) / static_cast<float>(volumeRegionSize_.get()))};
    // const DataFormatBase* volFormat = inport_.getData()->getDataFormat(); // Not used

    if (!outport_.hasData() || outport_.getData()->getDimensions() != outDim) {
        volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataUINT8::get()));
        // volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataUINT32::get()) );
        // volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataFLOAT32::get()) );
        // Use same transformation to make sure that they are render at the same location
        volumeOut_->setModelMatrix(volume->getModelMatrix());
        volumeOut_->setWorldMatrix(volume->getWorldMatrix());
        outport_.setData(volumeOut_.get(), false);
    }

    size3_t localWorkGroupSize(workGroupSize_.get());
    size3_t globalWorkGroupSize(getGlobalWorkGroupSize(outDim.x, localWorkGroupSize.x),
                              getGlobalWorkGroupSize(outDim.y, localWorkGroupSize.y),
                              getGlobalWorkGroupSize(outDim.z, localWorkGroupSize.z));

    if (useGLSharing_.get()) {
        SyncCLGL glSync;
        const VolumeCLGL* volumeCL = volume->getRepresentation<VolumeCLGL>();
        VolumeCLGL* volumeOutCL = volumeOut_->getEditableRepresentation<VolumeCLGL>();

        glSync.addToAquireGLObjectList(volumeCL);
        glSync.addToAquireGLObjectList(volumeOutCL);
        glSync.aquireAllObjects();

        executeVolumeOperation(volume, volumeCL, volumeOutCL, outDim, globalWorkGroupSize,
                               localWorkGroupSize);
    } else {
        const VolumeCL* volumeCL = volume->getRepresentation<VolumeCL>();
        VolumeCL* volumeOutCL = volumeOut_->getEditableRepresentation<VolumeCL>();
        executeVolumeOperation(volume, volumeCL, volumeOutCL, outDim, globalWorkGroupSize,
                               localWorkGroupSize);
    }
}

void VolumeMaxCLProcessor::executeVolumeOperation(const Volume* volume,
                                                  const VolumeCLBase* volumeCL,
                                                  VolumeCLBase* volumeOutCL, const size3_t& outDim,
                                                  const size3_t& globalWorkGroupSize,
                                                  const size3_t& localWorkgroupSize) {
    cl::Event events[2];
    try {
        BufferCL* tmpVolumeCL;
        int argIndex = 0;
        kernel_->setArg(argIndex++, *volumeCL);
        kernel_->setArg(argIndex++,
                        *(volumeCL->getVolumeStruct(volume)
                              .getRepresentation<BufferCL>()));  // Scaling for 12-bit data
        if (supportsVolumeWrite_) {
            kernel_->setArg(argIndex++, *volumeOutCL);
        } else {
            size_t outDimFlattened = outDim.x * outDim.y * outDim.z;
            if (tmpVolume_ == nullptr || tmpVolume_->getSize() != outDimFlattened) {
                delete tmpVolume_;
                tmpVolume_ = new BufferPrecision<unsigned char, POSITION_ATTRIB>(outDimFlattened);
            }
            tmpVolumeCL = tmpVolume_->getEditableRepresentation<BufferCL>();
            kernel_->setArg(argIndex++, *tmpVolumeCL);
        }
        kernel_->setArg(argIndex++, ivec4(outDim, 0));
        kernel_->setArg(argIndex++, ivec4(volumeRegionSize_.get()));

        OpenCL::getPtr()->getQueue().enqueueNDRangeKernel(
            *kernel_, cl::NullRange, globalWorkGroupSize, localWorkgroupSize, nullptr, &events[0]);

        if (!supportsVolumeWrite_) {
            std::vector<cl::Event> waitFor(1, events[0]);
            OpenCL::getPtr()->getQueue().enqueueCopyBufferToImage(
                tmpVolumeCL->get(), volumeOutCL->getEditable(), 0, size3_t(0), size3_t(outDim),
                &waitFor, &events[1]);
        }
    } catch (cl::Error& err) {
        LogError(getCLErrorString(err));
    }

#if IVW_PROFILING
    try {
        if (supportsVolumeWrite_) {
            events[0].wait();
            LogInfo("Exec time: " << events[0].getElapsedTime() << " ms");
        } else {
            // Measure both computation and copy (only need to wait for copy)
            events[1].wait();
            LogInfo("Exec time (computation, copy): "
                    << events[0].getElapsedTime() << " + " << events[1].getElapsedTime() << " = "
                    << events[0].getElapsedTime() + events[1].getElapsedTime() << " ms");
        }
    } catch (cl::Error& err) {
        LogError(getCLErrorString(err));
    }
#endif
}

void VolumeMaxCLProcessor::buildKernel() {
    std::stringstream defines;
    std::string extensions = OpenCL::getPtr()->getDevice().getInfo<CL_DEVICE_EXTENSIONS>();
    if (extensions.find("cl_khr_3d_image_writes") != std::string::npos) {
        supportsVolumeWrite_ = true;
        defines << " -D SUPPORTS_VOLUME_WRITE ";
    } else {
        supportsVolumeWrite_ = false;
    }
    kernel_ = addKernel("volumemax.cl", "volumeMaxKernel", defines.str());
}

}  // inviwo namespace
<commit_msg>BaseCL: Stopped VolumeMaxCL from using outport data<commit_after>/*********************************************************************************
*
* Inviwo - Interactive Visualization Workshop
*
* Copyright (c) 2013-2015 Inviwo Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*********************************************************************************/

#include <modules/basecl/processors/volumemaxclprocessor.h>
#include <inviwo/core/datastructures/buffer/buffer.h>
#include <modules/opencl/syncclgl.h>
#include <modules/opencl/buffer/buffercl.h>
#include <modules/opencl/buffer/bufferclgl.h>
#include <modules/opencl/volume/volumecl.h>
#include <modules/opencl/volume/volumeclgl.h>

namespace inviwo {

ProcessorClassIdentifier(VolumeMaxCLProcessor, "org.inviwo.VolumeMaxCL");
ProcessorDisplayName(VolumeMaxCLProcessor, "Volume Max");
ProcessorTags(VolumeMaxCLProcessor, Tags::CL);
ProcessorCategory(VolumeMaxCLProcessor, "Volume Operation");
ProcessorCodeState(VolumeMaxCLProcessor, CODE_STATE_EXPERIMENTAL);

VolumeMaxCLProcessor::VolumeMaxCLProcessor()
    : Processor()
    , ProcessorKernelOwner(this)
    , inport_("volume")
    , outport_("volume")
    , volumeRegionSize_("region", "Region size", 8, 1, 100)
    , workGroupSize_("wgsize", "Work group size", ivec3(8), ivec3(0), ivec3(256))
    , useGLSharing_("glsharing", "Use OpenGL sharing", true)
    , supportsVolumeWrite_(false)
    , tmpVolume_(nullptr)
    , kernel_(nullptr) {
    addPort(inport_);
    addPort(outport_);

    addProperty(volumeRegionSize_);
    addProperty(workGroupSize_);
    addProperty(useGLSharing_);
}

VolumeMaxCLProcessor::~VolumeMaxCLProcessor() {}

void VolumeMaxCLProcessor::initialize() {
    Processor::initialize();
    buildKernel();
}

void VolumeMaxCLProcessor::deinitialize() {
    Processor::deinitialize();
    delete tmpVolume_;
    tmpVolume_ = nullptr;
}

void VolumeMaxCLProcessor::process() {
    if (kernel_ == nullptr) {
        return;
    }
    const Volume* volume = inport_.getData();

    const size3_t dim{volume->getDimensions()};
    const size3_t outDim{glm::ceil(vec3(dim) / static_cast<float>(volumeRegionSize_.get()))};
    // const DataFormatBase* volFormat = inport_.getData()->getDataFormat(); // Not used

    if (!volumeOut_ || volumeOut_->getDimensions() != outDim) {
        volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataUINT8::get()));
        // volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataUINT32::get()) );
        // volumeOut_ = std::unique_ptr<Volume>( new Volume(outDim, DataFLOAT32::get()) );
        // Use same transformation to make sure that they are render at the same location
        volumeOut_->setModelMatrix(volume->getModelMatrix());
        volumeOut_->setWorldMatrix(volume->getWorldMatrix());
        outport_.setData(volumeOut_.get(), false);
    }

    size3_t localWorkGroupSize(workGroupSize_.get());
    size3_t globalWorkGroupSize(getGlobalWorkGroupSize(outDim.x, localWorkGroupSize.x),
                              getGlobalWorkGroupSize(outDim.y, localWorkGroupSize.y),
                              getGlobalWorkGroupSize(outDim.z, localWorkGroupSize.z));

    if (useGLSharing_.get()) {
        SyncCLGL glSync;
        const VolumeCLGL* volumeCL = volume->getRepresentation<VolumeCLGL>();
        VolumeCLGL* volumeOutCL = volumeOut_->getEditableRepresentation<VolumeCLGL>();

        glSync.addToAquireGLObjectList(volumeCL);
        glSync.addToAquireGLObjectList(volumeOutCL);
        glSync.aquireAllObjects();

        executeVolumeOperation(volume, volumeCL, volumeOutCL, outDim, globalWorkGroupSize,
                               localWorkGroupSize);
    } else {
        const VolumeCL* volumeCL = volume->getRepresentation<VolumeCL>();
        VolumeCL* volumeOutCL = volumeOut_->getEditableRepresentation<VolumeCL>();
        executeVolumeOperation(volume, volumeCL, volumeOutCL, outDim, globalWorkGroupSize,
                               localWorkGroupSize);
    }
}

void VolumeMaxCLProcessor::executeVolumeOperation(const Volume* volume,
                                                  const VolumeCLBase* volumeCL,
                                                  VolumeCLBase* volumeOutCL, const size3_t& outDim,
                                                  const size3_t& globalWorkGroupSize,
                                                  const size3_t& localWorkgroupSize) {
    cl::Event events[2];
    try {
        BufferCL* tmpVolumeCL;
        int argIndex = 0;
        kernel_->setArg(argIndex++, *volumeCL);
        kernel_->setArg(argIndex++,
                        *(volumeCL->getVolumeStruct(volume)
                              .getRepresentation<BufferCL>()));  // Scaling for 12-bit data
        if (supportsVolumeWrite_) {
            kernel_->setArg(argIndex++, *volumeOutCL);
        } else {
            size_t outDimFlattened = outDim.x * outDim.y * outDim.z;
            if (tmpVolume_ == nullptr || tmpVolume_->getSize() != outDimFlattened) {
                delete tmpVolume_;
                tmpVolume_ = new BufferPrecision<unsigned char, POSITION_ATTRIB>(outDimFlattened);
            }
            tmpVolumeCL = tmpVolume_->getEditableRepresentation<BufferCL>();
            kernel_->setArg(argIndex++, *tmpVolumeCL);
        }
        kernel_->setArg(argIndex++, ivec4(outDim, 0));
        kernel_->setArg(argIndex++, ivec4(volumeRegionSize_.get()));

        OpenCL::getPtr()->getQueue().enqueueNDRangeKernel(
            *kernel_, cl::NullRange, globalWorkGroupSize, localWorkgroupSize, nullptr, &events[0]);

        if (!supportsVolumeWrite_) {
            std::vector<cl::Event> waitFor(1, events[0]);
            OpenCL::getPtr()->getQueue().enqueueCopyBufferToImage(
                tmpVolumeCL->get(), volumeOutCL->getEditable(), 0, size3_t(0), size3_t(outDim),
                &waitFor, &events[1]);
        }
    } catch (cl::Error& err) {
        LogError(getCLErrorString(err));
    }

#if IVW_PROFILING
    try {
        if (supportsVolumeWrite_) {
            events[0].wait();
            LogInfo("Exec time: " << events[0].getElapsedTime() << " ms");
        } else {
            // Measure both computation and copy (only need to wait for copy)
            events[1].wait();
            LogInfo("Exec time (computation, copy): "
                    << events[0].getElapsedTime() << " + " << events[1].getElapsedTime() << " = "
                    << events[0].getElapsedTime() + events[1].getElapsedTime() << " ms");
        }
    } catch (cl::Error& err) {
        LogError(getCLErrorString(err));
    }
#endif
}

void VolumeMaxCLProcessor::buildKernel() {
    std::stringstream defines;
    std::string extensions = OpenCL::getPtr()->getDevice().getInfo<CL_DEVICE_EXTENSIONS>();
    if (extensions.find("cl_khr_3d_image_writes") != std::string::npos) {
        supportsVolumeWrite_ = true;
        defines << " -D SUPPORTS_VOLUME_WRITE ";
    } else {
        supportsVolumeWrite_ = false;
    }
    kernel_ = addKernel("volumemax.cl", "volumeMaxKernel", defines.str());
}

}  // inviwo namespace
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/platform_util.h"

#include <gtk/gtk.h>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/process_util.h"
#include "base/string_util.h"

namespace {

void XDGOpen(const FilePath& path) {
  std::vector<std::string> argv;
  argv.push_back("xdg-open");
  argv.push_back(path.value());
  base::file_handle_mapping_vector no_files;
  base::LaunchApp(argv, no_files, true, NULL);
}

}  // namespace

namespace platform_util {

// TODO(estade): It would be nice to be able to select the file in the file
// manager, but that probably requires extending xdg-open. For now just
// show the folder.
void ShowItemInFolder(const FilePath& full_path) {
  FilePath dir = full_path.DirName();
  if (!file_util::DirectoryExists(dir))
    return;

  XDGOpen(dir);
}

void OpenItem(const FilePath& full_path) {
  XDGOpen(full_path);
}

gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
  // A detached widget won't have a toplevel window as an ancestor, so we can't
  // assume that the query for toplevel will return a window.
  GtkWidget* toplevel = gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW);
  return GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : NULL;
}

string16 GetWindowTitle(gfx::NativeWindow window) {
  const gchar* title = gtk_window_get_title(window);
  return UTF8ToUTF16(title);
}

bool IsWindowActive(gfx::NativeWindow window) {
  return gtk_window_is_active(window);
}

bool IsVisible(gfx::NativeView view) {
  return GTK_WIDGET_VISIBLE(view);
}

}  // namespace platform_util
<commit_msg>Revert r19318. Seems we're blocking some UI thread though I thought we didn't here.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/platform_util.h"

#include <gtk/gtk.h>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/process_util.h"
#include "base/string_util.h"

namespace {

void XDGOpen(const FilePath& path) {
  std::vector<std::string> argv;
  argv.push_back("xdg-open");
  argv.push_back(path.value());
  base::file_handle_mapping_vector no_files;
  base::LaunchApp(argv, no_files, false, NULL);
}

}  // namespace

namespace platform_util {

// TODO(estade): It would be nice to be able to select the file in the file
// manager, but that probably requires extending xdg-open. For now just
// show the folder.
void ShowItemInFolder(const FilePath& full_path) {
  FilePath dir = full_path.DirName();
  if (!file_util::DirectoryExists(dir))
    return;

  XDGOpen(dir);
}

void OpenItem(const FilePath& full_path) {
  XDGOpen(full_path);
}

gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
  // A detached widget won't have a toplevel window as an ancestor, so we can't
  // assume that the query for toplevel will return a window.
  GtkWidget* toplevel = gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW);
  return GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : NULL;
}

string16 GetWindowTitle(gfx::NativeWindow window) {
  const gchar* title = gtk_window_get_title(window);
  return UTF8ToUTF16(title);
}

bool IsWindowActive(gfx::NativeWindow window) {
  return gtk_window_is_active(window);
}

bool IsVisible(gfx::NativeView view) {
  return GTK_WIDGET_VISIBLE(view);
}

}  // namespace platform_util
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"

class PreferenceServiceTest : public UITest {
public:
  void SetUp() {
    PathService::Get(base::DIR_TEMP, &tmp_profile_);
    tmp_profile_ = tmp_profile_.AppendASCII("tmp_profile");

    // Create a fresh, empty copy of this directory.
    file_util::Delete(tmp_profile_, true);
    file_util::CreateDirectory(tmp_profile_);

    FilePath reference_pref_file =
        test_data_directory_
            .AppendASCII("profiles")
            .AppendASCII("window_placement")
            .Append(chrome::kLocalStateFilename);

    tmp_pref_file_ = tmp_profile_.Append(chrome::kLocalStateFilename);

    ASSERT_TRUE(file_util::PathExists(reference_pref_file));

    // Copy only the Local State file, the rest will be automatically created
    ASSERT_TRUE(file_util::CopyFile(reference_pref_file, tmp_pref_file_));

#if defined(OS_WIN)
    // Make the copy writable.  On POSIX we assume the umask allows files
    // we create to be writable.
    ASSERT_TRUE(::SetFileAttributesW(tmp_pref_file_.value().c_str(),
        FILE_ATTRIBUTE_NORMAL));
#endif

    launch_arguments_.AppendSwitchWithValue(switches::kUserDataDir,
                                            tmp_profile_.ToWStringHack());
  }

  bool LaunchAppWithProfile() {
    if (!file_util::PathExists(tmp_pref_file_))
      return false;
    UITest::SetUp();
    return true;
  }

  void TearDown() {
    UITest::TearDown();

    EXPECT_TRUE(DieFileDie(tmp_profile_, true));
  }

public:
  FilePath tmp_pref_file_;
  FilePath tmp_profile_;
};

#if defined(OS_WIN)
// This test verifies that the window position from the prefs file is restored
// when the app restores.  This doesn't really make sense on Linux, where
// the window manager might fight with you over positioning.  However, we
// might be able to make this work on buildbots.
// Also, not sure what should happen on the mac.  In any case, the code below
// (minus the Windows bits) compiles fine on my Linux box now.
// TODO(port): revisit this.
TEST_F(PreferenceServiceTest, PreservedWindowPlacementIsLoaded) {
  // The window should open with the reference profile
  ASSERT_TRUE(LaunchAppWithProfile());

  ASSERT_TRUE(file_util::PathExists(tmp_pref_file_));

  JSONFileValueSerializer deserializer(tmp_pref_file_);
  scoped_ptr<Value> root(deserializer.Deserialize(NULL));

  ASSERT_TRUE(root.get());
  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));

  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());

  // Retrieve the screen rect for the launched window
  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_ptr<WindowProxy> window(browser->GetWindow());

  HWND hWnd;
  ASSERT_TRUE(window->GetHWND(&hWnd));

  WINDOWPLACEMENT window_placement;
  ASSERT_TRUE(GetWindowPlacement(hWnd, &window_placement));

  // Retrieve the expected rect values from "Preferences"
  int bottom = 0;
  std::wstring kBrowserWindowPlacement(prefs::kBrowserWindowPlacement);
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".bottom",
      &bottom));
  ASSERT_EQ(bottom, window_placement.rcNormalPosition.bottom);

  int top = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".top",
      &top));
  ASSERT_EQ(top, window_placement.rcNormalPosition.top);

  int left = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".left",
      &left));
  ASSERT_EQ(left, window_placement.rcNormalPosition.left);

  int right = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".right",
      &right));
  ASSERT_EQ(right, window_placement.rcNormalPosition.right);

  // Find if launched window is maximized
  bool is_window_maximized = (window_placement.showCmd == SW_MAXIMIZE);

  bool is_maximized = false;
  ASSERT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + L".maximized",
      &is_maximized));
  ASSERT_EQ(is_maximized, is_window_maximized);
}
#endif
<commit_msg>disabling a ui test while I investigate its failure<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"

class PreferenceServiceTest : public UITest {
public:
  void SetUp() {
    PathService::Get(base::DIR_TEMP, &tmp_profile_);
    tmp_profile_ = tmp_profile_.AppendASCII("tmp_profile");

    // Create a fresh, empty copy of this directory.
    file_util::Delete(tmp_profile_, true);
    file_util::CreateDirectory(tmp_profile_);

    FilePath reference_pref_file =
        test_data_directory_
            .AppendASCII("profiles")
            .AppendASCII("window_placement")
            .Append(chrome::kLocalStateFilename);

    tmp_pref_file_ = tmp_profile_.Append(chrome::kLocalStateFilename);

    ASSERT_TRUE(file_util::PathExists(reference_pref_file));

    // Copy only the Local State file, the rest will be automatically created
    ASSERT_TRUE(file_util::CopyFile(reference_pref_file, tmp_pref_file_));

#if defined(OS_WIN)
    // Make the copy writable.  On POSIX we assume the umask allows files
    // we create to be writable.
    ASSERT_TRUE(::SetFileAttributesW(tmp_pref_file_.value().c_str(),
        FILE_ATTRIBUTE_NORMAL));
#endif

    launch_arguments_.AppendSwitchWithValue(switches::kUserDataDir,
                                            tmp_profile_.ToWStringHack());
  }

  bool LaunchAppWithProfile() {
    if (!file_util::PathExists(tmp_pref_file_))
      return false;
    UITest::SetUp();
    return true;
  }

  void TearDown() {
    UITest::TearDown();

    EXPECT_TRUE(DieFileDie(tmp_profile_, true));
  }

public:
  FilePath tmp_pref_file_;
  FilePath tmp_profile_;
};

#if defined(OS_WIN)
// This test verifies that the window position from the prefs file is restored
// when the app restores.  This doesn't really make sense on Linux, where
// the window manager might fight with you over positioning.  However, we
// might be able to make this work on buildbots.
// Also, not sure what should happen on the mac.  In any case, the code below
// (minus the Windows bits) compiles fine on my Linux box now.
// TODO(port): revisit this.
TEST_F(PreferenceServiceTest, DISABLED_PreservedWindowPlacementIsLoaded) {
  // The window should open with the reference profile
  ASSERT_TRUE(LaunchAppWithProfile());

  ASSERT_TRUE(file_util::PathExists(tmp_pref_file_));

  JSONFileValueSerializer deserializer(tmp_pref_file_);
  scoped_ptr<Value> root(deserializer.Deserialize(NULL));

  ASSERT_TRUE(root.get());
  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));

  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());

  // Retrieve the screen rect for the launched window
  scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_ptr<WindowProxy> window(browser->GetWindow());

  HWND hWnd;
  ASSERT_TRUE(window->GetHWND(&hWnd));

  WINDOWPLACEMENT window_placement;
  ASSERT_TRUE(GetWindowPlacement(hWnd, &window_placement));

  // Retrieve the expected rect values from "Preferences"
  int bottom = 0;
  std::wstring kBrowserWindowPlacement(prefs::kBrowserWindowPlacement);
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".bottom",
      &bottom));
  ASSERT_EQ(bottom, window_placement.rcNormalPosition.bottom);

  int top = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".top",
      &top));
  ASSERT_EQ(top, window_placement.rcNormalPosition.top);

  int left = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".left",
      &left));
  ASSERT_EQ(left, window_placement.rcNormalPosition.left);

  int right = 0;
  ASSERT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".right",
      &right));
  ASSERT_EQ(right, window_placement.rcNormalPosition.right);

  // Find if launched window is maximized
  bool is_window_maximized = (window_placement.showCmd == SW_MAXIMIZE);

  bool is_maximized = false;
  ASSERT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + L".maximized",
      &is_maximized));
  ASSERT_EQ(is_maximized, is_window_maximized);
}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/user_script_slave.h"

#include "app/resource_bundle.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/perftimer.h"
#include "base/pickle.h"
#include "base/shared_memory.h"
#include "base/string_util.h"
#include "chrome/renderer/extension_groups.h"
#include "googleurl/src/gurl.h"
#include "webkit/api/public/WebFrame.h"

#include "grit/renderer_resources.h"

using WebKit::WebFrame;
using WebKit::WebString;

// These two strings are injected before and after the Greasemonkey API and
// user script to wrap it in an anonymous scope.
static const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
static const char kUserScriptTail[] = "\n})(window);";

// Sets up the chrome.extension module.
static const char kInitExtension[] = "chrome.initExtension('%s');";

int UserScriptSlave::GetIsolatedWorldId(const std::string& extension_id) {
  typedef std::map<std::string, int> IsolatedWorldMap;

  static IsolatedWorldMap g_isolated_world_ids;
  static int g_next_isolated_world_id = 1;

  IsolatedWorldMap::iterator iter = g_isolated_world_ids.find(extension_id);
  if (iter != g_isolated_world_ids.end())
    return iter->second;

  int new_id = g_next_isolated_world_id;
  ++g_next_isolated_world_id;

  // This map will tend to pile up over time, but realistically, you're never
  // going to have enough extensions for it to matter.
  g_isolated_world_ids[extension_id] = new_id;
  return new_id;
}

UserScriptSlave::UserScriptSlave()
    : shared_memory_(NULL),
      script_deleter_(&scripts_),
      user_script_start_line_(0) {
  api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
                IDR_GREASEMONKEY_API_JS);

  // Count the number of lines that will be injected before the user script.
  base::StringPiece::size_type pos = 0;
  while ((pos = api_js_.find('\n', pos)) != base::StringPiece::npos) {
    user_script_start_line_++;
    pos++;
  }

  // NOTE: There is actually one extra line in the injected script because the
  // function header includes a newline as well. But WebKit expects the
  // numbering to be one-based, not zero-based, so actually *not* accounting for
  // this extra line ends us up with the right offset.
}

bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
  scripts_.clear();

  // Create the shared memory object (read only).
  shared_memory_.reset(new base::SharedMemory(shared_memory, true));
  if (!shared_memory_.get())
    return false;

  // First get the size of the memory block.
  if (!shared_memory_->Map(sizeof(Pickle::Header)))
    return false;
  Pickle::Header* pickle_header =
      reinterpret_cast<Pickle::Header*>(shared_memory_->memory());

  // Now map in the rest of the block.
  int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
  shared_memory_->Unmap();
  if (!shared_memory_->Map(pickle_size))
    return false;

  // Unpickle scripts.
  void* iter = NULL;
  size_t num_scripts = 0;
  Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
                pickle_size);
  pickle.ReadSize(&iter, &num_scripts);

  scripts_.reserve(num_scripts);
  for (size_t i = 0; i < num_scripts; ++i) {
    scripts_.push_back(new UserScript());
    UserScript* script = scripts_.back();
    script->Unpickle(pickle, &iter);

    // Note that this is a pointer into shared memory. We don't own it. It gets
    // cleared up when the last renderer or browser process drops their
    // reference to the shared memory.
    for (size_t j = 0; j < script->js_scripts().size(); ++j) {
      const char* body = NULL;
      int body_length = 0;
      CHECK(pickle.ReadData(&iter, &body, &body_length));
      script->js_scripts()[j].set_external_content(
          base::StringPiece(body, body_length));
    }
    for (size_t j = 0; j < script->css_scripts().size(); ++j) {
      const char* body = NULL;
      int body_length = 0;
      CHECK(pickle.ReadData(&iter, &body, &body_length));
      script->css_scripts()[j].set_external_content(
          base::StringPiece(body, body_length));
    }
  }

  return true;
}

// static
void UserScriptSlave::InsertInitExtensionCode(
    std::vector<WebScriptSource>* sources, const std::string& extension_id) {
  DCHECK(sources);
  sources->insert(sources->begin(),
                  WebScriptSource(WebString::fromUTF8(
                  StringPrintf(kInitExtension, extension_id.c_str()))));
}

bool UserScriptSlave::InjectScripts(WebFrame* frame,
                                    UserScript::RunLocation location) {
  // Don't bother if this is not a URL we inject script into.
  if (!URLPattern::IsValidScheme(GURL(frame->url()).scheme()))
    return true;

  PerfTimer timer;
  int num_css = 0;
  int num_scripts = 0;

  for (size_t i = 0; i < scripts_.size(); ++i) {
    std::vector<WebScriptSource> sources;
    UserScript* script = scripts_[i];
    if (!script->MatchesUrl(frame->url()))
      continue;  // This frame doesn't match the script url pattern, skip it.

    // CSS files are always injected on document start before js scripts.
    if (location == UserScript::DOCUMENT_START) {
      num_css += script->css_scripts().size();
      for (size_t j = 0; j < script->css_scripts().size(); ++j) {
        UserScript::File& file = script->css_scripts()[j];
        frame->insertStyleText(
            WebString::fromUTF8(file.GetContent().as_string()), WebString());
      }
    }
    if (script->run_location() == location) {
      num_scripts += script->js_scripts().size();
      for (size_t j = 0; j < script->js_scripts().size(); ++j) {
        UserScript::File &file = script->js_scripts()[j];
        std::string content = file.GetContent().as_string();

        // We add this dumb function wrapper for standalone user script to
        // emulate what Greasemonkey does.
        if (script->is_standalone()) {
          content.insert(0, kUserScriptHead);
          content += kUserScriptTail;
        }
        sources.push_back(
            WebScriptSource(WebString::fromUTF8(content), file.url()));
      }
    }

    if (!sources.empty()) {
      int isolated_world_id = 0;

      if (script->is_standalone()) {
        // For standalone scripts, we try to emulate the Greasemonkey API.
        sources.insert(sources.begin(),
            WebScriptSource(WebString::fromUTF8(api_js_.as_string())));
      } else {
        // Setup chrome.self to contain an Extension object with the correct
        // ID.
        InsertInitExtensionCode(&sources, script->extension_id());
        isolated_world_id = GetIsolatedWorldId(script->extension_id());
      }

      frame->executeScriptInIsolatedWorld(
          isolated_world_id, &sources.front(), sources.size(),
          EXTENSION_GROUP_CONTENT_SCRIPTS);
    }
  }

  // Log debug info.
  if (location == UserScript::DOCUMENT_START) {
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", num_css);
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", num_scripts);
    UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", timer.Elapsed());
  } else {
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", num_scripts);
    UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", timer.Elapsed());
  }

  LOG(INFO) << "Injected " << num_scripts << " scripts and " << num_css <<
      "css files into " << frame->url().spec().data();
  return true;
}
<commit_msg>Don't call chrome.initExtension if we already called it.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/user_script_slave.h"

#include "app/resource_bundle.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/perftimer.h"
#include "base/pickle.h"
#include "base/shared_memory.h"
#include "base/string_util.h"
#include "chrome/renderer/extension_groups.h"
#include "googleurl/src/gurl.h"
#include "webkit/api/public/WebFrame.h"

#include "grit/renderer_resources.h"

using WebKit::WebFrame;
using WebKit::WebString;

// These two strings are injected before and after the Greasemonkey API and
// user script to wrap it in an anonymous scope.
static const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
static const char kUserScriptTail[] = "\n})(window);";

// Sets up the chrome.extension module. This may be run multiple times per
// context, but the init method deletes itself after the first time.
static const char kInitExtension[] =
  "if (chrome.initExtension) chrome.initExtension('%s');";

int UserScriptSlave::GetIsolatedWorldId(const std::string& extension_id) {
  typedef std::map<std::string, int> IsolatedWorldMap;

  static IsolatedWorldMap g_isolated_world_ids;
  static int g_next_isolated_world_id = 1;

  IsolatedWorldMap::iterator iter = g_isolated_world_ids.find(extension_id);
  if (iter != g_isolated_world_ids.end())
    return iter->second;

  int new_id = g_next_isolated_world_id;
  ++g_next_isolated_world_id;

  // This map will tend to pile up over time, but realistically, you're never
  // going to have enough extensions for it to matter.
  g_isolated_world_ids[extension_id] = new_id;
  return new_id;
}

UserScriptSlave::UserScriptSlave()
    : shared_memory_(NULL),
      script_deleter_(&scripts_),
      user_script_start_line_(0) {
  api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
                IDR_GREASEMONKEY_API_JS);

  // Count the number of lines that will be injected before the user script.
  base::StringPiece::size_type pos = 0;
  while ((pos = api_js_.find('\n', pos)) != base::StringPiece::npos) {
    user_script_start_line_++;
    pos++;
  }

  // NOTE: There is actually one extra line in the injected script because the
  // function header includes a newline as well. But WebKit expects the
  // numbering to be one-based, not zero-based, so actually *not* accounting for
  // this extra line ends us up with the right offset.
}

bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
  scripts_.clear();

  // Create the shared memory object (read only).
  shared_memory_.reset(new base::SharedMemory(shared_memory, true));
  if (!shared_memory_.get())
    return false;

  // First get the size of the memory block.
  if (!shared_memory_->Map(sizeof(Pickle::Header)))
    return false;
  Pickle::Header* pickle_header =
      reinterpret_cast<Pickle::Header*>(shared_memory_->memory());

  // Now map in the rest of the block.
  int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
  shared_memory_->Unmap();
  if (!shared_memory_->Map(pickle_size))
    return false;

  // Unpickle scripts.
  void* iter = NULL;
  size_t num_scripts = 0;
  Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
                pickle_size);
  pickle.ReadSize(&iter, &num_scripts);

  scripts_.reserve(num_scripts);
  for (size_t i = 0; i < num_scripts; ++i) {
    scripts_.push_back(new UserScript());
    UserScript* script = scripts_.back();
    script->Unpickle(pickle, &iter);

    // Note that this is a pointer into shared memory. We don't own it. It gets
    // cleared up when the last renderer or browser process drops their
    // reference to the shared memory.
    for (size_t j = 0; j < script->js_scripts().size(); ++j) {
      const char* body = NULL;
      int body_length = 0;
      CHECK(pickle.ReadData(&iter, &body, &body_length));
      script->js_scripts()[j].set_external_content(
          base::StringPiece(body, body_length));
    }
    for (size_t j = 0; j < script->css_scripts().size(); ++j) {
      const char* body = NULL;
      int body_length = 0;
      CHECK(pickle.ReadData(&iter, &body, &body_length));
      script->css_scripts()[j].set_external_content(
          base::StringPiece(body, body_length));
    }
  }

  return true;
}

// static
void UserScriptSlave::InsertInitExtensionCode(
    std::vector<WebScriptSource>* sources, const std::string& extension_id) {
  DCHECK(sources);
  sources->insert(sources->begin(),
                  WebScriptSource(WebString::fromUTF8(
                  StringPrintf(kInitExtension, extension_id.c_str()))));
}

bool UserScriptSlave::InjectScripts(WebFrame* frame,
                                    UserScript::RunLocation location) {
  // Don't bother if this is not a URL we inject script into.
  if (!URLPattern::IsValidScheme(GURL(frame->url()).scheme()))
    return true;

  PerfTimer timer;
  int num_css = 0;
  int num_scripts = 0;

  for (size_t i = 0; i < scripts_.size(); ++i) {
    std::vector<WebScriptSource> sources;
    UserScript* script = scripts_[i];
    if (!script->MatchesUrl(frame->url()))
      continue;  // This frame doesn't match the script url pattern, skip it.

    // CSS files are always injected on document start before js scripts.
    if (location == UserScript::DOCUMENT_START) {
      num_css += script->css_scripts().size();
      for (size_t j = 0; j < script->css_scripts().size(); ++j) {
        UserScript::File& file = script->css_scripts()[j];
        frame->insertStyleText(
            WebString::fromUTF8(file.GetContent().as_string()), WebString());
      }
    }
    if (script->run_location() == location) {
      num_scripts += script->js_scripts().size();
      for (size_t j = 0; j < script->js_scripts().size(); ++j) {
        UserScript::File &file = script->js_scripts()[j];
        std::string content = file.GetContent().as_string();

        // We add this dumb function wrapper for standalone user script to
        // emulate what Greasemonkey does.
        if (script->is_standalone()) {
          content.insert(0, kUserScriptHead);
          content += kUserScriptTail;
        }
        sources.push_back(
            WebScriptSource(WebString::fromUTF8(content), file.url()));
      }
    }

    if (!sources.empty()) {
      int isolated_world_id = 0;

      if (script->is_standalone()) {
        // For standalone scripts, we try to emulate the Greasemonkey API.
        sources.insert(sources.begin(),
            WebScriptSource(WebString::fromUTF8(api_js_.as_string())));
      } else {
        // Setup chrome.self to contain an Extension object with the correct
        // ID.
        InsertInitExtensionCode(&sources, script->extension_id());
        isolated_world_id = GetIsolatedWorldId(script->extension_id());
      }

      frame->executeScriptInIsolatedWorld(
          isolated_world_id, &sources.front(), sources.size(),
          EXTENSION_GROUP_CONTENT_SCRIPTS);
    }
  }

  // Log debug info.
  if (location == UserScript::DOCUMENT_START) {
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", num_css);
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", num_scripts);
    UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", timer.Elapsed());
  } else {
    UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", num_scripts);
    UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", timer.Elapsed());
  }

  LOG(INFO) << "Injected " << num_scripts << " scripts and " << num_css <<
      "css files into " << frame->url().spec().data();
  return true;
}
<|endoftext|>


<commit_before>#include "onair/okui/Application.h"

#include "onair/okui/Platform.h"

#include "onair/HTTPRequest.h"
#include "onair/thread.h"

namespace onair {
namespace okui {

Application::Application(const char* name, const char* organization, Platform* platform, ResourceManager* resourceManager)
    : _name{name}
    , _organization{organization}
    , _platform{platform}
    , _resourceManager{resourceManager}
{
    setMenu(Menu({
        MenuItem("Edit", Menu({
            MenuItem("Copy", kCommandCopy, KeyCode::kC, platform->defaultShortcutModifier()),
            MenuItem("Paste", kCommandPaste, KeyCode::kV, platform->defaultShortcutModifier()),
            MenuItem("Select All", kCommandSelectAll, KeyCode::kA, platform->defaultShortcutModifier()),
        })),
    }));
}

Application::~Application() {
    for (auto& task : _backgroundTasks) {
        task.wait();
    }
}

Responder* Application::firstResponder() {
    if (auto window = _platform->activeWindow()) {
        return window->firstResponder();
    }
    return this;
}

void Application::setMenu(const Menu& menu) {
    _platform->setApplicationMenu(this, menu);
}

std::string Application::userStoragePath() const {
    return _platform->userStoragePath(_name.c_str(), _organization.c_str());
}

std::future<std::shared_ptr<const std::string>> Application::download(const std::string& url, bool useCache) {
    auto it = _downloads.find(url);
    auto download = it == _downloads.end() ? (_downloads[url] = std::make_shared<DownloadInfo>()) : _downloads[url];
    std::lock_guard<std::mutex> lock(download->mutex);

    if (useCache) {
        if (download->result) {
            std::promise<std::shared_ptr<const std::string>> promise;
            promise.set_value(download->result);
            return promise.get_future();
        } else if (download->inProgress) {
            download->promises.emplace_back();
            return download->promises.back().get_future();
        }
    }

    std::promise<std::shared_ptr<const std::string>> promise;
    auto future = promise.get_future();

    ++download->inProgress;

    for (auto it = _backgroundTasks.begin(); it != _backgroundTasks.end();) {
        if (!it->valid() || it->wait_for(0_ms) == std::future_status::ready) {
            it = _backgroundTasks.erase(it);
        } else {
            ++it;
        }
    }

    _backgroundTasks.emplace_back(std::async([url, download, promise = std::move(promise)] () mutable {
        auto result = Download(url);

        std::lock_guard<std::mutex> lock(download->mutex);
        download->result = result;

        promise.set_value(result);
        for (auto& promise : download->promises) {
            promise.set_value(result);
        }

        download->promises.clear();
        --download->inProgress;
    }));

    return future;
}

void Application::run() {
    _platform->run();
}

void Application::quit() {
    _platform->quit();
}

Responder* Application::nextResponder() {
    return _platform;
}

bool Application::canHandleCommand(Command command) {
    return command == kCommandQuit;
}

void Application::handleCommand(Command command, CommandContext context) {
    if (command == kCommandQuit) {
        quit();
    } else {
        Responder::handleCommand(command, context);
    }
}

std::shared_ptr<const std::string> Application::Download(const std::string& url) {
    HTTPRequest request(url);
    request.wait();
    return request.responseStatus() == 200 ? std::make_shared<std::string>(request.responseBody()) : nullptr;
}

}}
<commit_msg>be explicit with std::async<commit_after>#include "onair/okui/Application.h"

#include "onair/okui/Platform.h"

#include "onair/HTTPRequest.h"
#include "onair/thread.h"

namespace onair {
namespace okui {

Application::Application(const char* name, const char* organization, Platform* platform, ResourceManager* resourceManager)
    : _name{name}
    , _organization{organization}
    , _platform{platform}
    , _resourceManager{resourceManager}
{
    setMenu(Menu({
        MenuItem("Edit", Menu({
            MenuItem("Copy", kCommandCopy, KeyCode::kC, platform->defaultShortcutModifier()),
            MenuItem("Paste", kCommandPaste, KeyCode::kV, platform->defaultShortcutModifier()),
            MenuItem("Select All", kCommandSelectAll, KeyCode::kA, platform->defaultShortcutModifier()),
        })),
    }));
}

Application::~Application() {
    for (auto& task : _backgroundTasks) {
        task.wait();
    }
}

Responder* Application::firstResponder() {
    if (auto window = _platform->activeWindow()) {
        return window->firstResponder();
    }
    return this;
}

void Application::setMenu(const Menu& menu) {
    _platform->setApplicationMenu(this, menu);
}

std::string Application::userStoragePath() const {
    return _platform->userStoragePath(_name.c_str(), _organization.c_str());
}

std::future<std::shared_ptr<const std::string>> Application::download(const std::string& url, bool useCache) {
    auto it = _downloads.find(url);
    auto download = it == _downloads.end() ? (_downloads[url] = std::make_shared<DownloadInfo>()) : _downloads[url];
    std::lock_guard<std::mutex> lock(download->mutex);

    if (useCache) {
        if (download->result) {
            std::promise<std::shared_ptr<const std::string>> promise;
            promise.set_value(download->result);
            return promise.get_future();
        } else if (download->inProgress) {
            download->promises.emplace_back();
            return download->promises.back().get_future();
        }
    }

    std::promise<std::shared_ptr<const std::string>> promise;
    auto future = promise.get_future();

    ++download->inProgress;

    for (auto it = _backgroundTasks.begin(); it != _backgroundTasks.end();) {
        if (!it->valid() || it->wait_for(0_ms) == std::future_status::ready) {
            it = _backgroundTasks.erase(it);
        } else {
            ++it;
        }
    }

    _backgroundTasks.emplace_back(std::async(std::launch::async, [url, download, promise = std::move(promise)] () mutable {
        auto result = Download(url);

        std::lock_guard<std::mutex> lock(download->mutex);
        download->result = result;

        promise.set_value(result);
        for (auto& promise : download->promises) {
            promise.set_value(result);
        }

        download->promises.clear();
        --download->inProgress;
    }));

    return future;
}

void Application::run() {
    _platform->run();
}

void Application::quit() {
    _platform->quit();
}

Responder* Application::nextResponder() {
    return _platform;
}

bool Application::canHandleCommand(Command command) {
    return command == kCommandQuit;
}

void Application::handleCommand(Command command, CommandContext context) {
    if (command == kCommandQuit) {
        quit();
    } else {
        Responder::handleCommand(command, context);
    }
}

std::shared_ptr<const std::string> Application::Download(const std::string& url) {
    HTTPRequest request(url);
    request.wait();
    return request.responseStatus() == 200 ? std::make_shared<std::string>(request.responseBody()) : nullptr;
}

}}
<|endoftext|>


<commit_before>#include "config.h"

#include <algorithm>
#include <functional>

#include "http_client.h"
#include "exception.h"
#include <cinttypes>
#ifndef HAVE_LIBCURL
#include "buffered_socket.h"
#include <cstrings>
#else
#include <cstrings>
#endif

namespace arg3
{
    namespace net
    {
#define THIS_USER_AGENT "libarg3net"

#ifdef HAVE_LIBCURL

        size_t curl_append_response_callback(void *ptr, size_t size, size_t nmemb, string *s)
        {
            if (s == NULL) return 0;

            const size_t new_len = size * nmemb;

            char buf[new_len + 1];

            memcpy(buf, ptr, size * nmemb);

            buf[new_len] = '\0';

            s->append(buf);

            return new_len;
        }
#endif

        size_t skip_newline(const string &s, size_t pos)
        {
            for (int i = 0; i < 2; i++, pos++) {
                if (s[pos] != '\r' && s[pos] != '\n') break;
            }

            return pos;
        }

        http_transfer::http_transfer() : version_(http::VERSION_1_1)
        {
        }

        http_transfer::http_transfer(const http_transfer &other) : payload_(other.payload_), headers_(other.headers_), version_(other.version_)
        {
        }

        http_transfer::http_transfer(http_transfer &&other)
            : payload_(std::move(other.payload_)), headers_(std::move(other.headers_)), version_(std::move(other.version_))
        {
        }

        http_transfer::~http_transfer()
        {
        }

        http_transfer &http_transfer::operator=(const http_transfer &other)
        {
            payload_ = other.payload_;
            headers_ = other.headers_;
            version_ = other.version_;
            return *this;
        }

        http_transfer &http_transfer::operator=(http_transfer &&other)
        {
            payload_ = std::move(other.payload_);
            headers_ = std::move(other.headers_);
            version_ = std::move(other.version_);
            return *this;
        }

        string http_transfer::header(const string &key)
        {
            return headers_[key];
        }

        const map<string, string> http_transfer::headers() const
        {
            return headers_;
        }

        string http_transfer::payload() const
        {
            return payload_;
        }

        string http_transfer::version() const
        {
            return version_;
        }

        void http_transfer::set_version(const string &value)
        {
            version_ = value;
        }

        http_response::http_response() : responseCode_(0)
        {
        }

        http_response::http_response(const string &fullResponse) : response_(fullResponse), responseCode_(0)
        {
            parse();
        }

        http_response::http_response(const http_response &other)
            : http_transfer(other), response_(other.response_), responseCode_(other.responseCode_)
        {
        }

        http_response::http_response(http_response &&other)
            : http_transfer(std::move(other)), response_(std::move(other.response_)), responseCode_(std::move(other.responseCode_))
        {
        }

        http_response::~http_response()
        {
        }

        http_response &http_response::operator=(const http_response &other)
        {
            http_transfer::operator=(other);

            response_ = other.response_;

            responseCode_ = other.responseCode_;

            return *this;
        }

        http_response &http_response::operator=(http_response &&other)
        {
            http_transfer::operator=(std::move(other));

            response_ = std::move(other.response_);

            responseCode_ = std::move(other.responseCode_);

            return *this;
        }

        string http_response::full_response() const
        {
            return response_;
        }

        http_response::operator string() const
        {
            return payload_;
        }

        int http_response::code() const
        {
            return responseCode_;
        }

        void http_response::parse(const string &value)
        {
            response_ = value;

            parse();
        }

        void http_response::clear()
        {
            response_.clear();
            responseCode_ = 0;
            headers_.clear();
            payload_.clear();
        }

        void http_response::parse()
        {
            auto pos = response_.find("\r\n");

            if (pos == string::npos) {
                payload_ = response_;
                return;
            }

            string line = response_.substr(0, pos);

            char buf[http::MAX_URL_LEN + 1] = {0};

            char version[http::MAX_URL_LEN + 1] = {0};

            if (sscanf(line.c_str(), http::RESPONSE_PREAMBLE, version, &responseCode_, buf) != 3) {
                payload_ = response_;
                return;
            }

            version_ = version;

            pos = skip_newline(response_, pos);

            while (!line.empty()) {
                auto next = response_.find("\r\n", pos);

                if (next == string::npos) break;

                line = response_.substr(pos, next - pos);

                auto sep = line.find(':');

                if (sep != string::npos) {
                    auto key = line.substr(0, sep);

                    auto value = line.substr(sep + 2);

                    headers_[key] = value;
                }

                pos = skip_newline(response_, next);
            }

            if (pos != string::npos) payload_ = response_.substr(pos);
        }

        http_client::http_client(const string &host) : scheme_(http::SCHEME), host_(host)
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::http_client()
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::~http_client()
        {
        }

        http_client::http_client(const http_client &other)
            : http_transfer(other), scheme_(other.scheme_), host_(other.host_), response_(other.response_)
        {
        }

        http_client::http_client(http_client &&other)
            : http_transfer(std::move(other)), scheme_(std::move(other.scheme_)), host_(std::move(other.host_)), response_(std::move(other.response_))
        {
        }

        http_client &http_client::operator=(const http_client &other)
        {
            http_transfer::operator=(other);
            scheme_ = other.scheme_;
            host_ = other.host_;
            headers_ = other.headers_;
            return *this;
        }

        http_client &http_client::operator=(http_client &&other)
        {
            http_transfer::operator=(std::move(other));
            scheme_ = std::move(other.scheme_);
            host_ = std::move(other.host_);
            response_ = std::move(other.response_);
            return *this;
        }

        http_client &http_client::add_header(const string &key, const string &value)
        {
            headers_[key] = value;
            return *this;
        }

        void http_client::remove_header(const string &key)
        {
            headers_.erase(key);
        }

        string http_client::host() const
        {
            return host_;
        }

        http_response http_client::response() const
        {
            return response_;
        }

        bool http_client::is_secure() const
        {
            return scheme_ == http::SECURE_SCHEME;
        }

        http_client &http_client::set_host(const string &host)
        {
            host_ = host;
            return *this;
        }

        http_client &http_client::set_secure(bool value)
        {
            scheme_ = value ? http::SECURE_SCHEME : http::SCHEME;
            return *this;
        }

        http_client &http_client::set_payload(const string &payload)
        {
            payload_ = payload;
            return *this;
        }

#ifdef HAVE_LIBCURL
        void http_client::request_curl(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            struct curl_slist *headers = NULL;

            CURL *curl_ = curl_easy_init();

            if (curl_ == NULL) {
                throw rest_exception("unable to initialize request");
            }

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, "%s://%s", scheme_.c_str(), host_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, "%s://%s%s", scheme_.c_str(), host_.c_str(), path.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, "%s://%s/%s", scheme_.c_str(), host_.c_str(), path.c_str());

            curl_easy_setopt(curl_, CURLOPT_URL, buf);

            curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curl_append_response_callback);

            curl_easy_setopt(curl_, CURLOPT_HEADER, 1L);

#ifdef DEBUG
            curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);
#endif

            switch (method) {
                case http::GET:
                    curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L);
                    break;
                case http::POST:
                    curl_easy_setopt(curl_, CURLOPT_POST, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                    break;
                case http::PUT:
                    curl_easy_setopt(curl_, CURLOPT_PUT, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                case http::DELETE:
                    curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, http::method_names[http::DELETE]);
                    break;
            }

            for (auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                headers = curl_slist_append(headers, buf);
            }

            curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers);

            curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response_.response_);

            CURLcode res = curl_easy_perform(curl_);

            if (res != CURLE_OK) {
                curl_easy_cleanup(curl_);

                throw rest_exception(curl_easy_strerror(res));
            }

            curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &response_.responseCode_);

            curl_easy_cleanup(curl_);

            response_.parse();
        }
#else
        void http_client::request_socket(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            buffered_socket sock;

            // create the socket based on hostname and port
            auto pos = host().find(':');

            if (is_secure()) sock.set_secure(true);

            if (pos != string::npos) {
                string hostname = host().substr(0, pos);
                int port = stoi(host().substr(pos + 1));

                if (!sock.connect(hostname, port)) throw socket_exception("unable to connect to " + host());
            } else {
                if (!sock.connect(host(), is_secure() ? http::DEFAULT_SECURE_PORT : http::DEFAULT_PORT))
                    throw socket_exception("unable to connect to " + host());
            }

            // send the method and path

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], "/", version_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], path.c_str(), version_.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], ("/" + path).c_str(), version_.c_str());

            sock.writeln(buf);

            bool chunked =
                headers_.count(http::HEADER_TRANSFER_ENCODING) != 0 && !strcasecmp(headers_[http::HEADER_TRANSFER_ENCODING].c_str(), "chunked");

            // specify the host
            if (headers_.count(http::HEADER_HOST) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", http::HEADER_HOST, host().c_str());
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_ACCEPT) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: */*", http::HEADER_ACCEPT);
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_CONNECTION) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: close", http::HEADER_CONNECTION);
                sock.writeln(buf);
            }

            // add the headers
            for (const auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                sock.writeln(buf);
            }

            // if we have a payload, add the size
            if (!chunked && !payload_.empty()) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %zu", http::HEADER_CONTENT_SIZE, payload_.size());

                sock.writeln(buf);
            }

            // finish header
            sock.writeln();

            // add the payload
            if (!payload_.empty()) {
                sock.write(payload_);
            }

#ifdef DEBUG
            cout << string(sock.output().begin(), sock.output().end());
#endif

            if (!sock.write_from_buffer()) throw socket_exception("unable to write to socket");

            if (!sock.read_to_buffer()) throw socket_exception("unable to read from socket");

            auto input = sock.input();

            response_.parse(string(input.begin(), input.end()));

            // sock.close();
        }
#endif

        http_client &http_client::request(http::method method, const string &path)
        {
            response_.clear();

            if (host_.empty()) throw socket_exception("no host");

#ifdef HAVE_LIBCURL
            request_curl(method, path);
#else
            request_socket(method, path);
#endif

            return *this;
        }

        http_client &http_client::get(const string &path)
        {
            return request(http::GET, path);
        }

        http_client &http_client::post(const string &path)
        {
            return request(http::POST, path);
        }

        http_client &http_client::put(const string &path)
        {
            return request(http::PUT, path);
        }

        http_client &http_client::de1ete(const string &path)
        {
            return request(http::DELETE, path);
        }
    }
}
<commit_msg>fix header issue<commit_after>#include "config.h"

#include <algorithm>
#include <functional>

#include "http_client.h"
#include "exception.h"
#include <cinttypes>
#ifndef HAVE_LIBCURL
#include "buffered_socket.h"
#include <cstring>
#else
#include <cstring>
#endif

namespace arg3
{
    namespace net
    {
#define THIS_USER_AGENT "libarg3net"

#ifdef HAVE_LIBCURL

        size_t curl_append_response_callback(void *ptr, size_t size, size_t nmemb, string *s)
        {
            if (s == NULL) return 0;

            const size_t new_len = size * nmemb;

            char buf[new_len + 1];

            memcpy(buf, ptr, size * nmemb);

            buf[new_len] = '\0';

            s->append(buf);

            return new_len;
        }
#endif

        size_t skip_newline(const string &s, size_t pos)
        {
            for (int i = 0; i < 2; i++, pos++) {
                if (s[pos] != '\r' && s[pos] != '\n') break;
            }

            return pos;
        }

        http_transfer::http_transfer() : version_(http::VERSION_1_1)
        {
        }

        http_transfer::http_transfer(const http_transfer &other) : payload_(other.payload_), headers_(other.headers_), version_(other.version_)
        {
        }

        http_transfer::http_transfer(http_transfer &&other)
            : payload_(std::move(other.payload_)), headers_(std::move(other.headers_)), version_(std::move(other.version_))
        {
        }

        http_transfer::~http_transfer()
        {
        }

        http_transfer &http_transfer::operator=(const http_transfer &other)
        {
            payload_ = other.payload_;
            headers_ = other.headers_;
            version_ = other.version_;
            return *this;
        }

        http_transfer &http_transfer::operator=(http_transfer &&other)
        {
            payload_ = std::move(other.payload_);
            headers_ = std::move(other.headers_);
            version_ = std::move(other.version_);
            return *this;
        }

        string http_transfer::header(const string &key)
        {
            return headers_[key];
        }

        const map<string, string> http_transfer::headers() const
        {
            return headers_;
        }

        string http_transfer::payload() const
        {
            return payload_;
        }

        string http_transfer::version() const
        {
            return version_;
        }

        void http_transfer::set_version(const string &value)
        {
            version_ = value;
        }

        http_response::http_response() : responseCode_(0)
        {
        }

        http_response::http_response(const string &fullResponse) : response_(fullResponse), responseCode_(0)
        {
            parse();
        }

        http_response::http_response(const http_response &other)
            : http_transfer(other), response_(other.response_), responseCode_(other.responseCode_)
        {
        }

        http_response::http_response(http_response &&other)
            : http_transfer(std::move(other)), response_(std::move(other.response_)), responseCode_(std::move(other.responseCode_))
        {
        }

        http_response::~http_response()
        {
        }

        http_response &http_response::operator=(const http_response &other)
        {
            http_transfer::operator=(other);

            response_ = other.response_;

            responseCode_ = other.responseCode_;

            return *this;
        }

        http_response &http_response::operator=(http_response &&other)
        {
            http_transfer::operator=(std::move(other));

            response_ = std::move(other.response_);

            responseCode_ = std::move(other.responseCode_);

            return *this;
        }

        string http_response::full_response() const
        {
            return response_;
        }

        http_response::operator string() const
        {
            return payload_;
        }

        int http_response::code() const
        {
            return responseCode_;
        }

        void http_response::parse(const string &value)
        {
            response_ = value;

            parse();
        }

        void http_response::clear()
        {
            response_.clear();
            responseCode_ = 0;
            headers_.clear();
            payload_.clear();
        }

        void http_response::parse()
        {
            auto pos = response_.find("\r\n");

            if (pos == string::npos) {
                payload_ = response_;
                return;
            }

            string line = response_.substr(0, pos);

            char buf[http::MAX_URL_LEN + 1] = {0};

            char version[http::MAX_URL_LEN + 1] = {0};

            if (sscanf(line.c_str(), http::RESPONSE_PREAMBLE, version, &responseCode_, buf) != 3) {
                payload_ = response_;
                return;
            }

            version_ = version;

            pos = skip_newline(response_, pos);

            while (!line.empty()) {
                auto next = response_.find("\r\n", pos);

                if (next == string::npos) break;

                line = response_.substr(pos, next - pos);

                auto sep = line.find(':');

                if (sep != string::npos) {
                    auto key = line.substr(0, sep);

                    auto value = line.substr(sep + 2);

                    headers_[key] = value;
                }

                pos = skip_newline(response_, next);
            }

            if (pos != string::npos) payload_ = response_.substr(pos);
        }

        http_client::http_client(const string &host) : scheme_(http::SCHEME), host_(host)
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::http_client()
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::~http_client()
        {
        }

        http_client::http_client(const http_client &other)
            : http_transfer(other), scheme_(other.scheme_), host_(other.host_), response_(other.response_)
        {
        }

        http_client::http_client(http_client &&other)
            : http_transfer(std::move(other)), scheme_(std::move(other.scheme_)), host_(std::move(other.host_)), response_(std::move(other.response_))
        {
        }

        http_client &http_client::operator=(const http_client &other)
        {
            http_transfer::operator=(other);
            scheme_ = other.scheme_;
            host_ = other.host_;
            headers_ = other.headers_;
            return *this;
        }

        http_client &http_client::operator=(http_client &&other)
        {
            http_transfer::operator=(std::move(other));
            scheme_ = std::move(other.scheme_);
            host_ = std::move(other.host_);
            response_ = std::move(other.response_);
            return *this;
        }

        http_client &http_client::add_header(const string &key, const string &value)
        {
            headers_[key] = value;
            return *this;
        }

        void http_client::remove_header(const string &key)
        {
            headers_.erase(key);
        }

        string http_client::host() const
        {
            return host_;
        }

        http_response http_client::response() const
        {
            return response_;
        }

        bool http_client::is_secure() const
        {
            return scheme_ == http::SECURE_SCHEME;
        }

        http_client &http_client::set_host(const string &host)
        {
            host_ = host;
            return *this;
        }

        http_client &http_client::set_secure(bool value)
        {
            scheme_ = value ? http::SECURE_SCHEME : http::SCHEME;
            return *this;
        }

        http_client &http_client::set_payload(const string &payload)
        {
            payload_ = payload;
            return *this;
        }

#ifdef HAVE_LIBCURL
        void http_client::request_curl(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            struct curl_slist *headers = NULL;

            CURL *curl_ = curl_easy_init();

            if (curl_ == NULL) {
                throw rest_exception("unable to initialize request");
            }

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, "%s://%s", scheme_.c_str(), host_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, "%s://%s%s", scheme_.c_str(), host_.c_str(), path.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, "%s://%s/%s", scheme_.c_str(), host_.c_str(), path.c_str());

            curl_easy_setopt(curl_, CURLOPT_URL, buf);

            curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curl_append_response_callback);

            curl_easy_setopt(curl_, CURLOPT_HEADER, 1L);

#ifdef DEBUG
            curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);
#endif

            switch (method) {
                case http::GET:
                    curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L);
                    break;
                case http::POST:
                    curl_easy_setopt(curl_, CURLOPT_POST, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                    break;
                case http::PUT:
                    curl_easy_setopt(curl_, CURLOPT_PUT, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                case http::DELETE:
                    curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, http::method_names[http::DELETE]);
                    break;
            }

            for (auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                headers = curl_slist_append(headers, buf);
            }

            curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers);

            curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response_.response_);

            CURLcode res = curl_easy_perform(curl_);

            if (res != CURLE_OK) {
                curl_easy_cleanup(curl_);

                throw rest_exception(curl_easy_strerror(res));
            }

            curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &response_.responseCode_);

            curl_easy_cleanup(curl_);

            response_.parse();
        }
#else
        void http_client::request_socket(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            buffered_socket sock;

            // create the socket based on hostname and port
            auto pos = host().find(':');

            if (is_secure()) sock.set_secure(true);

            if (pos != string::npos) {
                string hostname = host().substr(0, pos);
                int port = stoi(host().substr(pos + 1));

                if (!sock.connect(hostname, port)) throw socket_exception("unable to connect to " + host());
            } else {
                if (!sock.connect(host(), is_secure() ? http::DEFAULT_SECURE_PORT : http::DEFAULT_PORT))
                    throw socket_exception("unable to connect to " + host());
            }

            // send the method and path

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], "/", version_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], path.c_str(), version_.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], ("/" + path).c_str(), version_.c_str());

            sock.writeln(buf);

            bool chunked =
                headers_.count(http::HEADER_TRANSFER_ENCODING) != 0 && !strcasecmp(headers_[http::HEADER_TRANSFER_ENCODING].c_str(), "chunked");

            // specify the host
            if (headers_.count(http::HEADER_HOST) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", http::HEADER_HOST, host().c_str());
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_ACCEPT) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: */*", http::HEADER_ACCEPT);
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_CONNECTION) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: close", http::HEADER_CONNECTION);
                sock.writeln(buf);
            }

            // add the headers
            for (const auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                sock.writeln(buf);
            }

            // if we have a payload, add the size
            if (!chunked && !payload_.empty()) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %zu", http::HEADER_CONTENT_SIZE, payload_.size());

                sock.writeln(buf);
            }

            // finish header
            sock.writeln();

            // add the payload
            if (!payload_.empty()) {
                sock.write(payload_);
            }

#ifdef DEBUG
            cout << string(sock.output().begin(), sock.output().end());
#endif

            if (!sock.write_from_buffer()) throw socket_exception("unable to write to socket");

            if (!sock.read_to_buffer()) throw socket_exception("unable to read from socket");

            auto input = sock.input();

            response_.parse(string(input.begin(), input.end()));

            // sock.close();
        }
#endif

        http_client &http_client::request(http::method method, const string &path)
        {
            response_.clear();

            if (host_.empty()) throw socket_exception("no host");

#ifdef HAVE_LIBCURL
            request_curl(method, path);
#else
            request_socket(method, path);
#endif

            return *this;
        }

        http_client &http_client::get(const string &path)
        {
            return request(http::GET, path);
        }

        http_client &http_client::post(const string &path)
        {
            return request(http::POST, path);
        }

        http_client &http_client::put(const string &path)
        {
            return request(http::PUT, path);
        }

        http_client &http_client::de1ete(const string &path)
        {
            return request(http::DELETE, path);
        }
    }
}
<|endoftext|>