<commit_before>//--------------------------------------------------------------------------------------
// File: MeshOBJ.cpp
//
// Helper code for loading Mesh data from Wavefront OBJ
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkID=324981
// http://go.microsoft.com/fwlink/?LinkID=512686
//--------------------------------------------------------------------------------------

#pragma warning(push)
#pragma warning(disable : 4005)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define NODRAWTEXT
#define NOGDI
#define NOMCX
#define NOSERVICE
#define NOHELP
#pragma warning(pop)

#include "Mesh.h"
#include "WaveFrontReader.h"

#include <cwchar>
#include <iterator>
#include <new>

using namespace DirectX;

namespace
{
    std::wstring ProcessTextureFileName(const wchar_t* inName, bool dds)
    {
        if (!inName || !*inName)
            return std::wstring();

        wchar_t txext[_MAX_EXT] = {};
        wchar_t txfname[_MAX_FNAME] = {};
        _wsplitpath_s(inName, nullptr, 0, nullptr, 0, txfname, _MAX_FNAME, txext, _MAX_EXT);

        if (dds)
        {
            wcscpy_s(txext, L".dds");
        }

        wchar_t texture[_MAX_PATH] = {};
        _wmakepath_s(texture, nullptr, nullptr, txfname, txext);
        return std::wstring(texture);
    }
}

//--------------------------------------------------------------------------------------
HRESULT LoadFromOBJ(
    const wchar_t* szFilename,
    std::unique_ptr<Mesh>& inMesh,
    std::vector<Mesh::Material>& inMaterial,
    bool ccw,
    bool dds)
{
    WaveFrontReader<uint32_t> wfReader;
    HRESULT hr = wfReader.Load(szFilename, ccw);
    if (FAILED(hr))
        return hr;

    inMesh.reset(new (std::nothrow) Mesh);
    if (!inMesh)
        return E_OUTOFMEMORY;

    if (wfReader.indices.empty() || wfReader.vertices.empty())
        return E_FAIL;

    hr = inMesh->SetIndexData(wfReader.indices.size() / 3, wfReader.indices.data(),
        wfReader.attributes.empty() ? nullptr : wfReader.attributes.data());
    if (FAILED(hr))
        return hr;

    static const D3D11_INPUT_ELEMENT_DESC s_vboLayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    static const D3D11_INPUT_ELEMENT_DESC s_vboLayoutAlt[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    const D3D11_INPUT_ELEMENT_DESC* layout = s_vboLayout;
    size_t nDecl = std::size(s_vboLayout);

    if (!wfReader.hasNormals && !wfReader.hasTexcoords)
    {
        nDecl = 1;
    }
    else if (wfReader.hasNormals && !wfReader.hasTexcoords)
    {
        nDecl = 2;
    }
    else if (!wfReader.hasNormals && wfReader.hasTexcoords)
    {
        layout = s_vboLayoutAlt;
        nDecl = std::size(s_vboLayoutAlt);
    }

    VBReader vbr;
    hr = vbr.Initialize(layout, nDecl);
    if (FAILED(hr))
        return hr;

    hr = vbr.AddStream(wfReader.vertices.data(), wfReader.vertices.size(), 0, sizeof(WaveFrontReader<uint32_t>::Vertex));
    if (FAILED(hr))
        return hr;

    hr = inMesh->SetVertexData(vbr, wfReader.vertices.size());
    if (FAILED(hr))
        return hr;

    if (!wfReader.materials.empty())
    {
        inMaterial.clear();
        inMaterial.reserve(wfReader.materials.size());

        for (const auto& it : wfReader.materials)
        {
            Mesh::Material mtl = {};

            mtl.name = it.strName;
            mtl.specularPower = (it.bSpecular) ? float(it.nShininess) : 1.f;
            mtl.alpha = it.fAlpha;
            mtl.ambientColor = it.vAmbient;
            mtl.diffuseColor = it.vDiffuse;
            mtl.specularColor = (it.bSpecular) ? it.vSpecular : XMFLOAT3(0.f, 0.f, 0.f);
            mtl.emissiveColor = (it.bEmissive) ? it.vEmissive : XMFLOAT3(0.f, 0.f, 0.f);

            mtl.texture = ProcessTextureFileName(it.strTexture, dds);
            mtl.normalTexture = ProcessTextureFileName(it.strNormalTexture, dds);
            mtl.specularTexture = ProcessTextureFileName(it.strSpecularTexture, dds);
            if (it.bEmissive)
            {
                mtl.emissiveTexture = ProcessTextureFileName(it.strEmissiveTexture, dds);
            }
            mtl.rmaTexture = ProcessTextureFileName(it.strRMATexture, dds);

            inMaterial.push_back(mtl);
        }
    }

    if (wfReader.materials.size() > 1)
    {
        inMesh->SetMTLFileName(wfReader.name);
    }

    return S_OK;
}

//--------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Mesh::ExportToOBJ(const wchar_t* szFileName, size_t nMaterials, const Material* materials) const
{
    if (!szFileName)
        return E_INVALIDARG;

    if (nMaterials > 0 && !materials)
        return E_INVALIDARG;

    std::wofstream os;
    os.open(szFileName);
    if (!os)
        return E_FAIL;

    os << L"# " << szFileName << std::endl << L"#" << std::endl << std::endl;

    ExportToOBJ(os, nMaterials, materials);

    os.close();

    return (os.bad()) ? E_FAIL : S_OK;
}

_Use_decl_annotations_
void Mesh::ExportToOBJ(std::wostream& os, size_t nMaterials, const Material* materials) const
{
    if (!mtlFileName.empty())
        os << L"mtllib ./" << mtlFileName << L".mtl" << std::endl;

    for (size_t vert = 0; vert < mnVerts; ++vert)
    {
        os << L"v " << mPositions[vert].x << L" " << mPositions[vert].y << L" " << mPositions[vert].z << std::endl;
    }
    os << std::endl;

    if (mTexCoords)
    {
        for (size_t vert = 0; vert < mnVerts; ++vert)
        {
            os << L"vt " << mTexCoords[vert].x << L" " << mTexCoords[vert].y << std::endl;
        }
        os << std::endl;
    }

    if (mNormals)
    {
        for (size_t vert = 0; vert < mnVerts; ++vert)
        {
            os << L"vn " << mNormals[vert].x << L" " << mNormals[vert].y << L" " << mNormals[vert].z << std::endl;
        }
        os << std::endl;
    }

    // Using the first material entry as they are all the same for our use cases
    if (!materials || !mAttributes)
    {
        os << L"usemtl default" << std::endl;
    }

    /// Now the faces, a face is the first 3 indexes in indexes on the faces vertex
    uint32_t lastAttribute = uint32_t(-1);
    for (size_t face = 0; face < mnFaces; ++face)
    {
        if (mAttributes && mAttributes[face] != lastAttribute)
        {
            lastAttribute = mAttributes[face];
            if (lastAttribute < nMaterials)
            {
                os << L"usemtl " << materials[lastAttribute].name << std::endl;
            }
        }

        os << L"f ";
        for (size_t point = 0; point < 3; ++point)
        {
            uint32_t i = mIndices[face * 3 + point] + 1;

            os << i << L"/";
            if (mTexCoords)
                os << i;
            os << L"/";
            if (mNormals)
                os << i;
            os << L" ";
        }
        os << std::endl;
    }
}
<commit_msg>Fix locale issue when writing WaveFront OBJ files<commit_after>//--------------------------------------------------------------------------------------
// File: MeshOBJ.cpp
//
// Helper code for loading Mesh data from Wavefront OBJ
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkID=324981
// http://go.microsoft.com/fwlink/?LinkID=512686
//--------------------------------------------------------------------------------------

#pragma warning(push)
#pragma warning(disable : 4005)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define NODRAWTEXT
#define NOGDI
#define NOMCX
#define NOSERVICE
#define NOHELP
#pragma warning(pop)

#include "Mesh.h"
#include "WaveFrontReader.h"

#include <cwchar>
#include <iterator>
#include <locale>
#include <new>

using namespace DirectX;

namespace
{
    std::wstring ProcessTextureFileName(const wchar_t* inName, bool dds)
    {
        if (!inName || !*inName)
            return std::wstring();

        wchar_t txext[_MAX_EXT] = {};
        wchar_t txfname[_MAX_FNAME] = {};
        _wsplitpath_s(inName, nullptr, 0, nullptr, 0, txfname, _MAX_FNAME, txext, _MAX_EXT);

        if (dds)
        {
            wcscpy_s(txext, L".dds");
        }

        wchar_t texture[_MAX_PATH] = {};
        _wmakepath_s(texture, nullptr, nullptr, txfname, txext);
        return std::wstring(texture);
    }
}

//--------------------------------------------------------------------------------------
HRESULT LoadFromOBJ(
    const wchar_t* szFilename,
    std::unique_ptr<Mesh>& inMesh,
    std::vector<Mesh::Material>& inMaterial,
    bool ccw,
    bool dds)
{
    WaveFrontReader<uint32_t> wfReader;
    HRESULT hr = wfReader.Load(szFilename, ccw);
    if (FAILED(hr))
        return hr;

    inMesh.reset(new (std::nothrow) Mesh);
    if (!inMesh)
        return E_OUTOFMEMORY;

    if (wfReader.indices.empty() || wfReader.vertices.empty())
        return E_FAIL;

    hr = inMesh->SetIndexData(wfReader.indices.size() / 3, wfReader.indices.data(),
        wfReader.attributes.empty() ? nullptr : wfReader.attributes.data());
    if (FAILED(hr))
        return hr;

    static const D3D11_INPUT_ELEMENT_DESC s_vboLayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    static const D3D11_INPUT_ELEMENT_DESC s_vboLayoutAlt[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    const D3D11_INPUT_ELEMENT_DESC* layout = s_vboLayout;
    size_t nDecl = std::size(s_vboLayout);

    if (!wfReader.hasNormals && !wfReader.hasTexcoords)
    {
        nDecl = 1;
    }
    else if (wfReader.hasNormals && !wfReader.hasTexcoords)
    {
        nDecl = 2;
    }
    else if (!wfReader.hasNormals && wfReader.hasTexcoords)
    {
        layout = s_vboLayoutAlt;
        nDecl = std::size(s_vboLayoutAlt);
    }

    VBReader vbr;
    hr = vbr.Initialize(layout, nDecl);
    if (FAILED(hr))
        return hr;

    hr = vbr.AddStream(wfReader.vertices.data(), wfReader.vertices.size(), 0, sizeof(WaveFrontReader<uint32_t>::Vertex));
    if (FAILED(hr))
        return hr;

    hr = inMesh->SetVertexData(vbr, wfReader.vertices.size());
    if (FAILED(hr))
        return hr;

    if (!wfReader.materials.empty())
    {
        inMaterial.clear();
        inMaterial.reserve(wfReader.materials.size());

        for (const auto& it : wfReader.materials)
        {
            Mesh::Material mtl = {};

            mtl.name = it.strName;
            mtl.specularPower = (it.bSpecular) ? float(it.nShininess) : 1.f;
            mtl.alpha = it.fAlpha;
            mtl.ambientColor = it.vAmbient;
            mtl.diffuseColor = it.vDiffuse;
            mtl.specularColor = (it.bSpecular) ? it.vSpecular : XMFLOAT3(0.f, 0.f, 0.f);
            mtl.emissiveColor = (it.bEmissive) ? it.vEmissive : XMFLOAT3(0.f, 0.f, 0.f);

            mtl.texture = ProcessTextureFileName(it.strTexture, dds);
            mtl.normalTexture = ProcessTextureFileName(it.strNormalTexture, dds);
            mtl.specularTexture = ProcessTextureFileName(it.strSpecularTexture, dds);
            if (it.bEmissive)
            {
                mtl.emissiveTexture = ProcessTextureFileName(it.strEmissiveTexture, dds);
            }
            mtl.rmaTexture = ProcessTextureFileName(it.strRMATexture, dds);

            inMaterial.push_back(mtl);
        }
    }

    if (wfReader.materials.size() > 1)
    {
        inMesh->SetMTLFileName(wfReader.name);
    }

    return S_OK;
}

//--------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Mesh::ExportToOBJ(const wchar_t* szFileName, size_t nMaterials, const Material* materials) const
{
    if (!szFileName)
        return E_INVALIDARG;

    if (nMaterials > 0 && !materials)
        return E_INVALIDARG;

    std::wofstream os;
    os.open(szFileName);
    if (!os)
        return E_FAIL;

    os << L"# " << szFileName << std::endl << L"#" << std::endl << std::endl;

    ExportToOBJ(os, nMaterials, materials);

    os.close();

    return (os.bad()) ? E_FAIL : S_OK;
}

_Use_decl_annotations_
void Mesh::ExportToOBJ(std::wostream& os, size_t nMaterials, const Material* materials) const
{
    os.imbue(std::locale::classic());

    if (!mtlFileName.empty())
        os << L"mtllib ./" << mtlFileName << L".mtl" << std::endl;

    for (size_t vert = 0; vert < mnVerts; ++vert)
    {
        os << L"v " << mPositions[vert].x << L" " << mPositions[vert].y << L" " << mPositions[vert].z << std::endl;
    }
    os << std::endl;

    if (mTexCoords)
    {
        for (size_t vert = 0; vert < mnVerts; ++vert)
        {
            os << L"vt " << mTexCoords[vert].x << L" " << mTexCoords[vert].y << std::endl;
        }
        os << std::endl;
    }

    if (mNormals)
    {
        for (size_t vert = 0; vert < mnVerts; ++vert)
        {
            os << L"vn " << mNormals[vert].x << L" " << mNormals[vert].y << L" " << mNormals[vert].z << std::endl;
        }
        os << std::endl;
    }

    // Using the first material entry as they are all the same for our use cases
    if (!materials || !mAttributes)
    {
        os << L"usemtl default" << std::endl;
    }

    /// Now the faces, a face is the first 3 indexes in indexes on the faces vertex
    uint32_t lastAttribute = uint32_t(-1);
    for (size_t face = 0; face < mnFaces; ++face)
    {
        if (mAttributes && mAttributes[face] != lastAttribute)
        {
            lastAttribute = mAttributes[face];
            if (lastAttribute < nMaterials)
            {
                os << L"usemtl " << materials[lastAttribute].name << std::endl;
            }
        }

        os << L"f ";
        for (size_t point = 0; point < 3; ++point)
        {
            uint32_t i = mIndices[face * 3 + point] + 1;

            os << i << L"/";
            if (mTexCoords)
                os << i;
            os << L"/";
            if (mNormals)
                os << i;
            os << L" ";
        }
        os << std::endl;
    }
}
<|endoftext|>


<commit_before>/**
 * \file Core.cpp
 */

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

#include <ATK/Core/BaseFilter.h>
#include <ATK/Core/ComplexConvertFilter.h>
#include <ATK/Core/InPointerFilter.h>
#include <ATK/Core/OutPointerFilter.h>
#include <ATK/Core/PipelineGlobalSinkFilter.h>

namespace py = pybind11;

using namespace ATK;

namespace
{
  template<typename DataType_, typename DataType__ = DataType_>
  void populate_TypedBaseFilter(py::module& m, const char* type)
  {
    py::class_<TypedBaseFilter<DataType_, DataType__>, BaseFilter>(m, type)
      .def("get_output_array", [](TypedBaseFilter<DataType__>& instance, std::size_t port)
    {
      if (port >= instance.get_nb_output_ports())
      {
        throw std::length_error("No port with this number");
      }
      return py::array_t<DataType__>(instance.get_output_array_size(), instance.get_output_array(port));
    });
  }

  void create_base_filter(py::module& m)
  {
    py::class_<BaseFilter>(m, "BaseFilter")
      .def("set_input_port", &BaseFilter::set_input_port)
      .def("process", &BaseFilter::process)
      .def("full_setup", &BaseFilter::full_setup)
      .def_property("input_sampling_rate", &BaseFilter::get_input_sampling_rate, &BaseFilter::set_input_sampling_rate)
      .def_property("output_sampling_rate", &BaseFilter::get_output_sampling_rate, &BaseFilter::set_output_sampling_rate)
      .def_property("input_delay", &BaseFilter::get_input_delay, &BaseFilter::set_input_delay)
      .def_property("output_delay", &BaseFilter::get_output_delay, &BaseFilter::set_output_delay)
      .def_property("nb_input_ports", &BaseFilter::get_nb_input_ports, &BaseFilter::set_nb_input_ports)
      .def_property("nb_output_ports", &BaseFilter::get_nb_output_ports, &BaseFilter::set_nb_output_ports)
      .def_property("latency", &BaseFilter::get_latency, &BaseFilter::set_latency)
      .def_property_readonly("global_latency", &BaseFilter::get_global_latency);

    populate_TypedBaseFilter<int16_t>(m, "Int16TypedBaseFilter");
    populate_TypedBaseFilter<int32_t>(m, "Int32TypedBaseFilter");
    populate_TypedBaseFilter<int64_t>(m, "Int64TypedBaseFilter");
    populate_TypedBaseFilter<float>(m, "FloatTypedBaseFilter");
    populate_TypedBaseFilter<double>(m, "DoubleTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<float>>(m, "ComplexFloatTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<double>>(m, "ComplexDoubleTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<float>, float>(m, "ComplexFloatFloatTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<double>, double>(m, "ComplexDoubleDoubleTypedBaseFilter");
    populate_TypedBaseFilter<float, std::complex<float>>(m, "FloatComplexFloatTypedBaseFilter");
    populate_TypedBaseFilter<double, std::complex<double>>(m, "DoubleComplexDoubleTypedBaseFilter");
  }

  template<typename DataType>
  void populate_InPointerFilter(py::module& m, const char* type)
  {
    py::class_<InPointerFilter<DataType>, TypedBaseFilter<DataType>>(m, type)
      .def("__init__", [](InPointerFilter<DataType>& instance, const py::array_t<DataType>& array, bool interleaved) {
        std::size_t channels = 1;
        std::size_t size = array.shape(0);
        if(array.ndim() == 2)
        {
          channels = array.shape(0);
          size = array.shape(1);
        }
        new (&instance) InPointerFilter<DataType>(array.data(), channels, size, interleaved);
    }, py::arg().noconvert(), py::arg("interleaved") = false)
      .def("set_pointer", [](InPointerFilter<DataType>& instance, const py::array_t<DataType>& array)
    {
      std::size_t channels = 1;
      std::size_t size = array.shape(0);
      if(array.ndim() == 2)
      {
        channels = array.shape(0);
        size = array.shape(1);
      }
      if (channels != instance.get_nb_output_ports())
      {
        throw std::length_error("Wrong size for the number of channels");
      }
      instance.set_pointer(array.data(), array.ndim() == 2 ? array.shape(1) : array.shape(0));
    });
  }

  template<typename DataType>
  void populate_OutPointerFilter(py::module& m, const char* type)
  {
    py::class_<OutPointerFilter<DataType>, TypedBaseFilter<DataType>>(m, type)
      .def("__init__", [](OutPointerFilter<DataType>& instance, py::array_t<DataType>& array, bool interleaved) {
        std::size_t channels = 1;
        std::size_t size = array.shape(0);
        if(array.ndim() == 2)
        {
          channels = array.shape(0);
          size = array.shape(1);
        }
      new (&instance) OutPointerFilter<DataType>(array.mutable_data(), channels, size, interleaved);
    }, py::arg().noconvert(), py::arg("interleaved") = false)
      .def("set_pointer", [](OutPointerFilter<DataType>& instance, py::array_t<DataType>& array)
    {
      std::size_t channels = 1;
      std::size_t size = array.shape(0);
      if(array.ndim() == 2)
      {
        channels = array.shape(0);
        size = array.shape(1);
      }
      if (channels != instance.get_nb_output_ports())
      {
        throw std::length_error("Wrong size for the number of channels");
      }
      instance.set_pointer(array.mutable_data(), array.ndim() == 2 ? array.shape(1) : array.shape(0));
    });
  }

  template<typename DataType>
  void populate_ComplexToRealFilter(py::module& m, const char* type)
  {
    py::class_<ComplexToRealFilter<DataType>, TypedBaseFilter<std::complex<DataType>, DataType>>(m, type)
    .def(py::init<std::size_t>(), py::arg("nb_channels") = 1);
  }

  template<typename DataType>
  void populate_RealToComplexFilter(py::module& m, const char* type)
  {
    py::class_<RealToComplexFilter<DataType>, TypedBaseFilter<DataType, std::complex<DataType>>>(m, type)
    .def(py::init<std::size_t>(), py::arg("nb_channels") = 1);
  }
}

PYBIND11_PLUGIN(PythonCore) {
  py::module m("PythonCore", "Audio ToolKit Core module");

  create_base_filter(m);
  populate_InPointerFilter<int16_t>(m, "Int16InPointerFilter");
  populate_InPointerFilter<int32_t>(m, "Int32InPointerFilter");
  populate_InPointerFilter<int64_t>(m, "Int64InPointerFilter");
  populate_InPointerFilter<float>(m, "FloatInPointerFilter");
  populate_InPointerFilter<double>(m, "DoubleInPointerFilter");
  populate_InPointerFilter<std::complex<float>>(m, "ComplexFloatInPointerFilter");
  populate_InPointerFilter<std::complex<double>>(m, "ComplexDoubleInPointerFilter");
  populate_OutPointerFilter<int16_t>(m, "Int16OutPointerFilter");
  populate_OutPointerFilter<int32_t>(m, "Int32OutPointerFilter");
  populate_OutPointerFilter<int64_t>(m, "Int64OutPointerFilter");
  populate_OutPointerFilter<float>(m, "FloatOutPointerFilter");
  populate_OutPointerFilter<double>(m, "DoubleOutPointerFilter");
  populate_OutPointerFilter<std::complex<float>>(m, "ComplexFloatOutPointerFilter");
  populate_OutPointerFilter<std::complex<double>>(m, "ComplexDoubleOutPointerFilter");

  py::class_<PipelineGlobalSinkFilter, BaseFilter>(m, "PipelineGlobalSinkFilter")
    .def(py::init())
    .def("add_filter", &PipelineGlobalSinkFilter::add_filter)
    .def("remove_filter", &PipelineGlobalSinkFilter::remove_filter);

  populate_ComplexToRealFilter<float>(m, "FloatComplexToRealFilter");
  populate_ComplexToRealFilter<double>(m, "DoubleComplexToRealFilter");
  populate_RealToComplexFilter<float>(m, "FloatRealToComplexFilter");
  populate_RealToComplexFilter<double>(m, "DoubleRealToComplexFilter");

  return m.ptr();
}
<commit_msg>Get around the Python issues with gsl::not_null with lambdas<commit_after>/**
 * \file Core.cpp
 */

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

#include <ATK/Core/BaseFilter.h>
#include <ATK/Core/ComplexConvertFilter.h>
#include <ATK/Core/InPointerFilter.h>
#include <ATK/Core/OutPointerFilter.h>
#include <ATK/Core/PipelineGlobalSinkFilter.h>

namespace py = pybind11;

using namespace ATK;

namespace
{
  template<typename DataType_, typename DataType__ = DataType_>
  void populate_TypedBaseFilter(py::module& m, const char* type)
  {
    py::class_<TypedBaseFilter<DataType_, DataType__>, BaseFilter>(m, type)
      .def("get_output_array", [](TypedBaseFilter<DataType__>& instance, std::size_t port)
    {
      if (port >= instance.get_nb_output_ports())
      {
        throw std::length_error("No port with this number");
      }
      return py::array_t<DataType__>(instance.get_output_array_size(), instance.get_output_array(port));
    });
  }

  void create_base_filter(py::module& m)
  {
    py::class_<BaseFilter>(m, "BaseFilter")
    .def("set_input_port", [](BaseFilter& instance, std::size_t input_port, BaseFilter& filter, std::size_t output_port){instance.set_input_port(input_port, &filter, output_port);})
      .def("process", &BaseFilter::process)
      .def("full_setup", &BaseFilter::full_setup)
      .def_property("input_sampling_rate", &BaseFilter::get_input_sampling_rate, &BaseFilter::set_input_sampling_rate)
      .def_property("output_sampling_rate", &BaseFilter::get_output_sampling_rate, &BaseFilter::set_output_sampling_rate)
      .def_property("input_delay", &BaseFilter::get_input_delay, &BaseFilter::set_input_delay)
      .def_property("output_delay", &BaseFilter::get_output_delay, &BaseFilter::set_output_delay)
      .def_property("nb_input_ports", &BaseFilter::get_nb_input_ports, &BaseFilter::set_nb_input_ports)
      .def_property("nb_output_ports", &BaseFilter::get_nb_output_ports, &BaseFilter::set_nb_output_ports)
      .def_property("latency", &BaseFilter::get_latency, &BaseFilter::set_latency)
      .def_property_readonly("global_latency", &BaseFilter::get_global_latency);

    populate_TypedBaseFilter<int16_t>(m, "Int16TypedBaseFilter");
    populate_TypedBaseFilter<int32_t>(m, "Int32TypedBaseFilter");
    populate_TypedBaseFilter<int64_t>(m, "Int64TypedBaseFilter");
    populate_TypedBaseFilter<float>(m, "FloatTypedBaseFilter");
    populate_TypedBaseFilter<double>(m, "DoubleTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<float>>(m, "ComplexFloatTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<double>>(m, "ComplexDoubleTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<float>, float>(m, "ComplexFloatFloatTypedBaseFilter");
    populate_TypedBaseFilter<std::complex<double>, double>(m, "ComplexDoubleDoubleTypedBaseFilter");
    populate_TypedBaseFilter<float, std::complex<float>>(m, "FloatComplexFloatTypedBaseFilter");
    populate_TypedBaseFilter<double, std::complex<double>>(m, "DoubleComplexDoubleTypedBaseFilter");
  }

  template<typename DataType>
  void populate_InPointerFilter(py::module& m, const char* type)
  {
    py::class_<InPointerFilter<DataType>, TypedBaseFilter<DataType>>(m, type)
      .def("__init__", [](InPointerFilter<DataType>& instance, const py::array_t<DataType>& array, bool interleaved) {
        std::size_t channels = 1;
        std::size_t size = array.shape(0);
        if(array.ndim() == 2)
        {
          channels = array.shape(0);
          size = array.shape(1);
        }
        new (&instance) InPointerFilter<DataType>(array.data(), channels, size, interleaved);
    }, py::arg().noconvert(), py::arg("interleaved") = false)
      .def("set_pointer", [](InPointerFilter<DataType>& instance, const py::array_t<DataType>& array)
    {
      std::size_t channels = 1;
      std::size_t size = array.shape(0);
      if(array.ndim() == 2)
      {
        channels = array.shape(0);
        size = array.shape(1);
      }
      if (channels != instance.get_nb_output_ports())
      {
        throw std::length_error("Wrong size for the number of channels");
      }
      instance.set_pointer(array.data(), array.ndim() == 2 ? array.shape(1) : array.shape(0));
    });
  }

  template<typename DataType>
  void populate_OutPointerFilter(py::module& m, const char* type)
  {
    py::class_<OutPointerFilter<DataType>, TypedBaseFilter<DataType>>(m, type)
      .def("__init__", [](OutPointerFilter<DataType>& instance, py::array_t<DataType>& array, bool interleaved) {
        std::size_t channels = 1;
        std::size_t size = array.shape(0);
        if(array.ndim() == 2)
        {
          channels = array.shape(0);
          size = array.shape(1);
        }
      new (&instance) OutPointerFilter<DataType>(array.mutable_data(), channels, size, interleaved);
    }, py::arg().noconvert(), py::arg("interleaved") = false)
      .def("set_pointer", [](OutPointerFilter<DataType>& instance, py::array_t<DataType>& array)
    {
      std::size_t channels = 1;
      std::size_t size = array.shape(0);
      if(array.ndim() == 2)
      {
        channels = array.shape(0);
        size = array.shape(1);
      }
      if (channels != instance.get_nb_output_ports())
      {
        throw std::length_error("Wrong size for the number of channels");
      }
      instance.set_pointer(array.mutable_data(), array.ndim() == 2 ? array.shape(1) : array.shape(0));
    });
  }

  template<typename DataType>
  void populate_ComplexToRealFilter(py::module& m, const char* type)
  {
    py::class_<ComplexToRealFilter<DataType>, TypedBaseFilter<std::complex<DataType>, DataType>>(m, type)
    .def(py::init<std::size_t>(), py::arg("nb_channels") = 1);
  }

  template<typename DataType>
  void populate_RealToComplexFilter(py::module& m, const char* type)
  {
    py::class_<RealToComplexFilter<DataType>, TypedBaseFilter<DataType, std::complex<DataType>>>(m, type)
    .def(py::init<std::size_t>(), py::arg("nb_channels") = 1);
  }
}

PYBIND11_PLUGIN(PythonCore) {
  py::module m("PythonCore", "Audio ToolKit Core module");

  create_base_filter(m);
  populate_InPointerFilter<int16_t>(m, "Int16InPointerFilter");
  populate_InPointerFilter<int32_t>(m, "Int32InPointerFilter");
  populate_InPointerFilter<int64_t>(m, "Int64InPointerFilter");
  populate_InPointerFilter<float>(m, "FloatInPointerFilter");
  populate_InPointerFilter<double>(m, "DoubleInPointerFilter");
  populate_InPointerFilter<std::complex<float>>(m, "ComplexFloatInPointerFilter");
  populate_InPointerFilter<std::complex<double>>(m, "ComplexDoubleInPointerFilter");
  populate_OutPointerFilter<int16_t>(m, "Int16OutPointerFilter");
  populate_OutPointerFilter<int32_t>(m, "Int32OutPointerFilter");
  populate_OutPointerFilter<int64_t>(m, "Int64OutPointerFilter");
  populate_OutPointerFilter<float>(m, "FloatOutPointerFilter");
  populate_OutPointerFilter<double>(m, "DoubleOutPointerFilter");
  populate_OutPointerFilter<std::complex<float>>(m, "ComplexFloatOutPointerFilter");
  populate_OutPointerFilter<std::complex<double>>(m, "ComplexDoubleOutPointerFilter");

  py::class_<PipelineGlobalSinkFilter, BaseFilter>(m, "PipelineGlobalSinkFilter")
    .def(py::init())
    .def("add_filter", [](PipelineGlobalSinkFilter& instance, BaseFilter& filter){instance.add_filter(&filter);})
    .def("remove_filter", [](PipelineGlobalSinkFilter& instance, BaseFilter& filter){instance.remove_filter(&filter);});

  populate_ComplexToRealFilter<float>(m, "FloatComplexToRealFilter");
  populate_ComplexToRealFilter<double>(m, "DoubleComplexToRealFilter");
  populate_RealToComplexFilter<float>(m, "FloatRealToComplexFilter");
  populate_RealToComplexFilter<double>(m, "DoubleRealToComplexFilter");

  return m.ptr();
}
<|endoftext|>


<commit_before>/*
 * opencog/cython/PythonSCM.h
 *
 * Copyright (c) 2016 Linas Vepstas <linasvepstas@gmail.com>
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef _OPENCOG_PYTHON_SCM_H
#define _OPENCOG_PYTHON_SCM_H

#include <string>

namespace opencog
{
/** \addtogroup grp_smob
 *  @{
 */

class PythonSCM
{
private:
	static void* init_in_guile(void*);
	static void init_in_module(void*);
	void init(void);
public:
	PythonSCM();
	const std::string& eval(const std::string&);
}; // class

/** @}*/
}  // namespace

extern "C" {
void opencog_python_init(void);
};

#endif // _OPENCOG_PYTHON_SCM_H

#include <opencog/guile/SchemePrimitive.h>
#include <opencog/cython/PythonEval.h>

using namespace opencog;

PythonSCM::PythonSCM()
{
#ifdef HAVE_GUILE
	static bool is_init = false;
	if (is_init) return;
	is_init = true;
	scm_with_guile(init_in_guile, this);
#endif
}

void* PythonSCM::init_in_guile(void* self)
{
#ifdef HAVE_GUILE
	scm_c_define_module("opencog python", init_in_module, self);
	scm_c_use_module("opencog python");
#endif
	return NULL;
}

void PythonSCM::init_in_module(void* data)
{
	PythonSCM* self = (PythonSCM*) data;
	self->init();
}

void PythonSCM::init(void)
{
#ifdef HAVE_GUILE
	define_scheme_primitive("python-eval", &PythonSCM::eval, this, "python");
#endif
}

const std::string& PythonSCM::eval(const std::string& pystr)
{
	// This assumes that python is already initialized. If not,
	// I guess it creahes and burns...
	static PythonEval& pyev = PythonEval::instance();

	// This assumes that python is being invoked from a single thread.
	static std::string rv;
	rv = pyev.eval(pystr);
	return rv;
}

void opencog_python_init(void)
{
	static PythonSCM patty;
}
<commit_msg>Add a mutex to keep python happy.<commit_after>/*
 * opencog/cython/PythonSCM.h
 *
 * Copyright (c) 2016 Linas Vepstas <linasvepstas@gmail.com>
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef _OPENCOG_PYTHON_SCM_H
#define _OPENCOG_PYTHON_SCM_H

#include <string>

namespace opencog
{
/** \addtogroup grp_smob
 *  @{
 */

class PythonSCM
{
private:
	static void* init_in_guile(void*);
	static void init_in_module(void*);
	void init(void);
public:
	PythonSCM();
	const std::string& eval(const std::string&);
}; // class

/** @}*/
}  // namespace

extern "C" {
void opencog_python_init(void);
};

#endif // _OPENCOG_PYTHON_SCM_H

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

#include <mutex>

#include <opencog/guile/SchemePrimitive.h>
#include <opencog/cython/PythonEval.h>

using namespace opencog;

PythonSCM::PythonSCM()
{
#ifdef HAVE_GUILE
	static bool is_init = false;
	if (is_init) return;
	is_init = true;
	scm_with_guile(init_in_guile, this);
#endif
}

void* PythonSCM::init_in_guile(void* self)
{
#ifdef HAVE_GUILE
	scm_c_define_module("opencog python", init_in_module, self);
	scm_c_use_module("opencog python");
#endif
	return NULL;
}

void PythonSCM::init_in_module(void* data)
{
	PythonSCM* self = (PythonSCM*) data;
	self->init();
}

void PythonSCM::init(void)
{
#ifdef HAVE_GUILE
	define_scheme_primitive("python-eval", &PythonSCM::eval, this, "python");
#endif
}

const std::string& PythonSCM::eval(const std::string& pystr)
{
	// This assumes that python is already initialized. If not,
	// I guess it creahes and burns...
	static PythonEval& pyev = PythonEval::instance();
	static std::mutex pythr;
	static std::string rv;

	// Python is necessarily single-threaded. However, scheme is not,
	// so we don't know if we are being called from multiple threads.
	// So serialize access to the python evaluator.
	// XXX FIXME -- the const std::string& return value is not
	// protected!! WTF!! (this means there is a tiny race window).
	std::lock_guard<std::mutex> lock(pythr);
	rv = pyev.eval(pystr);
	return rv;
}

void opencog_python_init(void)
{
	static PythonSCM patty;
}
<|endoftext|>


<commit_before>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Contributions: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2014 - 2015 Intel Corporation.
 *
 * 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.
 */

#pragma once

#include "uart.h"
#include <stdexcept>

namespace mraa
{

/**
 * @brief API to UART (enabling only)
 *
 * This file defines the UART interface for libmraa
 */
class Uart
{
  public:
    /**
     * Uart Constructor, takes a pin number which will map directly to the
     * linux uart number, this 'enables' the uart, nothing more
     *
     * @param uart the index of the uart set to use
     */
    Uart(int uart)
    {
        m_uart = mraa_uart_init(uart);

        if (m_uart == NULL) {
            throw std::invalid_argument("Error initialising UART");
        }
    }
    /**
     * Uart destructor
     */
    ~Uart()
    {
        closeDevice();
        return;
    }

    /**
     * Get string with tty device path within Linux
     * For example. Could point to "/dev/ttyS0"
     *
     * @return char pointer of device path
     */
    std::string
    getDevicePath()
    {
        std::string ret_val(mraa_uart_get_dev_path(m_uart));
        return ret_val;
    }

    /**
     * Open the TTY device associated with a UART context, and set up the
     * terminal modes and baud rate.  The TTY is setup for a 'raw'
     * mode.  81N, no echo or special character handling, such as flow
     * control or line editing semantics.
     *
     * @param baud desired baud rate
     * @return mraa_result_t
     */
    mraa_result_t
    openDevice(unsigned int baud)
    {
        return mraa_uart_open_dev(m_uart, baud);
    }

    /**
     * Close a device previously opened with mraa_uart_open_dev().
     *
     * @param dev uart context
     * @return mraa_result_t
     */
    mraa_result_t
    closeDevice()
    {
        return mraa_uart_close_dev(m_uart);
    }

    /**
     * Read bytes from the device into a buffer
     *
     * @param buf buffer pointer
     * @param len maximum size of buffer
     * @return the number of bytes read, or -1 if an error occurred
     */
    int
    read(char* buf, size_t len)
    {
        return mraa_uart_read(m_uart, buf, len);
    }

    /**
     * Write bytes in buffer to a device
     *
     * @param buf buffer pointer
     * @param len maximum size of buffer
     * @return the number of bytes written, or -1 if an error occurred
     */
    int
    write(char* buf, size_t len)
    {
        return mraa_uart_write(m_uart, buf, len);
    }

    /**
     * Check to see if data is available on the device for reading
     *
     * @param millis number of milliseconds to wait, or 0 to return immediately
     * @return true if there is data available to read, false otherwise
     */
    bool
    dataAvailable(unsigned int millis = 0)
    {
        if (mraa_uart_data_available(m_uart, millis))
            return true;
        else
            return false;
    }

  private:
    mraa_uart_context m_uart;
};
}
<commit_msg>uart: change hpp, use new names of functions<commit_after>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Contributions: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2014 - 2015 Intel Corporation.
 *
 * 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.
 */

#pragma once

#include "uart.h"
#include <stdexcept>

namespace mraa
{

/**
 * @brief API to UART (enabling only)
 *
 * This file defines the UART interface for libmraa
 */
class Uart
{
  public:
    /**
     * Uart Constructor, takes a pin number which will map directly to the
     * linux uart number, this 'enables' the uart, nothing more
     *
     * @param uart the index of the uart set to use
     */
    Uart(int uart)
    {
        m_uart = mraa_uart_init(uart);

        if (m_uart == NULL) {
            throw std::invalid_argument("Error initialising UART");
        }
    }
    /**
     * Uart destructor
     */
    ~Uart()
    {
        stopDevice();
        return;
    }

    /**
     * Get string with tty device path within Linux
     * For example. Could point to "/dev/ttyS0"
     *
     * @return char pointer of device path
     */
    std::string
    getDevicePath()
    {
        std::string ret_val(mraa_uart_get_dev_path(m_uart));
        return ret_val;
    }

    /**
     * Open the TTY device associated with a UART context, and set up the
     * terminal modes and baud rate.  The TTY is setup for a 'raw'
     * mode.  81N, no echo or special character handling, such as flow
     * control or line editing semantics.
     *
     * @param baud desired baud rate
     * @return mraa_result_t
     */
    mraa_result_t
    openDevice(unsigned int baud)
    {
        return mraa_uart_open_dev(m_uart, baud);
    }

    /**
     * Close a device previously opened with mraa_uart_open_dev().
     *
     * @param dev uart context
     * @return mraa_result_t
     */
    mraa_result_t
    stopDevice()
    {
        return mraa_uart_stop(m_uart);
    }

    /**
     * Read bytes from the device into a buffer
     *
     * @param buf buffer pointer
     * @param len maximum size of buffer
     * @return the number of bytes read, or -1 if an error occurred
     */
    int
    read(char* buf, size_t len)
    {
        return mraa_uart_read(m_uart, buf, len);
    }

    /**
     * Write bytes in buffer to a device
     *
     * @param buf buffer pointer
     * @param len maximum size of buffer
     * @return the number of bytes written, or -1 if an error occurred
     */
    int
    write(char* buf, size_t len)
    {
        return mraa_uart_write(m_uart, buf, len);
    }

    /**
     * Check to see if data is available on the device for reading
     *
     * @param millis number of milliseconds to wait, or 0 to return immediately
     * @return true if there is data available to read, false otherwise
     */
    bool
    dataAvailable(unsigned int millis = 0)
    {
        if (mraa_uart_data_available(m_uart, millis))
            return true;
        else
            return false;
    }

  private:
    mraa_uart_context m_uart;
};
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed 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                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "OSPCommon.h"
#include "api/Device.h"

namespace ospray {

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void *malloc64(size_t size)
  {
    return ospcommon::alignedMalloc(size);
  }

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void free64(void *ptr)
  {
    return ospcommon::alignedFree(ptr);
  }

  WarnOnce::WarnOnce(const std::string &s, uint32_t postAtLogLevel)
    : s(s)
  {
    postErrorMsg(postAtLogLevel) << "Warning: "
                                 << s
                                 << " (only reporting first occurrence)";
  }

  /*! for debugging. compute a checksum for given area range... */
  void *computeCheckSum(const void *ptr, size_t numBytes)
  {
    long *end = (long *)((char *)ptr + (numBytes - (numBytes%8)));
    long *mem = (long *)ptr;
    long sum = 0;
    long i = 0;

    while (mem < end) {
      sum += (i+13) * *mem;
      ++i;
      ++mem;
    }
    return (void *)sum;
  }

  void removeArgs(int &ac, char **&av, int where, int howMany)
  {
    for (int i=where+howMany;i<ac;i++)
      av[i-howMany] = av[i];
    ac -= howMany;
  }

  void initFromCommandLine(int *_ac, const char ***_av)
  {
    auto &device = ospray::api::Device::current;

    if (_ac && _av) {
      int &ac = *_ac;
      char ** &av = *(char ***)_av;
      for (int i=1;i<ac;) {
        std::string parm = av[i];
        if (parm == "--osp:debug") {
          device->findParam("debug", true)->set(true);
          // per default enable logging to cout; may be overridden later
          device->error_fcn = [](const char *msg){ std::cout << msg; };
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:verbose") {
          device->findParam("logLevel", true)->set(1);
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:vv") {
          device->findParam("logLevel", true)->set(2);
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:loglevel") {
          device->findParam("logLevel", true)->set(atoi(av[i+1]));
          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:logoutput") {
          std::string dst = av[i+1];

          if (dst == "cout")
            device->error_fcn = [](const char *msg){ std::cout << msg; };
          else if (dst == "cerr")
            device->error_fcn = [](const char *msg){ std::cerr << msg; };
          else
            postErrorMsg("You must use 'cout' or 'cerr' for --osp:logoutput!");

          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:numthreads" || parm == "--osp:num-threads") {
          device->findParam("numThreads", true)->set(atoi(av[i+1]));
          removeArgs(ac,av,i,2);
        } else {
          ++i;
        }
      }
    }
  }

  size_t sizeOf(const OSPDataType type) {
    switch (type) {
    case OSP_VOID_PTR:
    case OSP_OBJECT:
    case OSP_CAMERA:
    case OSP_DATA:
    case OSP_DEVICE:
    case OSP_FRAMEBUFFER:
    case OSP_GEOMETRY:
    case OSP_LIGHT:
    case OSP_MATERIAL:
    case OSP_MODEL:
    case OSP_RENDERER:
    case OSP_TEXTURE:
    case OSP_TRANSFER_FUNCTION:
    case OSP_VOLUME:
    case OSP_PIXEL_OP:
    case OSP_STRING:    return sizeof(void *);
    case OSP_CHAR:      return sizeof(int8);
    case OSP_UCHAR:     return sizeof(uint8);
    case OSP_UCHAR2:    return sizeof(vec2uc);
    case OSP_UCHAR3:    return sizeof(vec3uc);
    case OSP_UCHAR4:    return sizeof(vec4uc);
    case OSP_SHORT:     return sizeof(int16);
    case OSP_USHORT:    return sizeof(uint16);
    case OSP_INT:       return sizeof(int32);
    case OSP_INT2:      return sizeof(vec2i);
    case OSP_INT3:      return sizeof(vec3i);
    case OSP_INT4:      return sizeof(vec4i);
    case OSP_UINT:      return sizeof(uint32);
    case OSP_UINT2:     return sizeof(vec2ui);
    case OSP_UINT3:     return sizeof(vec3ui);
    case OSP_UINT4:     return sizeof(vec4ui);
    case OSP_LONG:      return sizeof(int64);
    case OSP_LONG2:     return sizeof(vec2l);
    case OSP_LONG3:     return sizeof(vec3l);
    case OSP_LONG4:     return sizeof(vec4l);
    case OSP_ULONG:     return sizeof(uint64);
    case OSP_ULONG2:    return sizeof(vec2ul);
    case OSP_ULONG3:    return sizeof(vec3ul);
    case OSP_ULONG4:    return sizeof(vec4ul);
    case OSP_FLOAT:     return sizeof(float);
    case OSP_FLOAT2:    return sizeof(vec2f);
    case OSP_FLOAT3:    return sizeof(vec3f);
    case OSP_FLOAT4:    return sizeof(vec4f);
    case OSP_FLOAT3A:   return sizeof(vec3fa);
    case OSP_DOUBLE:    return sizeof(double);
    case OSP_UNKNOWN:   break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  OSPDataType typeForString(const char *string)
  {
    if (string == nullptr)             return(OSP_UNKNOWN);
    if (strcmp(string, "char"  ) == 0) return(OSP_CHAR);
    if (strcmp(string, "double") == 0) return(OSP_DOUBLE);
    if (strcmp(string, "float" ) == 0) return(OSP_FLOAT);
    if (strcmp(string, "float2") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float3") == 0) return(OSP_FLOAT3);
    if (strcmp(string, "float4") == 0) return(OSP_FLOAT4);
    if (strcmp(string, "int"   ) == 0) return(OSP_INT);
    if (strcmp(string, "int2"  ) == 0) return(OSP_INT2);
    if (strcmp(string, "int3"  ) == 0) return(OSP_INT3);
    if (strcmp(string, "int4"  ) == 0) return(OSP_INT4);
    if (strcmp(string, "uchar" ) == 0) return(OSP_UCHAR);
    if (strcmp(string, "uchar2") == 0) return(OSP_UCHAR2);
    if (strcmp(string, "uchar3") == 0) return(OSP_UCHAR3);
    if (strcmp(string, "uchar4") == 0) return(OSP_UCHAR4);
    if (strcmp(string, "short" ) == 0) return(OSP_SHORT);
    if (strcmp(string, "ushort") == 0) return(OSP_USHORT);
    if (strcmp(string, "uint"  ) == 0) return(OSP_UINT);
    if (strcmp(string, "uint2" ) == 0) return(OSP_UINT2);
    if (strcmp(string, "uint3" ) == 0) return(OSP_UINT3);
    if (strcmp(string, "uint4" ) == 0) return(OSP_UINT4);
    return(OSP_UNKNOWN);
  }

  std::string stringForType(OSPDataType type)
  {
    switch (type) {
    case OSP_VOID_PTR:          return "void_ptr";
    case OSP_OBJECT:            return "object";
    case OSP_CAMERA:            return "camera";
    case OSP_DATA:              return "data";
    case OSP_DEVICE:            return "device";
    case OSP_FRAMEBUFFER:       return "framebuffer";
    case OSP_GEOMETRY:          return "geometry";
    case OSP_LIGHT:             return "light";
    case OSP_MATERIAL:          return "material";
    case OSP_MODEL:             return "model";
    case OSP_RENDERER:          return "renderer";
    case OSP_TEXTURE:           return "texture";
    case OSP_TRANSFER_FUNCTION: return "transfer_function";
    case OSP_VOLUME:            return "volume";
    case OSP_PIXEL_OP:          return "pixel_op";
    case OSP_STRING:            return "string";
    case OSP_CHAR:              return "char";
    case OSP_UCHAR:             return "uchar";
    case OSP_UCHAR2:            return "uchar2";
    case OSP_UCHAR3:            return "uchar3";
    case OSP_UCHAR4:            return "uchar4";
    case OSP_SHORT:             return "short";
    case OSP_USHORT:            return "ushort";
    case OSP_INT:               return "int";
    case OSP_INT2:              return "int2";
    case OSP_INT3:              return "int3";
    case OSP_INT4:              return "int4";
    case OSP_UINT:              return "uint";
    case OSP_UINT2:             return "uint2";
    case OSP_UINT3:             return "uint3";
    case OSP_UINT4:             return "uint4";
    case OSP_LONG:              return "long";
    case OSP_LONG2:             return "long2";
    case OSP_LONG3:             return "long3";
    case OSP_LONG4:             return "long4";
    case OSP_ULONG:             return "ulong";
    case OSP_ULONG2:            return "ulong2";
    case OSP_ULONG3:            return "ulong3";
    case OSP_ULONG4:            return "ulong4";
    case OSP_FLOAT:             return "float";
    case OSP_FLOAT2:            return "float2";
    case OSP_FLOAT3:            return "float3";
    case OSP_FLOAT4:            return "float4";
    case OSP_FLOAT3A:           return "float3a";
    case OSP_DOUBLE:            return "double";
    case OSP_UNKNOWN:           break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  size_t sizeOf(const OSPTextureFormat type)
  {
    switch (type) {
      case OSP_TEXTURE_RGBA8:
      case OSP_TEXTURE_SRGBA:          return sizeof(uint32);
      case OSP_TEXTURE_RGBA32F:        return sizeof(vec4f);
      case OSP_TEXTURE_RGB8:
      case OSP_TEXTURE_SRGB:           return sizeof(vec3uc);
      case OSP_TEXTURE_RGB32F:         return sizeof(vec3f);
      case OSP_TEXTURE_R8:             return sizeof(uint8);
      case OSP_TEXTURE_R32F:           return sizeof(float);
      case OSP_TEXTURE_FORMAT_INVALID: break;
    }

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPTextureFormat "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  uint32_t logLevel()
  {
    return ospray::api::Device::current->logLevel;
  }

  int loadLocalModule(const std::string &name)
  {
    std::string libName = "ospray_module_" + name;
    loadLibrary(libName);

    std::string initSymName = "ospray_init_module_" + name;
    void*initSym = getSymbol(initSymName);
    if (!initSym) {
      throw std::runtime_error("#osp:api: could not find module initializer "
                               +initSymName);
    }

    void (*initMethod)() = (void(*)())initSym;

    //NOTE(jda) - don't use magic numbers!
    if (!initMethod)
      return 2;

    try {
      initMethod();
    } catch (...) {
      return 3;
    }

    return 0;
  }

  void postErrorMsg(const std::stringstream &msg, uint32_t postAtLogLevel)
  {
    postErrorMsg(msg.str(), postAtLogLevel);
  }

  void postErrorMsg(const std::string &msg, uint32_t postAtLogLevel)
  {
    if (logLevel() >= postAtLogLevel && ospray::api::Device::current.ptr)
      ospray::api::Device::current->error_fcn(msg.c_str());
  }

  ErrorMsgStream::ErrorMsgStream(uint32_t postAtLogLevel)
    : logLevel(postAtLogLevel)
  {
  }

  ErrorMsgStream::~ErrorMsgStream()
  {
    if (!msg.str().empty()) {
      msg << std::endl;
      postErrorMsg(msg, logLevel);
    }
  }

  ErrorMsgStream::ErrorMsgStream(ErrorMsgStream &&other)
  {
    msg      = std::move(other.msg);
    logLevel = other.logLevel;
  }

  ErrorMsgStream postErrorMsg(uint32_t postAtLogLevel)
  {
    return ErrorMsgStream(postAtLogLevel);
  }

} // ::ospray

<commit_msg>better fix for previous error<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed 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                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "OSPCommon.h"
#include "api/Device.h"

namespace ospray {

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void *malloc64(size_t size)
  {
    return ospcommon::alignedMalloc(size);
  }

  /*! 64-bit malloc. allows for alloc'ing memory larger than 64 bits */
  extern "C" void free64(void *ptr)
  {
    return ospcommon::alignedFree(ptr);
  }

  WarnOnce::WarnOnce(const std::string &s, uint32_t postAtLogLevel)
    : s(s)
  {
    postErrorMsg(postAtLogLevel) << "Warning: "
                                 << s
                                 << " (only reporting first occurrence)";
  }

  /*! for debugging. compute a checksum for given area range... */
  void *computeCheckSum(const void *ptr, size_t numBytes)
  {
    long *end = (long *)((char *)ptr + (numBytes - (numBytes%8)));
    long *mem = (long *)ptr;
    long sum = 0;
    long i = 0;

    while (mem < end) {
      sum += (i+13) * *mem;
      ++i;
      ++mem;
    }
    return (void *)sum;
  }

  void removeArgs(int &ac, char **&av, int where, int howMany)
  {
    for (int i=where+howMany;i<ac;i++)
      av[i-howMany] = av[i];
    ac -= howMany;
  }

  void initFromCommandLine(int *_ac, const char ***_av)
  {
    auto &device = ospray::api::Device::current;

    if (_ac && _av) {
      int &ac = *_ac;
      char ** &av = *(char ***)_av;
      for (int i=1;i<ac;) {
        std::string parm = av[i];
        if (parm == "--osp:debug") {
          device->findParam("debug", true)->set(true);
          // per default enable logging to cout; may be overridden later
          device->error_fcn = [](const char *msg){ std::cout << msg; };
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:verbose") {
          device->findParam("logLevel", true)->set(1);
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:vv") {
          device->findParam("logLevel", true)->set(2);
          removeArgs(ac,av,i,1);
        } else if (parm == "--osp:loglevel") {
          device->findParam("logLevel", true)->set(atoi(av[i+1]));
          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:logoutput") {
          std::string dst = av[i+1];

          if (dst == "cout")
            device->error_fcn = [](const char *msg){ std::cout << msg; };
          else if (dst == "cerr")
            device->error_fcn = [](const char *msg){ std::cerr << msg; };
          else
            postErrorMsg("You must use 'cout' or 'cerr' for --osp:logoutput!");

          removeArgs(ac,av,i,2);
        } else if (parm == "--osp:numthreads" || parm == "--osp:num-threads") {
          device->findParam("numThreads", true)->set(atoi(av[i+1]));
          removeArgs(ac,av,i,2);
        } else {
          ++i;
        }
      }
    }
  }

  size_t sizeOf(const OSPDataType type) {
    switch (type) {
    case OSP_VOID_PTR:
    case OSP_OBJECT:
    case OSP_CAMERA:
    case OSP_DATA:
    case OSP_DEVICE:
    case OSP_FRAMEBUFFER:
    case OSP_GEOMETRY:
    case OSP_LIGHT:
    case OSP_MATERIAL:
    case OSP_MODEL:
    case OSP_RENDERER:
    case OSP_TEXTURE:
    case OSP_TRANSFER_FUNCTION:
    case OSP_VOLUME:
    case OSP_PIXEL_OP:
    case OSP_STRING:    return sizeof(void *);
    case OSP_CHAR:      return sizeof(int8);
    case OSP_UCHAR:     return sizeof(uint8);
    case OSP_UCHAR2:    return sizeof(vec2uc);
    case OSP_UCHAR3:    return sizeof(vec3uc);
    case OSP_UCHAR4:    return sizeof(vec4uc);
    case OSP_SHORT:     return sizeof(int16);
    case OSP_USHORT:    return sizeof(uint16);
    case OSP_INT:       return sizeof(int32);
    case OSP_INT2:      return sizeof(vec2i);
    case OSP_INT3:      return sizeof(vec3i);
    case OSP_INT4:      return sizeof(vec4i);
    case OSP_UINT:      return sizeof(uint32);
    case OSP_UINT2:     return sizeof(vec2ui);
    case OSP_UINT3:     return sizeof(vec3ui);
    case OSP_UINT4:     return sizeof(vec4ui);
    case OSP_LONG:      return sizeof(int64);
    case OSP_LONG2:     return sizeof(vec2l);
    case OSP_LONG3:     return sizeof(vec3l);
    case OSP_LONG4:     return sizeof(vec4l);
    case OSP_ULONG:     return sizeof(uint64);
    case OSP_ULONG2:    return sizeof(vec2ul);
    case OSP_ULONG3:    return sizeof(vec3ul);
    case OSP_ULONG4:    return sizeof(vec4ul);
    case OSP_FLOAT:     return sizeof(float);
    case OSP_FLOAT2:    return sizeof(vec2f);
    case OSP_FLOAT3:    return sizeof(vec3f);
    case OSP_FLOAT4:    return sizeof(vec4f);
    case OSP_FLOAT3A:   return sizeof(vec3fa);
    case OSP_DOUBLE:    return sizeof(double);
    case OSP_UNKNOWN:   break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  OSPDataType typeForString(const char *string)
  {
    if (string == nullptr)             return(OSP_UNKNOWN);
    if (strcmp(string, "char"  ) == 0) return(OSP_CHAR);
    if (strcmp(string, "double") == 0) return(OSP_DOUBLE);
    if (strcmp(string, "float" ) == 0) return(OSP_FLOAT);
    if (strcmp(string, "float2") == 0) return(OSP_FLOAT2);
    if (strcmp(string, "float3") == 0) return(OSP_FLOAT3);
    if (strcmp(string, "float4") == 0) return(OSP_FLOAT4);
    if (strcmp(string, "int"   ) == 0) return(OSP_INT);
    if (strcmp(string, "int2"  ) == 0) return(OSP_INT2);
    if (strcmp(string, "int3"  ) == 0) return(OSP_INT3);
    if (strcmp(string, "int4"  ) == 0) return(OSP_INT4);
    if (strcmp(string, "uchar" ) == 0) return(OSP_UCHAR);
    if (strcmp(string, "uchar2") == 0) return(OSP_UCHAR2);
    if (strcmp(string, "uchar3") == 0) return(OSP_UCHAR3);
    if (strcmp(string, "uchar4") == 0) return(OSP_UCHAR4);
    if (strcmp(string, "short" ) == 0) return(OSP_SHORT);
    if (strcmp(string, "ushort") == 0) return(OSP_USHORT);
    if (strcmp(string, "uint"  ) == 0) return(OSP_UINT);
    if (strcmp(string, "uint2" ) == 0) return(OSP_UINT2);
    if (strcmp(string, "uint3" ) == 0) return(OSP_UINT3);
    if (strcmp(string, "uint4" ) == 0) return(OSP_UINT4);
    return(OSP_UNKNOWN);
  }

  std::string stringForType(OSPDataType type)
  {
    switch (type) {
    case OSP_VOID_PTR:          return "void_ptr";
    case OSP_OBJECT:            return "object";
    case OSP_CAMERA:            return "camera";
    case OSP_DATA:              return "data";
    case OSP_DEVICE:            return "device";
    case OSP_FRAMEBUFFER:       return "framebuffer";
    case OSP_GEOMETRY:          return "geometry";
    case OSP_LIGHT:             return "light";
    case OSP_MATERIAL:          return "material";
    case OSP_MODEL:             return "model";
    case OSP_RENDERER:          return "renderer";
    case OSP_TEXTURE:           return "texture";
    case OSP_TRANSFER_FUNCTION: return "transfer_function";
    case OSP_VOLUME:            return "volume";
    case OSP_PIXEL_OP:          return "pixel_op";
    case OSP_STRING:            return "string";
    case OSP_CHAR:              return "char";
    case OSP_UCHAR:             return "uchar";
    case OSP_UCHAR2:            return "uchar2";
    case OSP_UCHAR3:            return "uchar3";
    case OSP_UCHAR4:            return "uchar4";
    case OSP_SHORT:             return "short";
    case OSP_USHORT:            return "ushort";
    case OSP_INT:               return "int";
    case OSP_INT2:              return "int2";
    case OSP_INT3:              return "int3";
    case OSP_INT4:              return "int4";
    case OSP_UINT:              return "uint";
    case OSP_UINT2:             return "uint2";
    case OSP_UINT3:             return "uint3";
    case OSP_UINT4:             return "uint4";
    case OSP_LONG:              return "long";
    case OSP_LONG2:             return "long2";
    case OSP_LONG3:             return "long3";
    case OSP_LONG4:             return "long4";
    case OSP_ULONG:             return "ulong";
    case OSP_ULONG2:            return "ulong2";
    case OSP_ULONG3:            return "ulong3";
    case OSP_ULONG4:            return "ulong4";
    case OSP_FLOAT:             return "float";
    case OSP_FLOAT2:            return "float2";
    case OSP_FLOAT3:            return "float3";
    case OSP_FLOAT4:            return "float4";
    case OSP_FLOAT3A:           return "float3a";
    case OSP_DOUBLE:            return "double";
    case OSP_UNKNOWN:           break;
    };

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPDataType "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  size_t sizeOf(const OSPTextureFormat type)
  {
    switch (type) {
      case OSP_TEXTURE_RGBA8:
      case OSP_TEXTURE_SRGBA:          return sizeof(uint32);
      case OSP_TEXTURE_RGBA32F:        return sizeof(vec4f);
      case OSP_TEXTURE_RGB8:
      case OSP_TEXTURE_SRGB:           return sizeof(vec3uc);
      case OSP_TEXTURE_RGB32F:         return sizeof(vec3f);
      case OSP_TEXTURE_R8:             return sizeof(uint8);
      case OSP_TEXTURE_R32F:           return sizeof(float);
      case OSP_TEXTURE_FORMAT_INVALID: break;
    }

    std::stringstream error;
    error << __FILE__ << ":" << __LINE__ << ": unknown OSPTextureFormat "
          << (int)type;
    throw std::runtime_error(error.str());
  }

  uint32_t logLevel()
  {
    return ospray::api::Device::current->logLevel;
  }

  int loadLocalModule(const std::string &name)
  {
    std::string libName = "ospray_module_" + name;
    loadLibrary(libName);

    std::string initSymName = "ospray_init_module_" + name;
    void*initSym = getSymbol(initSymName);
    if (!initSym) {
      throw std::runtime_error("#osp:api: could not find module initializer "
                               +initSymName);
    }

    void (*initMethod)() = (void(*)())initSym;

    //NOTE(jda) - don't use magic numbers!
    if (!initMethod)
      return 2;

    try {
      initMethod();
    } catch (...) {
      return 3;
    }

    return 0;
  }

  void postErrorMsg(const std::stringstream &msg, uint32_t postAtLogLevel)
  {
    postErrorMsg(msg.str(), postAtLogLevel);
  }

  void postErrorMsg(const std::string &msg, uint32_t postAtLogLevel)
  {
    if (logLevel() >= postAtLogLevel && ospray::api::Device::current.ptr)
      ospray::api::Device::current->error_fcn(msg.c_str());
  }

  ErrorMsgStream::ErrorMsgStream(uint32_t postAtLogLevel)
    : logLevel(postAtLogLevel)
  {
  }

  ErrorMsgStream::~ErrorMsgStream()
  {
    if (!msg.str().empty()) {
      msg << std::endl;
      postErrorMsg(msg, logLevel);
    }
  }

  ErrorMsgStream::ErrorMsgStream(ErrorMsgStream &&other)
  {
    msg.str(other.msg.str());
    logLevel = other.logLevel;
  }

  ErrorMsgStream postErrorMsg(uint32_t postAtLogLevel)
  {
    return ErrorMsgStream(postAtLogLevel);
  }

} // ::ospray

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <osquery/core.h>
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/sql.h>

#include "osquery/sql/sqlite_util.h"
#include "osquery/sql/virtual_table.h"

namespace osquery {

using OpReg = QueryPlanner::Opcode::Register;

/// SQL provider for osquery internal/core.
REGISTER_INTERNAL(SQLiteSQLPlugin, "sql", "sql");

FLAG(string,
     disable_tables,
     "Not Specified",
     "Comma-delimited list of table names to be disabled");

using SQLiteDBInstanceRef = std::shared_ptr<SQLiteDBInstance>;

/**
 * @brief A map of SQLite status codes to their corresponding message string
 *
 * Details of this map are defined at: http://www.sqlite.org/c3ref/c_abort.html
 */
// clang-format off
const std::map<int, std::string> kSQLiteReturnCodes = {
    {0, "SQLITE_OK"},        {1, "SQLITE_ERROR"},       {2, "SQLITE_INTERNAL"},
    {3, "SQLITE_PERM"},      {4, "SQLITE_ABORT"},       {5, "SQLITE_BUSY"},
    {6, "SQLITE_LOCKED"},    {7, "SQLITE_NOMEM"},       {8, "SQLITE_READONLY"},
    {9, "SQLITE_INTERRUPT"}, {10, "SQLITE_IOERR"},      {11, "SQLITE_CORRUPT"},
    {12, "SQLITE_NOTFOUND"}, {13, "SQLITE_FULL"},       {14, "SQLITE_CANTOPEN"},
    {15, "SQLITE_PROTOCOL"}, {16, "SQLITE_EMPTY"},      {17, "SQLITE_SCHEMA"},
    {18, "SQLITE_TOOBIG"},   {19, "SQLITE_CONSTRAINT"}, {20, "SQLITE_MISMATCH"},
    {21, "SQLITE_MISUSE"},   {22, "SQLITE_NOLFS"},      {23, "SQLITE_AUTH"},
    {24, "SQLITE_FORMAT"},   {25, "SQLITE_RANGE"},      {26, "SQLITE_NOTADB"},
    {27, "SQLITE_NOTICE"},   {28, "SQLITE_WARNING"},    {100, "SQLITE_ROW"},
    {101, "SQLITE_DONE"},
};

const std::map<std::string, std::string> kMemoryDBSettings = {
    {"synchronous", "OFF"},      {"count_changes", "OFF"},
    {"default_temp_store", "0"}, {"auto_vacuum", "FULL"},
    {"journal_mode", "OFF"},     {"cache_size", "0"},
    {"page_count", "0"},
};
// clang-format on

#define OpComparator(x)                                                        \
  { x, QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE) }
#define Arithmetic(x)                                                          \
  { x, QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE) }

/**
 * @brief A map from opcode to pair of result register and resultant type.
 *
 * For most opcodes we can deduce a column type based on an interred input
 * to the opcode "function". These come in a few sets, arithmetic operators,
 * comparators, aggregates, and copies.
 */
const std::map<std::string, QueryPlanner::Opcode> kSQLOpcodes = {
    {"Concat", QueryPlanner::Opcode(OpReg::P3, TEXT_TYPE)},
    {"AggStep", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)},
    {"AggStep0", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)},
    {"Integer", QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE)},
    {"Int64", QueryPlanner::Opcode(OpReg::P2, BIGINT_TYPE)},
    {"String", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)},
    {"String8", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)},
    {"Or", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)},
    {"And", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)},

    // Arithmetic yields a BIGINT for safety.
    Arithmetic("BitAnd"),
    Arithmetic("BitAnd"),
    Arithmetic("BitOr"),
    Arithmetic("ShiftLeft"),
    Arithmetic("ShiftRight"),
    Arithmetic("Add"),
    Arithmetic("Subtract"),
    Arithmetic("Multiply"),
    Arithmetic("Divide"),
    Arithmetic("Remainder"),

    // Comparators result in booleans and are treated as INTEGERs.
    OpComparator("Not"),
    OpComparator("IsNull"),
    OpComparator("NotNull"),
    OpComparator("Ne"),
    OpComparator("Eq"),
    OpComparator("Gt"),
    OpComparator("Le"),
    OpComparator("Lt"),
    OpComparator("Ge"),
    OpComparator("IfNeg"),
    OpComparator("IfNotZero"),
};

std::string getStringForSQLiteReturnCode(int code) {
  if (kSQLiteReturnCodes.find(code) != kSQLiteReturnCodes.end()) {
    return kSQLiteReturnCodes.at(code);
  } else {
    std::ostringstream s;
    s << "Error: " << code << " is not a valid SQLite result code";
    return s.str();
  }
}

Status SQLiteSQLPlugin::query(const std::string& q, QueryData& results) const {
  auto dbc = SQLiteDBManager::get();
  auto result = queryInternal(q, results, dbc->db());
  dbc->clearAffectedTables();
  return result;
}

Status SQLiteSQLPlugin::getQueryColumns(const std::string& q,
                                        TableColumns& columns) const {
  auto dbc = SQLiteDBManager::get();
  return getQueryColumnsInternal(q, columns, dbc->db());
}

SQLInternal::SQLInternal(const std::string& q) {
  auto dbc = SQLiteDBManager::get();
  status_ = queryInternal(q, results_, dbc->db());

  // One of the advantages of using SQLInternal (aside from the Registry-bypass)
  // is the ability to "deep-inspect" the table attributes and actions.
  event_based_ = (dbc->getAttributes() & TableAttributes::EVENT_BASED) != 0;

  dbc->clearAffectedTables();
}

Status SQLiteSQLPlugin::attach(const std::string& name) {
  PluginResponse response;
  auto status =
      Registry::call("table", name, {{"action", "columns"}}, response);
  if (!status.ok()) {
    return status;
  }

  auto statement = columnDefinition(response);
  // Attach requests occurring via the plugin/registry APIs must act on the
  // primary database. To allow this, getConnection can explicitly request the
  // primary instance and avoid the contention decisions.
  auto dbc = SQLiteDBManager::getConnection(true);
  return attachTableInternal(name, statement, dbc);
}

void SQLiteSQLPlugin::detach(const std::string& name) {
  auto dbc = SQLiteDBManager::get();
  if (!dbc->isPrimary()) {
    return;
  }
  detachTableInternal(name, dbc->db());
}

SQLiteDBInstance::SQLiteDBInstance(sqlite3*& db, std::mutex& mtx)
    : db_(db), lock_(mtx, std::try_to_lock) {
  if (lock_.owns_lock()) {
    primary_ = true;
  } else {
    db_ = nullptr;
    VLOG(1) << "DBManager contention: opening transient SQLite database";
    init();
  }
}

static inline void openOptimized(sqlite3*& db) {
  sqlite3_open(":memory:", &db);

  std::string settings;
  for (const auto& setting : kMemoryDBSettings) {
    settings += "PRAGMA " + setting.first + "=" + setting.second + "; ";
  }
  sqlite3_exec(db, settings.c_str(), nullptr, nullptr, nullptr);

  // Register function extensions.
  registerMathExtensions(db);
  registerStringExtensions(db);
}

void SQLiteDBInstance::init() {
  primary_ = false;
  openOptimized(db_);
}

void SQLiteDBInstance::addAffectedTable(VirtualTableContent* table) {
  // An xFilter/scan was requested for this virtual table.
  affected_tables_.insert(std::make_pair(table->name, table));
}

TableAttributes SQLiteDBInstance::getAttributes() const {
  const SQLiteDBInstance* rdbc = this;
  if (isPrimary() && !managed_) {
    // Similarly to clearAffectedTables, the connection may be forwarded.
    rdbc = SQLiteDBManager::getConnection(true).get();
  }

  TableAttributes attributes = TableAttributes::NONE;
  for (const auto& table : rdbc->affected_tables_) {
    attributes = table.second->attributes | attributes;
  }
  return attributes;
}

void SQLiteDBInstance::clearAffectedTables() {
  if (isPrimary() && !managed_) {
    // A primary instance must forward clear requests to the DB manager's
    // 'connection' instance. This is a temporary primary instance.
    SQLiteDBManager::getConnection(true)->clearAffectedTables();
    return;
  }

  for (const auto& table : affected_tables_) {
    table.second->constraints.clear();
    table.second->cache.clear();
  }
  // Since the affected tables are cleared, there are no more affected tables.
  // There is no concept of compounding tables between queries.
  affected_tables_.clear();
}

SQLiteDBInstance::~SQLiteDBInstance() {
  if (!isPrimary()) {
    sqlite3_close(db_);
  } else {
    db_ = nullptr;
  }
}

SQLiteDBManager::SQLiteDBManager() : db_(nullptr) {
  sqlite3_soft_heap_limit64(1);
  setDisabledTables(Flag::getValue("disable_tables"));
}

bool SQLiteDBManager::isDisabled(const std::string& table_name) {
  const auto& element = instance().disabled_tables_.find(table_name);
  return (element != instance().disabled_tables_.end());
}

void SQLiteDBManager::setDisabledTables(const std::string& list) {
  const auto& tables = split(list, ",");
  disabled_tables_ =
      std::unordered_set<std::string>(tables.begin(), tables.end());
}

SQLiteDBInstanceRef SQLiteDBManager::getUnique() {
  auto instance = std::make_shared<SQLiteDBInstance>();
  attachVirtualTables(instance);
  return instance;
}

SQLiteDBInstanceRef SQLiteDBManager::getConnection(bool primary) {
  auto& self = instance();
  std::unique_lock<std::mutex> lock(self.create_mutex_);

  if (self.db_ == nullptr) {
    // Create primary SQLite DB instance.
    openOptimized(self.db_);
    self.connection_ = SQLiteDBInstanceRef(new SQLiteDBInstance(self.db_));
    attachVirtualTables(self.connection_);
  }

  // Internal usage may request the primary connection explicitly.
  if (primary) {
    return self.connection_;
  }

  // Create a 'database connection' for the managed database instance.
  auto instance = std::make_shared<SQLiteDBInstance>(self.db_, self.mutex_);
  if (!instance->isPrimary()) {
    attachVirtualTables(instance);
  }
  return instance;
}

SQLiteDBManager::~SQLiteDBManager() {
  connection_ = nullptr;
  if (db_ != nullptr) {
    sqlite3_close(db_);
    db_ = nullptr;
  }
}

QueryPlanner::QueryPlanner(const std::string& query, sqlite3* db) {
  QueryData plan;
  queryInternal("EXPLAIN QUERY PLAN " + query, plan, db);
  queryInternal("EXPLAIN " + query, program_, db);

  for (const auto& row : plan) {
    auto details = osquery::split(row.at("detail"));
    tables_.push_back(details[2]);
  }
}

Status QueryPlanner::applyTypes(TableColumns& columns) {
  std::map<size_t, ColumnType> column_types;
  for (const auto& row : program_) {
    if (row.at("opcode") == "ResultRow") {
      // The column parsing is finished.
      auto k = boost::lexical_cast<size_t>(row.at("p1"));
      for (const auto& type : column_types) {
        if (type.first - k < columns.size()) {
          std::get<1>(columns[type.first - k]) = type.second;
        }
      }
    }

    if (row.at("opcode") == "Copy") {
      // Copy P1 -> P1 + P3 into P2 -> P2 + P3.
      auto from = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      auto size = boost::lexical_cast<size_t>(row.at("p3"));
      for (size_t i = 0; i <= size; i++) {
        if (column_types.count(from + i)) {
          column_types[to + i] = std::move(column_types[from + i]);
          column_types.erase(from + i);
        }
      }
    }

    if (kSQLOpcodes.count(row.at("opcode"))) {
      const auto& op = kSQLOpcodes.at(row.at("opcode"));
      auto k = boost::lexical_cast<size_t>(row.at(Opcode::regString(op.reg)));
      column_types[k] = op.type;
    }
  }

  return Status(0);
}

int queryDataCallback(void* argument, int argc, char* argv[], char* column[]) {
  if (argument == nullptr) {
    VLOG(1) << "Query execution failed: received a bad callback argument";
    return SQLITE_MISUSE;
  }

  QueryData* qData = (QueryData*)argument;
  Row r;
  for (int i = 0; i < argc; i++) {
    if (column[i] != nullptr) {
      r[column[i]] = (argv[i] != nullptr) ? argv[i] : "";
    }
  }
  (*qData).push_back(std::move(r));
  return 0;
}

Status queryInternal(const std::string& q, QueryData& results, sqlite3* db) {
  char* err = nullptr;
  sqlite3_exec(db, q.c_str(), queryDataCallback, &results, &err);
  sqlite3_db_release_memory(db);
  if (err != nullptr) {
    auto error_string = std::string(err);
    sqlite3_free(err);
    return Status(1, "Error running query: " + error_string);
  }
  return Status(0, "OK");
}

Status getQueryColumnsInternal(const std::string& q,
                               TableColumns& columns,
                               sqlite3* db) {
  // Turn the query into a prepared statement
  sqlite3_stmt* stmt{nullptr};
  auto rc = sqlite3_prepare_v2(
      db, q.c_str(), static_cast<int>(q.length() + 1), &stmt, nullptr);
  if (rc != SQLITE_OK || stmt == nullptr) {
    if (stmt != nullptr) {
      sqlite3_finalize(stmt);
    }
    return Status(1, sqlite3_errmsg(db));
  }

  // Get column count
  auto num_columns = sqlite3_column_count(stmt);
  TableColumns results;
  results.reserve(num_columns);

  // Get column names and types
  Status status = Status();
  bool unknown_type = false;
  for (int i = 0; i < num_columns; ++i) {
    auto col_name = sqlite3_column_name(stmt, i);
    auto col_type = sqlite3_column_decltype(stmt, i);

    if (col_name == nullptr) {
      status = Status(1, "Could not get column type");
      break;
    }

    if (col_type == nullptr) {
      // Types are only returned for table columns (not expressions).
      col_type = "UNKNOWN";
      unknown_type = true;
    }
    results.push_back(std::make_tuple(
        col_name, columnTypeName(col_type), ColumnOptions::DEFAULT));
  }

  // An unknown type means we have to parse the plan and SQLite opcodes.
  if (unknown_type) {
    QueryPlanner planner(q, db);
    planner.applyTypes(results);
  }

  if (status.ok()) {
    columns = std::move(results);
  }

  sqlite3_finalize(stmt);
  return status;
}
}
<commit_msg>[#2809] Emit verbose warning on column collisions (#2810)<commit_after>/*
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <osquery/core.h>
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/sql.h>

#include "osquery/sql/sqlite_util.h"
#include "osquery/sql/virtual_table.h"

namespace osquery {

/// SQL provider for osquery internal/core.
REGISTER_INTERNAL(SQLiteSQLPlugin, "sql", "sql");

FLAG(string,
     disable_tables,
     "Not Specified",
     "Comma-delimited list of table names to be disabled");

DECLARE_string(nullvalue);

using OpReg = QueryPlanner::Opcode::Register;

using SQLiteDBInstanceRef = std::shared_ptr<SQLiteDBInstance>;

/**
 * @brief A map of SQLite status codes to their corresponding message string
 *
 * Details of this map are defined at: http://www.sqlite.org/c3ref/c_abort.html
 */
// clang-format off
const std::map<int, std::string> kSQLiteReturnCodes = {
    {0, "SQLITE_OK"},        {1, "SQLITE_ERROR"},       {2, "SQLITE_INTERNAL"},
    {3, "SQLITE_PERM"},      {4, "SQLITE_ABORT"},       {5, "SQLITE_BUSY"},
    {6, "SQLITE_LOCKED"},    {7, "SQLITE_NOMEM"},       {8, "SQLITE_READONLY"},
    {9, "SQLITE_INTERRUPT"}, {10, "SQLITE_IOERR"},      {11, "SQLITE_CORRUPT"},
    {12, "SQLITE_NOTFOUND"}, {13, "SQLITE_FULL"},       {14, "SQLITE_CANTOPEN"},
    {15, "SQLITE_PROTOCOL"}, {16, "SQLITE_EMPTY"},      {17, "SQLITE_SCHEMA"},
    {18, "SQLITE_TOOBIG"},   {19, "SQLITE_CONSTRAINT"}, {20, "SQLITE_MISMATCH"},
    {21, "SQLITE_MISUSE"},   {22, "SQLITE_NOLFS"},      {23, "SQLITE_AUTH"},
    {24, "SQLITE_FORMAT"},   {25, "SQLITE_RANGE"},      {26, "SQLITE_NOTADB"},
    {27, "SQLITE_NOTICE"},   {28, "SQLITE_WARNING"},    {100, "SQLITE_ROW"},
    {101, "SQLITE_DONE"},
};

const std::map<std::string, std::string> kMemoryDBSettings = {
    {"synchronous", "OFF"},      {"count_changes", "OFF"},
    {"default_temp_store", "0"}, {"auto_vacuum", "FULL"},
    {"journal_mode", "OFF"},     {"cache_size", "0"},
    {"page_count", "0"},
};
// clang-format on

#define OpComparator(x)                                                        \
  { x, QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE) }
#define Arithmetic(x)                                                          \
  { x, QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE) }

/**
 * @brief A map from opcode to pair of result register and resultant type.
 *
 * For most opcodes we can deduce a column type based on an interred input
 * to the opcode "function". These come in a few sets, arithmetic operators,
 * comparators, aggregates, and copies.
 */
const std::map<std::string, QueryPlanner::Opcode> kSQLOpcodes = {
    {"Concat", QueryPlanner::Opcode(OpReg::P3, TEXT_TYPE)},
    {"AggStep", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)},
    {"AggStep0", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)},
    {"Integer", QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE)},
    {"Int64", QueryPlanner::Opcode(OpReg::P2, BIGINT_TYPE)},
    {"String", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)},
    {"String8", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)},
    {"Or", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)},
    {"And", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)},

    // Arithmetic yields a BIGINT for safety.
    Arithmetic("BitAnd"),
    Arithmetic("BitAnd"),
    Arithmetic("BitOr"),
    Arithmetic("ShiftLeft"),
    Arithmetic("ShiftRight"),
    Arithmetic("Add"),
    Arithmetic("Subtract"),
    Arithmetic("Multiply"),
    Arithmetic("Divide"),
    Arithmetic("Remainder"),

    // Comparators result in booleans and are treated as INTEGERs.
    OpComparator("Not"),
    OpComparator("IsNull"),
    OpComparator("NotNull"),
    OpComparator("Ne"),
    OpComparator("Eq"),
    OpComparator("Gt"),
    OpComparator("Le"),
    OpComparator("Lt"),
    OpComparator("Ge"),
    OpComparator("IfNeg"),
    OpComparator("IfNotZero"),
};

std::string getStringForSQLiteReturnCode(int code) {
  if (kSQLiteReturnCodes.find(code) != kSQLiteReturnCodes.end()) {
    return kSQLiteReturnCodes.at(code);
  } else {
    std::ostringstream s;
    s << "Error: " << code << " is not a valid SQLite result code";
    return s.str();
  }
}

Status SQLiteSQLPlugin::query(const std::string& q, QueryData& results) const {
  auto dbc = SQLiteDBManager::get();
  auto result = queryInternal(q, results, dbc->db());
  dbc->clearAffectedTables();
  return result;
}

Status SQLiteSQLPlugin::getQueryColumns(const std::string& q,
                                        TableColumns& columns) const {
  auto dbc = SQLiteDBManager::get();
  return getQueryColumnsInternal(q, columns, dbc->db());
}

SQLInternal::SQLInternal(const std::string& q) {
  auto dbc = SQLiteDBManager::get();
  status_ = queryInternal(q, results_, dbc->db());

  // One of the advantages of using SQLInternal (aside from the Registry-bypass)
  // is the ability to "deep-inspect" the table attributes and actions.
  event_based_ = (dbc->getAttributes() & TableAttributes::EVENT_BASED) != 0;

  dbc->clearAffectedTables();
}

Status SQLiteSQLPlugin::attach(const std::string& name) {
  PluginResponse response;
  auto status =
      Registry::call("table", name, {{"action", "columns"}}, response);
  if (!status.ok()) {
    return status;
  }

  auto statement = columnDefinition(response);
  // Attach requests occurring via the plugin/registry APIs must act on the
  // primary database. To allow this, getConnection can explicitly request the
  // primary instance and avoid the contention decisions.
  auto dbc = SQLiteDBManager::getConnection(true);
  return attachTableInternal(name, statement, dbc);
}

void SQLiteSQLPlugin::detach(const std::string& name) {
  auto dbc = SQLiteDBManager::get();
  if (!dbc->isPrimary()) {
    return;
  }
  detachTableInternal(name, dbc->db());
}

SQLiteDBInstance::SQLiteDBInstance(sqlite3*& db, std::mutex& mtx)
    : db_(db), lock_(mtx, std::try_to_lock) {
  if (lock_.owns_lock()) {
    primary_ = true;
  } else {
    db_ = nullptr;
    VLOG(1) << "DBManager contention: opening transient SQLite database";
    init();
  }
}

static inline void openOptimized(sqlite3*& db) {
  sqlite3_open(":memory:", &db);

  std::string settings;
  for (const auto& setting : kMemoryDBSettings) {
    settings += "PRAGMA " + setting.first + "=" + setting.second + "; ";
  }
  sqlite3_exec(db, settings.c_str(), nullptr, nullptr, nullptr);

  // Register function extensions.
  registerMathExtensions(db);
  registerStringExtensions(db);
}

void SQLiteDBInstance::init() {
  primary_ = false;
  openOptimized(db_);
}

void SQLiteDBInstance::addAffectedTable(VirtualTableContent* table) {
  // An xFilter/scan was requested for this virtual table.
  affected_tables_.insert(std::make_pair(table->name, table));
}

TableAttributes SQLiteDBInstance::getAttributes() const {
  const SQLiteDBInstance* rdbc = this;
  if (isPrimary() && !managed_) {
    // Similarly to clearAffectedTables, the connection may be forwarded.
    rdbc = SQLiteDBManager::getConnection(true).get();
  }

  TableAttributes attributes = TableAttributes::NONE;
  for (const auto& table : rdbc->affected_tables_) {
    attributes = table.second->attributes | attributes;
  }
  return attributes;
}

void SQLiteDBInstance::clearAffectedTables() {
  if (isPrimary() && !managed_) {
    // A primary instance must forward clear requests to the DB manager's
    // 'connection' instance. This is a temporary primary instance.
    SQLiteDBManager::getConnection(true)->clearAffectedTables();
    return;
  }

  for (const auto& table : affected_tables_) {
    table.second->constraints.clear();
    table.second->cache.clear();
  }
  // Since the affected tables are cleared, there are no more affected tables.
  // There is no concept of compounding tables between queries.
  affected_tables_.clear();
}

SQLiteDBInstance::~SQLiteDBInstance() {
  if (!isPrimary()) {
    sqlite3_close(db_);
  } else {
    db_ = nullptr;
  }
}

SQLiteDBManager::SQLiteDBManager() : db_(nullptr) {
  sqlite3_soft_heap_limit64(1);
  setDisabledTables(Flag::getValue("disable_tables"));
}

bool SQLiteDBManager::isDisabled(const std::string& table_name) {
  const auto& element = instance().disabled_tables_.find(table_name);
  return (element != instance().disabled_tables_.end());
}

void SQLiteDBManager::setDisabledTables(const std::string& list) {
  const auto& tables = split(list, ",");
  disabled_tables_ =
      std::unordered_set<std::string>(tables.begin(), tables.end());
}

SQLiteDBInstanceRef SQLiteDBManager::getUnique() {
  auto instance = std::make_shared<SQLiteDBInstance>();
  attachVirtualTables(instance);
  return instance;
}

SQLiteDBInstanceRef SQLiteDBManager::getConnection(bool primary) {
  auto& self = instance();
  std::unique_lock<std::mutex> lock(self.create_mutex_);

  if (self.db_ == nullptr) {
    // Create primary SQLite DB instance.
    openOptimized(self.db_);
    self.connection_ = SQLiteDBInstanceRef(new SQLiteDBInstance(self.db_));
    attachVirtualTables(self.connection_);
  }

  // Internal usage may request the primary connection explicitly.
  if (primary) {
    return self.connection_;
  }

  // Create a 'database connection' for the managed database instance.
  auto instance = std::make_shared<SQLiteDBInstance>(self.db_, self.mutex_);
  if (!instance->isPrimary()) {
    attachVirtualTables(instance);
  }
  return instance;
}

SQLiteDBManager::~SQLiteDBManager() {
  connection_ = nullptr;
  if (db_ != nullptr) {
    sqlite3_close(db_);
    db_ = nullptr;
  }
}

QueryPlanner::QueryPlanner(const std::string& query, sqlite3* db) {
  QueryData plan;
  queryInternal("EXPLAIN QUERY PLAN " + query, plan, db);
  queryInternal("EXPLAIN " + query, program_, db);

  for (const auto& row : plan) {
    auto details = osquery::split(row.at("detail"));
    tables_.push_back(details[2]);
  }
}

Status QueryPlanner::applyTypes(TableColumns& columns) {
  std::map<size_t, ColumnType> column_types;
  for (const auto& row : program_) {
    if (row.at("opcode") == "ResultRow") {
      // The column parsing is finished.
      auto k = boost::lexical_cast<size_t>(row.at("p1"));
      for (const auto& type : column_types) {
        if (type.first - k < columns.size()) {
          std::get<1>(columns[type.first - k]) = type.second;
        }
      }
    }

    if (row.at("opcode") == "Copy") {
      // Copy P1 -> P1 + P3 into P2 -> P2 + P3.
      auto from = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      auto size = boost::lexical_cast<size_t>(row.at("p3"));
      for (size_t i = 0; i <= size; i++) {
        if (column_types.count(from + i)) {
          column_types[to + i] = std::move(column_types[from + i]);
          column_types.erase(from + i);
        }
      }
    }

    if (kSQLOpcodes.count(row.at("opcode"))) {
      const auto& op = kSQLOpcodes.at(row.at("opcode"));
      auto k = boost::lexical_cast<size_t>(row.at(Opcode::regString(op.reg)));
      column_types[k] = op.type;
    }
  }

  return Status(0);
}

int queryDataCallback(void* argument, int argc, char* argv[], char* column[]) {
  if (argument == nullptr) {
    VLOG(1) << "Query execution failed: received a bad callback argument";
    return SQLITE_MISUSE;
  }

  auto qData = static_cast<QueryData*>(argument);
  Row r;
  for (int i = 0; i < argc; i++) {
    if (column[i] != nullptr) {
      if (r.count(column[i])) {
        // Found a column name collision in the result.
        VLOG(1) << "Detected overloaded column name " << column[i]
                << " in query result consider using aliases";
      }
      r[column[i]] = (argv[i] != nullptr) ? argv[i] : FLAGS_nullvalue;
    }
  }
  (*qData).push_back(std::move(r));
  return 0;
}

Status queryInternal(const std::string& q, QueryData& results, sqlite3* db) {
  char* err = nullptr;
  sqlite3_exec(db, q.c_str(), queryDataCallback, &results, &err);
  sqlite3_db_release_memory(db);
  if (err != nullptr) {
    auto error_string = std::string(err);
    sqlite3_free(err);
    return Status(1, "Error running query: " + error_string);
  }
  return Status(0, "OK");
}

Status getQueryColumnsInternal(const std::string& q,
                               TableColumns& columns,
                               sqlite3* db) {
  // Turn the query into a prepared statement
  sqlite3_stmt* stmt{nullptr};
  auto rc = sqlite3_prepare_v2(
      db, q.c_str(), static_cast<int>(q.length() + 1), &stmt, nullptr);
  if (rc != SQLITE_OK || stmt == nullptr) {
    if (stmt != nullptr) {
      sqlite3_finalize(stmt);
    }
    return Status(1, sqlite3_errmsg(db));
  }

  // Get column count
  auto num_columns = sqlite3_column_count(stmt);
  TableColumns results;
  results.reserve(num_columns);

  // Get column names and types
  Status status = Status();
  bool unknown_type = false;
  for (int i = 0; i < num_columns; ++i) {
    auto col_name = sqlite3_column_name(stmt, i);
    auto col_type = sqlite3_column_decltype(stmt, i);

    if (col_name == nullptr) {
      status = Status(1, "Could not get column type");
      break;
    }

    if (col_type == nullptr) {
      // Types are only returned for table columns (not expressions).
      col_type = "UNKNOWN";
      unknown_type = true;
    }
    results.push_back(std::make_tuple(
        col_name, columnTypeName(col_type), ColumnOptions::DEFAULT));
  }

  // An unknown type means we have to parse the plan and SQLite opcodes.
  if (unknown_type) {
    QueryPlanner planner(q, db);
    planner.applyTypes(results);
  }

  if (status.ok()) {
    columns = std::move(results);
  }

  sqlite3_finalize(stmt);
  return status;
}
}
<|endoftext|>


<commit_before>#include "GPUSBVR.h"

#include <math.h>
#include <Basics/SysTools.h>
#include "../Controller/MasterController.h"

GPUSBVR::GPUSBVR(MasterController* pMasterController) :
	m_xRot(0),
	m_iCurrentView(0)
{
	m_pMasterController = pMasterController;

}

GPUSBVR::~GPUSBVR() {
}

void GPUSBVR::Initialize() {

	m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","");

	glClearColor(1,0,0,0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_CULL_FACE);

	m_IDTex[0] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin1x3.bmp").c_str());
	if (m_IDTex[0] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","First Image load failed");
	}
	m_IDTex[1] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin2x2.bmp").c_str());
	if (m_IDTex[1] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","Second Image load failed");
	}
	m_IDTex[2] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin1.bmp").c_str());
	if (m_IDTex[2] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","Third Image load failed");
	}
}

void GPUSBVR::Paint() {
//	m_pMasterController->DebugOut()->Message("GPUSBVR::Paint","");

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glTranslated(0.0, 0.0, -10.0);
	glRotated(m_xRot / 16.0, 1.0, 0.0, 0.0);

	m_IDTex[m_iCurrentView]->Bind();

	glBegin(GL_QUADS);
		glColor4d(1,1,1,1);
		glTexCoord2d(0,0);
		glVertex3d(-0.5,  0.5, 0.0);
		glTexCoord2d(1,0);
		glVertex3d( 0.5,  0.5, 0.0);
		glTexCoord2d(1,1);
		glVertex3d( 0.5, -0.5, 0.0);
		glTexCoord2d(0,1);
		glVertex3d(-0.5, -0.5, 0.0);
	glEnd();
}

void GPUSBVR::Resize(int width, int height) {
	m_pMasterController->DebugOut()->Message("GPUSBVR::Resize","");

	int side = std::min(width, height);
	glViewport((width - side) / 2, (height - side) / 2, side, side);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
	glMatrixMode(GL_MODELVIEW);
}

void GPUSBVR::Cleanup() {
//	glDeleteLists(object, 1);
}
<commit_msg><commit_after>#include "GPUSBVR.h"

#include <math.h>
#include <Basics/SysTools.h>
#include "../Controller/MasterController.h"

GPUSBVR::GPUSBVR(MasterController* pMasterController) :
	m_iCurrentView(0),
	m_xRot(0)
{
	m_pMasterController = pMasterController;
}

GPUSBVR::~GPUSBVR() {
}

void GPUSBVR::Initialize() {

	m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","");

	glClearColor(1,0,0,0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_CULL_FACE);

	m_IDTex[0] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin1x3.bmp").c_str());
	if (m_IDTex[0] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","First Image load failed");
	}
	m_IDTex[1] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin2x2.bmp").c_str());
	if (m_IDTex[1] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","Second Image load failed");
	}
	m_IDTex[2] = m_pMasterController->MemMan()->Load2DTextureFromFile(SysTools::GetFromResourceOnMac("RenderWin1.bmp").c_str());
	if (m_IDTex[2] == NULL) {
		m_pMasterController->DebugOut()->Message("GPUSBVR::Initialize","Third Image load failed");
	}
}

void GPUSBVR::Paint() {
//	m_pMasterController->DebugOut()->Message("GPUSBVR::Paint","");

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glTranslated(0.0, 0.0, -10.0);
	glRotated(m_xRot / 16.0, 1.0, 0.0, 0.0);

	m_IDTex[m_iCurrentView]->Bind();

	glBegin(GL_QUADS);
		glColor4d(1,1,1,1);
		glTexCoord2d(0,0);
		glVertex3d(-0.5,  0.5, 0.0);
		glTexCoord2d(1,0);
		glVertex3d( 0.5,  0.5, 0.0);
		glTexCoord2d(1,1);
		glVertex3d( 0.5, -0.5, 0.0);
		glTexCoord2d(0,1);
		glVertex3d(-0.5, -0.5, 0.0);
	glEnd();
}

void GPUSBVR::Resize(int width, int height) {
	m_pMasterController->DebugOut()->Message("GPUSBVR::Resize","");

	int side = std::min(width, height);
	glViewport((width - side) / 2, (height - side) / 2, side, side);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
	glMatrixMode(GL_MODELVIEW);
}

void GPUSBVR::Cleanup() {
//	glDeleteLists(object, 1);
}
<|endoftext|>