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

#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"

namespace angle
{

class SRGBTextureTest : public ANGLETest
{
  protected:
    SRGBTextureTest()
    {
        setWindowWidth(128);
        setWindowHeight(128);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
    }

    void SetUp() override
    {
        ANGLETest::SetUp();

        const std::string vs =
            "precision highp float;\n"
            "attribute vec4 position;\n"
            "varying vec2 texcoord;\n"
            "\n"
            "void main()\n"
            "{\n"
            "   gl_Position = vec4(position.xy, 0.0, 1.0);\n"
            "   texcoord = (position.xy * 0.5) + 0.5;\n"
            "}\n";

        const std::string fs =
            "precision highp float;\n"
            "uniform sampler2D tex;\n"
            "varying vec2 texcoord;\n"
            "\n"
            "void main()\n"
            "{\n"
            "   gl_FragColor = texture2D(tex, texcoord);\n"
            "}\n";

        mProgram = CompileProgram(vs, fs);
        ASSERT_NE(0u, mProgram);

        mTextureLocation = glGetUniformLocation(mProgram, "tex");
        ASSERT_NE(-1, mTextureLocation);
    }

    void TearDown() override
    {
        glDeleteProgram(mProgram);

        ANGLETest::TearDown();
    }

    GLuint mProgram        = 0;
    GLint mTextureLocation = -1;
};

TEST_P(SRGBTextureTest, SRGBValidation)
{
    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint tex = 0;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLubyte pixel[3] = { 0 };
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, 1, 1, 0, GL_SRGB, GL_UNSIGNED_BYTE, pixel);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();

        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_SRGB, GL_UNSIGNED_BYTE, pixel);
        EXPECT_GL_NO_ERROR();

        glGenerateMipmap(GL_TEXTURE_2D);
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteTextures(1, &tex);
}

TEST_P(SRGBTextureTest, SRGBAValidation)
{
    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint tex = 0;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLubyte pixel[4] = { 0 };
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, pixel);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();

        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, pixel);
        EXPECT_GL_NO_ERROR();

        glGenerateMipmap(GL_TEXTURE_2D);
        if (getClientMajorVersion() == 2)
        {
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
        }
        else
        {
            EXPECT_GL_NO_ERROR();
        }
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteTextures(1, &tex);
}

TEST_P(SRGBTextureTest, SRGBARenderbuffer)
{
    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint rbo = 0;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);

    glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8_EXT, 1, 1);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);

        // Make sure the rbo has a size for future tests
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
        EXPECT_GL_NO_ERROR();
    }

    GLuint fbo = 0;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
    EXPECT_GL_NO_ERROR();

    GLint colorEncoding = 0;
    glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                          GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, &colorEncoding);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(GL_SRGB_EXT, colorEncoding);
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteFramebuffers(1, &fbo);
    glDeleteRenderbuffers(1, &rbo);
}

// Verify that if the srgb decode extension is available, srgb textures are too
TEST_P(SRGBTextureTest, SRGBDecodeExtensionAvailability)
{
    bool hasSRGBDecode = extensionEnabled("GL_EXT_texture_sRGB_decode");
    if (hasSRGBDecode)
    {
        bool hasSRGBTextures = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() >= 3;
        EXPECT_TRUE(hasSRGBTextures);
    }
}

// Test basic functionality of SRGB decode using the texture parameter
TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
{
    // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
    if (IsOzone() && IsIntel() && IsOpenGLES())
    {
        std::cout << "Test skipped on Ozone Intel." << std::endl;
        return;
    }

    if (!extensionEnabled("GL_EXT_texture_sRGB_decode"))
    {
        std::cout << "Test skipped because GL_EXT_texture_sRGB_decode is not available."
                  << std::endl;
        return;
    }

    GLColor linearColor(64, 127, 191, 255);
    GLColor srgbColor(13, 54, 133, 255);

    GLTexture tex;
    glBindTexture(GL_TEXTURE_2D, tex.get());
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
                 &linearColor);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
    ASSERT_GL_NO_ERROR();

    glUseProgram(mProgram);
    glUniform1i(mTextureLocation, 0);

    glDisable(GL_DEPTH_TEST);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}

// Test basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter)
{
    if (!extensionEnabled("GL_EXT_texture_sRGB_decode") || getClientMajorVersion() < 3)
    {
        std::cout << "Test skipped because GL_EXT_texture_sRGB_decode or ES3 is not available."
                  << std::endl;
        return;
    }

    GLColor linearColor(64, 127, 191, 255);
    GLColor srgbColor(13, 54, 133, 255);

    GLTexture tex;
    glBindTexture(GL_TEXTURE_2D, tex.get());
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
                 &linearColor);
    ASSERT_GL_NO_ERROR();

    GLSampler sampler;
    glBindSampler(0, sampler.get());
    glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);

    glUseProgram(mProgram);
    glUniform1i(mTextureLocation, 0);

    glDisable(GL_DEPTH_TEST);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);

    glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}

// Test that mipmaps are generated correctly for sRGB textures
TEST_P(SRGBTextureTest, GenerateMipmaps)
{
    if (getClientMajorVersion() < 3)
    {
        std::cout << "Test skipped because ES3 is not available." << std::endl;
        return;
    }

    if (IsOpenGL() && (IsIntel() || IsAMD()))
    {
        std::cout << "Test skipped on Intel and AMD OpenGL drivers." << std::endl;
        return;
    }

    auto createAndReadBackTexture = [this](GLenum internalFormat, const GLColor &color) {
        constexpr GLsizei width  = 128;
        constexpr GLsizei height = 128;

        std::array<GLColor, width * height> buf;
        std::fill(buf.begin(), buf.end(), color);

        // Set up-left region of the texture as red color.
        // In order to make sure bi-linear interpolation operates on different colors, red region
        // is 1 pixel smaller than a quarter of the full texture on each side.
        constexpr GLsizei redWidth  = width / 2 - 1;
        constexpr GLsizei redHeight = height / 2 - 1;
        std::array<GLColor, redWidth * redHeight> redBuf;
        std::fill(redBuf.begin(), redBuf.end(), GLColor::red);

        GLTexture tex;
        glBindTexture(GL_TEXTURE_2D, tex.get());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                     buf.data());
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, redWidth, redHeight, GL_RGBA, GL_UNSIGNED_BYTE,
                        redBuf.data());
        glGenerateMipmap(GL_TEXTURE_2D);

        constexpr GLsizei drawWidth  = 32;
        constexpr GLsizei drawHeight = 32;
        glViewport(0, 0, drawWidth, drawHeight);

        drawQuad(mProgram, "position", 0.5f);

        std::array<GLColor, drawWidth * drawHeight> result;
        glReadPixels(0, 0, drawWidth, drawHeight, GL_RGBA, GL_UNSIGNED_BYTE, result.data());

        EXPECT_GL_NO_ERROR();

        return result;
    };

    GLColor srgbaColor(0, 63, 127, 255);
    auto srgbaReadback = createAndReadBackTexture(GL_SRGB8_ALPHA8, srgbaColor);

    GLColor linearColor(0, 13, 54, 255);
    auto rgbaReadback = createAndReadBackTexture(GL_RGBA8, linearColor);

    ASSERT_EQ(srgbaReadback.size(), rgbaReadback.size());
    for (size_t i = 0; i < srgbaReadback.size(); i++)
    {
        constexpr double tolerence = 7.0;
        EXPECT_COLOR_NEAR(srgbaReadback[i], rgbaReadback[i], tolerence);
    }
}

// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SRGBTextureTest,
                       ES2_D3D9(),
                       ES2_D3D11(),
                       ES3_D3D11(),
                       ES2_OPENGL(),
                       ES3_OPENGL(),
                       ES2_OPENGLES(),
                       ES3_OPENGLES());

} // namespace
<commit_msg>Skip the RGBTextureTest.SRGB[A]Validation test on Ozone.<commit_after>//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"

namespace angle
{

class SRGBTextureTest : public ANGLETest
{
  protected:
    SRGBTextureTest()
    {
        setWindowWidth(128);
        setWindowHeight(128);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
    }

    void SetUp() override
    {
        ANGLETest::SetUp();

        const std::string vs =
            "precision highp float;\n"
            "attribute vec4 position;\n"
            "varying vec2 texcoord;\n"
            "\n"
            "void main()\n"
            "{\n"
            "   gl_Position = vec4(position.xy, 0.0, 1.0);\n"
            "   texcoord = (position.xy * 0.5) + 0.5;\n"
            "}\n";

        const std::string fs =
            "precision highp float;\n"
            "uniform sampler2D tex;\n"
            "varying vec2 texcoord;\n"
            "\n"
            "void main()\n"
            "{\n"
            "   gl_FragColor = texture2D(tex, texcoord);\n"
            "}\n";

        mProgram = CompileProgram(vs, fs);
        ASSERT_NE(0u, mProgram);

        mTextureLocation = glGetUniformLocation(mProgram, "tex");
        ASSERT_NE(-1, mTextureLocation);
    }

    void TearDown() override
    {
        glDeleteProgram(mProgram);

        ANGLETest::TearDown();
    }

    GLuint mProgram        = 0;
    GLint mTextureLocation = -1;
};

TEST_P(SRGBTextureTest, SRGBValidation)
{
    // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
    if (IsOzone() && IsIntel() && IsOpenGLES())
    {
        std::cout << "Test skipped on Ozone Intel." << std::endl;
        return;
    }

    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint tex = 0;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLubyte pixel[3] = { 0 };
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, 1, 1, 0, GL_SRGB, GL_UNSIGNED_BYTE, pixel);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();

        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_SRGB, GL_UNSIGNED_BYTE, pixel);
        EXPECT_GL_NO_ERROR();

        glGenerateMipmap(GL_TEXTURE_2D);
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteTextures(1, &tex);
}

TEST_P(SRGBTextureTest, SRGBAValidation)
{
    // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
    if (IsOzone() && IsIntel() && IsOpenGLES())
    {
        std::cout << "Test skipped on Ozone Intel." << std::endl;
        return;
    }

    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint tex = 0;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLubyte pixel[4] = { 0 };
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, pixel);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();

        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, pixel);
        EXPECT_GL_NO_ERROR();

        glGenerateMipmap(GL_TEXTURE_2D);
        if (getClientMajorVersion() == 2)
        {
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
        }
        else
        {
            EXPECT_GL_NO_ERROR();
        }
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteTextures(1, &tex);
}

TEST_P(SRGBTextureTest, SRGBARenderbuffer)
{
    bool supported = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3;

    GLuint rbo = 0;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);

    glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8_ALPHA8_EXT, 1, 1);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);

        // Make sure the rbo has a size for future tests
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
        EXPECT_GL_NO_ERROR();
    }

    GLuint fbo = 0;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
    EXPECT_GL_NO_ERROR();

    GLint colorEncoding = 0;
    glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                          GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, &colorEncoding);
    if (supported)
    {
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(GL_SRGB_EXT, colorEncoding);
    }
    else
    {
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    }

    glDeleteFramebuffers(1, &fbo);
    glDeleteRenderbuffers(1, &rbo);
}

// Verify that if the srgb decode extension is available, srgb textures are too
TEST_P(SRGBTextureTest, SRGBDecodeExtensionAvailability)
{
    bool hasSRGBDecode = extensionEnabled("GL_EXT_texture_sRGB_decode");
    if (hasSRGBDecode)
    {
        bool hasSRGBTextures = extensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() >= 3;
        EXPECT_TRUE(hasSRGBTextures);
    }
}

// Test basic functionality of SRGB decode using the texture parameter
TEST_P(SRGBTextureTest, SRGBDecodeTextureParameter)
{
    // TODO(fjhenigman): Figure out why this fails on Ozone Intel.
    if (IsOzone() && IsIntel() && IsOpenGLES())
    {
        std::cout << "Test skipped on Ozone Intel." << std::endl;
        return;
    }

    if (!extensionEnabled("GL_EXT_texture_sRGB_decode"))
    {
        std::cout << "Test skipped because GL_EXT_texture_sRGB_decode is not available."
                  << std::endl;
        return;
    }

    GLColor linearColor(64, 127, 191, 255);
    GLColor srgbColor(13, 54, 133, 255);

    GLTexture tex;
    glBindTexture(GL_TEXTURE_2D, tex.get());
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
                 &linearColor);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
    ASSERT_GL_NO_ERROR();

    glUseProgram(mProgram);
    glUniform1i(mTextureLocation, 0);

    glDisable(GL_DEPTH_TEST);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}

// Test basic functionality of SRGB decode using the sampler parameter
TEST_P(SRGBTextureTest, SRGBDecodeSamplerParameter)
{
    if (!extensionEnabled("GL_EXT_texture_sRGB_decode") || getClientMajorVersion() < 3)
    {
        std::cout << "Test skipped because GL_EXT_texture_sRGB_decode or ES3 is not available."
                  << std::endl;
        return;
    }

    GLColor linearColor(64, 127, 191, 255);
    GLColor srgbColor(13, 54, 133, 255);

    GLTexture tex;
    glBindTexture(GL_TEXTURE_2D, tex.get());
    glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE,
                 &linearColor);
    ASSERT_GL_NO_ERROR();

    GLSampler sampler;
    glBindSampler(0, sampler.get());
    glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);

    glUseProgram(mProgram);
    glUniform1i(mTextureLocation, 0);

    glDisable(GL_DEPTH_TEST);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, srgbColor, 1.0);

    glSamplerParameteri(sampler.get(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
    drawQuad(mProgram, "position", 0.5f);

    EXPECT_PIXEL_COLOR_NEAR(0, 0, linearColor, 1.0);
}

// Test that mipmaps are generated correctly for sRGB textures
TEST_P(SRGBTextureTest, GenerateMipmaps)
{
    if (getClientMajorVersion() < 3)
    {
        std::cout << "Test skipped because ES3 is not available." << std::endl;
        return;
    }

    if (IsOpenGL() && (IsIntel() || IsAMD()))
    {
        std::cout << "Test skipped on Intel and AMD OpenGL drivers." << std::endl;
        return;
    }

    auto createAndReadBackTexture = [this](GLenum internalFormat, const GLColor &color) {
        constexpr GLsizei width  = 128;
        constexpr GLsizei height = 128;

        std::array<GLColor, width * height> buf;
        std::fill(buf.begin(), buf.end(), color);

        // Set up-left region of the texture as red color.
        // In order to make sure bi-linear interpolation operates on different colors, red region
        // is 1 pixel smaller than a quarter of the full texture on each side.
        constexpr GLsizei redWidth  = width / 2 - 1;
        constexpr GLsizei redHeight = height / 2 - 1;
        std::array<GLColor, redWidth * redHeight> redBuf;
        std::fill(redBuf.begin(), redBuf.end(), GLColor::red);

        GLTexture tex;
        glBindTexture(GL_TEXTURE_2D, tex.get());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                     buf.data());
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, redWidth, redHeight, GL_RGBA, GL_UNSIGNED_BYTE,
                        redBuf.data());
        glGenerateMipmap(GL_TEXTURE_2D);

        constexpr GLsizei drawWidth  = 32;
        constexpr GLsizei drawHeight = 32;
        glViewport(0, 0, drawWidth, drawHeight);

        drawQuad(mProgram, "position", 0.5f);

        std::array<GLColor, drawWidth * drawHeight> result;
        glReadPixels(0, 0, drawWidth, drawHeight, GL_RGBA, GL_UNSIGNED_BYTE, result.data());

        EXPECT_GL_NO_ERROR();

        return result;
    };

    GLColor srgbaColor(0, 63, 127, 255);
    auto srgbaReadback = createAndReadBackTexture(GL_SRGB8_ALPHA8, srgbaColor);

    GLColor linearColor(0, 13, 54, 255);
    auto rgbaReadback = createAndReadBackTexture(GL_RGBA8, linearColor);

    ASSERT_EQ(srgbaReadback.size(), rgbaReadback.size());
    for (size_t i = 0; i < srgbaReadback.size(); i++)
    {
        constexpr double tolerence = 7.0;
        EXPECT_COLOR_NEAR(srgbaReadback[i], rgbaReadback[i], tolerence);
    }
}

// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SRGBTextureTest,
                       ES2_D3D9(),
                       ES2_D3D11(),
                       ES3_D3D11(),
                       ES2_OPENGL(),
                       ES3_OPENGL(),
                       ES2_OPENGLES(),
                       ES3_OPENGLES());

} // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2014 Dims dev-team
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "internalMediumProvider.h"
#include "internalOperationsMedium.h"
#include "common/mediumKinds.h"
#include "bitcoinNodeMedium.h"

namespace tracker
{

CInternalMediumProvider * CInternalMediumProvider::ms_instance = NULL;

CInternalMediumProvider*
CInternalMediumProvider::getInstance( )
{
	if ( !ms_instance )
	{
		ms_instance = new CInternalMediumProvider();
	};
	return ms_instance;
}

CInternalMediumProvider::CInternalMediumProvider()
{
	m_mediums.push_back( CInternalOperationsMedium::getInstance() );
}

std::list< common::CMedium< TrackerResponses > *>
CInternalMediumProvider::provideConnection( int const _actionKind, unsigned _requestedConnectionNumber )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	if ( common::CMediumKinds::Internal == _actionKind )
		return m_mediums;
	else if ( common::CMediumKinds::BitcoinsNodes == _actionKind )
	{
		std::list< common::CMedium< TrackerResponses > *> mediums;

		std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator =  m_nodeToMedium.begin();
		//simplified  approach
		for ( unsigned int i = 0; ( i < vNodes.size() ) && ( i < _requestedConnectionNumber ); )
		{

			if ( iterator != m_nodeToMedium.end() )
			{
				// validate that node  is  still working??
				mediums.push_back( static_cast< common::CMedium< TrackerResponses > * >( iterator->second ) );
				iterator++;
				++i;
			}
			else
			{
				CNode * node = vNodes.at( i );
				m_nodeToMedium.insert( std::make_pair( node, new CBitcoinNodeMedium( node ) ) );
				//ugly
				iterator =  m_nodeToMedium.begin();
				std::advance( iterator, i );
			}

		}

		return mediums;
	}
	else
		return std::list< common::CMedium< TrackerResponses > *>();
}

void
CInternalMediumProvider::setResponse( CTransaction const & _response, CNode * _node )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator = m_nodeToMedium.find( _node );

	iterator->second->setResponse( _response );
}

void
CInternalMediumProvider::setResponse( CMerkleBlock const & _merkle, CNode * _node )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator = m_nodeToMedium.find( _node );

	iterator->second->setResponse( _merkle );
}

}
<commit_msg>try prevent  crash in synchronization mechanics<commit_after>// Copyright (c) 2014 Dims dev-team
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "internalMediumProvider.h"
#include "internalOperationsMedium.h"
#include "common/mediumKinds.h"
#include "bitcoinNodeMedium.h"

namespace tracker
{

CInternalMediumProvider * CInternalMediumProvider::ms_instance = NULL;

CInternalMediumProvider*
CInternalMediumProvider::getInstance( )
{
	if ( !ms_instance )
	{
		ms_instance = new CInternalMediumProvider();
	};
	return ms_instance;
}

CInternalMediumProvider::CInternalMediumProvider()
{
	m_mediums.push_back( CInternalOperationsMedium::getInstance() );
}

std::list< common::CMedium< TrackerResponses > *>
CInternalMediumProvider::provideConnection( int const _actionKind, unsigned _requestedConnectionNumber )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	if ( common::CMediumKinds::Internal == _actionKind )
		return m_mediums;
	else if ( common::CMediumKinds::BitcoinsNodes == _actionKind )
	{
		std::list< common::CMedium< TrackerResponses > *> mediums;

		std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator =  m_nodeToMedium.begin();
		//simplified  approach
		for ( unsigned int i = 0; ( i < vNodes.size() ) && ( i < _requestedConnectionNumber ); )
		{

			if ( iterator != m_nodeToMedium.end() )
			{
				// validate that node  is  still working??
				mediums.push_back( static_cast< common::CMedium< TrackerResponses > * >( iterator->second ) );
				iterator++;
				++i;
			}
			else
			{
				CNode * node = vNodes.at( i );
				m_nodeToMedium.insert( std::make_pair( node, new CBitcoinNodeMedium( node ) ) );
				//ugly
				iterator =  m_nodeToMedium.begin();
				std::advance( iterator, i );
			}

		}

		return mediums;
	}
	else
		return std::list< common::CMedium< TrackerResponses > *>();
}

void
CInternalMediumProvider::setResponse( CTransaction const & _response, CNode * _node )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator = m_nodeToMedium.find( _node );

	if( iterator == m_nodeToMedium.end() ) return;// not  asked

	iterator->second->setResponse( _response );
}

void
CInternalMediumProvider::setResponse( CMerkleBlock const & _merkle, CNode * _node )
{
	boost::lock_guard<boost::mutex> lock( m_mutex );

	std::map< CNode *, CBitcoinNodeMedium * >::iterator iterator = m_nodeToMedium.find( _node );

	if( iterator == m_nodeToMedium.end() ) return;// not  asked

	iterator->second->setResponse( _merkle );
}

}
<|endoftext|>


<commit_before>#include "FailSafeConfig.h"

FailSafeConfig::FailSafeConfig(QWidget *parent) : AP2ConfigWidget(parent)
{
    ui.setupUi(this);
    ui.radio1In->setName("Radio 1");
    ui.radio1In->setMin(800);
    ui.radio1In->setMax(2200);
    ui.radio1In->setOrientation(Qt::Horizontal);
    ui.radio2In->setName("Radio 2");
    ui.radio2In->setMin(800);
    ui.radio2In->setMax(2200);
    ui.radio2In->setOrientation(Qt::Horizontal);
    ui.radio3In->setName("Radio 3");
    ui.radio3In->setMin(800);
    ui.radio3In->setMax(2200);
    ui.radio3In->setOrientation(Qt::Horizontal);
    ui.radio4In->setName("Radio 4");
    ui.radio4In->setMin(800);
    ui.radio4In->setMax(2200);
    ui.radio4In->setOrientation(Qt::Horizontal);
    ui.radio5In->setName("Radio 5");
    ui.radio5In->setMin(800);
    ui.radio5In->setMax(2200);
    ui.radio5In->setOrientation(Qt::Horizontal);
    ui.radio6In->setName("Radio 6");
    ui.radio6In->setMin(800);
    ui.radio6In->setMax(2200);
    ui.radio6In->setOrientation(Qt::Horizontal);
    ui.radio7In->setName("Radio 7");
    ui.radio7In->setMin(800);
    ui.radio7In->setMax(2200);
    ui.radio7In->setOrientation(Qt::Horizontal);
    ui.radio8In->setName("Radio 8");
    ui.radio8In->setMin(800);
    ui.radio8In->setMax(2200);
    ui.radio8In->setOrientation(Qt::Horizontal);

    ui.radio1Out->setName("Radio 1");
    ui.radio1Out->setMin(800);
    ui.radio1Out->setMax(2200);
    ui.radio1Out->setOrientation(Qt::Horizontal);
    ui.radio2Out->setName("Radio 2");
    ui.radio2Out->setMin(800);
    ui.radio2Out->setMax(2200);
    ui.radio2Out->setOrientation(Qt::Horizontal);
    ui.radio3Out->setName("Radio 3");
    ui.radio3Out->setMin(800);
    ui.radio3Out->setMax(2200);
    ui.radio3Out->setOrientation(Qt::Horizontal);
    ui.radio4Out->setName("Radio 4");
    ui.radio4Out->setMin(800);
    ui.radio4Out->setMax(2200);
    ui.radio4Out->setOrientation(Qt::Horizontal);
    ui.radio5Out->setName("Radio 5");
    ui.radio5Out->setMin(800);
    ui.radio5Out->setMax(2200);
    ui.radio5Out->setOrientation(Qt::Horizontal);
    ui.radio6Out->setName("Radio 6");
    ui.radio6Out->setMin(800);
    ui.radio6Out->setMax(2200);
    ui.radio6Out->setOrientation(Qt::Horizontal);
    ui.radio7Out->setName("Radio 7");
    ui.radio7Out->setMin(800);
    ui.radio7Out->setMax(2200);
    ui.radio7Out->setOrientation(Qt::Horizontal);
    ui.radio8Out->setName("Radio 8");
    ui.radio8Out->setMin(800);
    ui.radio8Out->setMax(2200);
    ui.radio8Out->setOrientation(Qt::Horizontal);

    ui.throttleFailSafeComboBox->addItem("Disable");
    ui.throttleFailSafeComboBox->addItem("Enabled - Always TRL");
    ui.throttleFailSafeComboBox->addItem("Enabled - Continue in auto");

    connect(ui.batteryFailCheckBox,SIGNAL(clicked(bool)),this,SLOT(batteryFailChecked(bool)));
    connect(ui.fsLongCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsLongClicked(bool)));
    connect(ui.fsShortCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsShortClicked(bool)));
    connect(ui.gcsCheckBox,SIGNAL(clicked(bool)),this,SLOT(gcsChecked(bool)));
    connect(ui.throttleActionCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleActionChecked(bool)));
    connect(ui.throttleCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleChecked(bool)));
    connect(ui.throttlePwmSpinBox,SIGNAL(editingFinished()),this,SLOT(throttlePwmChanged()));
    connect(ui.throttleFailSafeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(throttleFailSafeChanged(int)));

    ui.armedLabel->setText("
DISARMED
");

    ui.modeLabel->setText("
MODE
");
    initConnections();
}
void FailSafeConfig::gcsChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_GCS_ENABL",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_GCS_ENABL",0);
    }
}

void FailSafeConfig::throttleActionChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"THR_FS_ACTION",1);
    }
    else
    {
        m_uas->setParameter(1,"THR_FS_ACTION",0);
    }
}

void FailSafeConfig::throttleChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"THR_FAILSAFE",1);
    }
    else
    {
        m_uas->setParameter(1,"THR_FAILSAFE",0);
    }
}

void FailSafeConfig::throttlePwmChanged()
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    m_uas->setParameter(1,"THR_FS_VALUE",ui.throttlePwmSpinBox->value());
}

void FailSafeConfig::throttleFailSafeChanged(int index)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    m_uas->setParameter(1,"FS_THR_ENABLE",index);
}

void FailSafeConfig::fsLongClicked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_LONG_ACTN",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_LONG_ACTN",0);
    }
}

void FailSafeConfig::fsShortClicked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_SHORT_ACTN",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_SHORT_ACTN",0);
    }
}

void FailSafeConfig::batteryFailChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_BATT_ENABLE",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_BATT_ENABLE",0);
    }
}

FailSafeConfig::~FailSafeConfig()
{
}
void FailSafeConfig::activeUASSet(UASInterface *uas)
{
    if (m_uas)
    {
        disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float)));
        disconnect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)));
        disconnect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool)));
    }
    AP2ConfigWidget::activeUASSet(uas);
    if (!uas)
    {
        return;
    }
    connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float)));
    connect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)));
    connect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool)));
    connect(m_uas,SIGNAL(gpsLocalizationChanged(UASInterface*,int)),this,SLOT(gpsStatusChanged(UASInterface*,int)));
    if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING)
    {
        ui.batteryFailCheckBox->setVisible(false);
        ui.throttleFailSafeComboBox->setVisible(false);
        ui.batteryVoltSpinBox->setVisible(false);
        ui.label_6->setVisible(false);

        ui.throttlePwmSpinBox->setVisible(true); //Both

        ui.throttleCheckBox->setVisible(true);
        ui.throttleActionCheckBox->setVisible(true);
        ui.gcsCheckBox->setVisible(true);
        ui.fsLongCheckBox->setVisible(true);
        ui.fsShortCheckBox->setVisible(true);
    }
    else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR)
    {
        ui.batteryFailCheckBox->setVisible(true);
        ui.throttleFailSafeComboBox->setVisible(true);
        ui.batteryVoltSpinBox->setVisible(true);
        ui.label_6->setVisible(true);

        ui.throttlePwmSpinBox->setVisible(true); //Both

        ui.throttleCheckBox->setVisible(false);
        ui.throttleActionCheckBox->setVisible(false);
        ui.gcsCheckBox->setVisible(false);
        ui.fsLongCheckBox->setVisible(false);
        ui.fsShortCheckBox->setVisible(false);
    }
    else
    {
        //Show all, just in case
        ui.batteryFailCheckBox->setVisible(true);
        ui.throttleFailSafeComboBox->setVisible(true);
        ui.batteryVoltSpinBox->setVisible(true);
        ui.throttlePwmSpinBox->setVisible(true); //Both
        ui.throttleCheckBox->setVisible(true);
        ui.throttleActionCheckBox->setVisible(true);
        ui.gcsCheckBox->setVisible(true);
        ui.fsLongCheckBox->setVisible(true);
        ui.fsShortCheckBox->setVisible(true);
    }

}
void FailSafeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value)
{
    //Arducopter
    if (parameterName == "FS_THR_ENABLE")
    {
        ui.throttleFailSafeComboBox->setCurrentIndex(value.toInt());
    }
    else if (parameterName == "FS_THR_VALUE")
    {
        ui.throttlePwmSpinBox->setValue(value.toFloat());
    }
    else if (parameterName == "FS_BATT_ENABLE")
    {
        if (value.toInt() == 0)
        {
            ui.batteryFailCheckBox->setChecked(false);
        }
        else
        {
            ui.batteryFailCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "LOW_VOLT")
    {
        ui.batteryVoltSpinBox->setValue(value.toFloat());
    }
    //Arduplane
    else if (parameterName == "THR_FAILSAFE")
    {
        if (value.toInt() == 0)
        {
            ui.throttleCheckBox->setChecked(false);
        }
        else
        {
            ui.throttleCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "THR_FS_VALUE")
    {
        ui.throttlePwmSpinBox->setValue(value.toFloat());
    }
    else if (parameterName == "THR_FS_ACTION")
    {
        if (value.toInt() == 0)
        {
            ui.throttleActionCheckBox->setChecked(false);
        }
        else
        {
            ui.throttleActionCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_GCS_ENABL")
    {
        if (value.toInt() == 0)
        {
            ui.gcsCheckBox->setChecked(false);
        }
        else
        {
            ui.gcsCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_SHORT_ACTN")
    {
        if (value.toInt() == 0)
        {
            ui.fsShortCheckBox->setChecked(false);
        }
        else
        {
            ui.fsShortCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_LONG_ACTN")
    {
        if (value.toInt() == 0)
        {
            ui.fsLongCheckBox->setChecked(false);
        }
        else
        {
            ui.fsLongCheckBox->setChecked(true);
        }
    }

}

void FailSafeConfig::armingChanged(bool armed)
{
    if (armed)
    {
        ui.armedLabel->setText("
ARMED
");
    }
    else
    {
        ui.armedLabel->setText("
DISARMED
");
    }
}

void FailSafeConfig::remoteControlChannelRawChanges(int chan,float value)
{
    if (chan == 0)
    {
        ui.radio1In->setValue(value);
    }
    else if (chan == 1)
    {
        ui.radio2In->setValue(value);
    }
    else if (chan == 2)
    {
        ui.radio3In->setValue(value);
    }
    else if (chan == 3)
    {
        ui.radio4In->setValue(value);
    }
    else if (chan == 4)
    {
        ui.radio5In->setValue(value);
    }
    else if (chan == 5)
    {
        ui.radio6In->setValue(value);
    }
    else if (chan == 6)
    {
        ui.radio7In->setValue(value);
    }
    else if (chan == 7)
    {
        ui.radio8In->setValue(value);
    }
}
void FailSafeConfig::hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8)
{
    ui.radio1Out->setValue(act1);
    ui.radio2Out->setValue(act2);
    ui.radio3Out->setValue(act3);
    ui.radio4Out->setValue(act4);
    ui.radio5Out->setValue(act5);
    ui.radio6Out->setValue(act6);
    ui.radio7Out->setValue(act7);
    ui.radio8Out->setValue(act8);
}
void FailSafeConfig::gpsStatusChanged(UASInterface* uas,int fixtype)
{
    if (fixtype == 0 || fixtype == 1)
    {
        ui.gpsLabel->setText("
None
");
    }
    else if (fixtype == 2)
    {
        ui.gpsLabel->setText("
2D Fix
");
    }
    else if (fixtype == 3)
    {
        ui.gpsLabel->setText("
3D Fix
");
    }
}
<commit_msg>Typographical error corrections<commit_after>#include "FailSafeConfig.h"

FailSafeConfig::FailSafeConfig(QWidget *parent) : AP2ConfigWidget(parent)
{
    ui.setupUi(this);
    ui.radio1In->setName("Radio 1");
    ui.radio1In->setMin(800);
    ui.radio1In->setMax(2200);
    ui.radio1In->setOrientation(Qt::Horizontal);
    ui.radio2In->setName("Radio 2");
    ui.radio2In->setMin(800);
    ui.radio2In->setMax(2200);
    ui.radio2In->setOrientation(Qt::Horizontal);
    ui.radio3In->setName("Radio 3");
    ui.radio3In->setMin(800);
    ui.radio3In->setMax(2200);
    ui.radio3In->setOrientation(Qt::Horizontal);
    ui.radio4In->setName("Radio 4");
    ui.radio4In->setMin(800);
    ui.radio4In->setMax(2200);
    ui.radio4In->setOrientation(Qt::Horizontal);
    ui.radio5In->setName("Radio 5");
    ui.radio5In->setMin(800);
    ui.radio5In->setMax(2200);
    ui.radio5In->setOrientation(Qt::Horizontal);
    ui.radio6In->setName("Radio 6");
    ui.radio6In->setMin(800);
    ui.radio6In->setMax(2200);
    ui.radio6In->setOrientation(Qt::Horizontal);
    ui.radio7In->setName("Radio 7");
    ui.radio7In->setMin(800);
    ui.radio7In->setMax(2200);
    ui.radio7In->setOrientation(Qt::Horizontal);
    ui.radio8In->setName("Radio 8");
    ui.radio8In->setMin(800);
    ui.radio8In->setMax(2200);
    ui.radio8In->setOrientation(Qt::Horizontal);

    ui.radio1Out->setName("Radio 1");
    ui.radio1Out->setMin(800);
    ui.radio1Out->setMax(2200);
    ui.radio1Out->setOrientation(Qt::Horizontal);
    ui.radio2Out->setName("Radio 2");
    ui.radio2Out->setMin(800);
    ui.radio2Out->setMax(2200);
    ui.radio2Out->setOrientation(Qt::Horizontal);
    ui.radio3Out->setName("Radio 3");
    ui.radio3Out->setMin(800);
    ui.radio3Out->setMax(2200);
    ui.radio3Out->setOrientation(Qt::Horizontal);
    ui.radio4Out->setName("Radio 4");
    ui.radio4Out->setMin(800);
    ui.radio4Out->setMax(2200);
    ui.radio4Out->setOrientation(Qt::Horizontal);
    ui.radio5Out->setName("Radio 5");
    ui.radio5Out->setMin(800);
    ui.radio5Out->setMax(2200);
    ui.radio5Out->setOrientation(Qt::Horizontal);
    ui.radio6Out->setName("Radio 6");
    ui.radio6Out->setMin(800);
    ui.radio6Out->setMax(2200);
    ui.radio6Out->setOrientation(Qt::Horizontal);
    ui.radio7Out->setName("Radio 7");
    ui.radio7Out->setMin(800);
    ui.radio7Out->setMax(2200);
    ui.radio7Out->setOrientation(Qt::Horizontal);
    ui.radio8Out->setName("Radio 8");
    ui.radio8Out->setMin(800);
    ui.radio8Out->setMax(2200);
    ui.radio8Out->setOrientation(Qt::Horizontal);

    ui.throttleFailSafeComboBox->addItem("Disable");
    ui.throttleFailSafeComboBox->addItem("Enabled - Always RTL");
    ui.throttleFailSafeComboBox->addItem("Enabled - Continue in auto");

    connect(ui.batteryFailCheckBox,SIGNAL(clicked(bool)),this,SLOT(batteryFailChecked(bool)));
    connect(ui.fsLongCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsLongClicked(bool)));
    connect(ui.fsShortCheckBox,SIGNAL(clicked(bool)),this,SLOT(fsShortClicked(bool)));
    connect(ui.gcsCheckBox,SIGNAL(clicked(bool)),this,SLOT(gcsChecked(bool)));
    connect(ui.throttleActionCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleActionChecked(bool)));
    connect(ui.throttleCheckBox,SIGNAL(clicked(bool)),this,SLOT(throttleChecked(bool)));
    connect(ui.throttlePwmSpinBox,SIGNAL(editingFinished()),this,SLOT(throttlePwmChanged()));
    connect(ui.throttleFailSafeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(throttleFailSafeChanged(int)));

    ui.armedLabel->setText("
DISARMED
");

    ui.modeLabel->setText("
MODE
");
    initConnections();
}
void FailSafeConfig::gcsChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_GCS_ENABL",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_GCS_ENABL",0);
    }
}

void FailSafeConfig::throttleActionChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"THR_FS_ACTION",1);
    }
    else
    {
        m_uas->setParameter(1,"THR_FS_ACTION",0);
    }
}

void FailSafeConfig::throttleChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"THR_FAILSAFE",1);
    }
    else
    {
        m_uas->setParameter(1,"THR_FAILSAFE",0);
    }
}

void FailSafeConfig::throttlePwmChanged()
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    m_uas->setParameter(1,"THR_FS_VALUE",ui.throttlePwmSpinBox->value());
}

void FailSafeConfig::throttleFailSafeChanged(int index)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    m_uas->setParameter(1,"FS_THR_ENABLE",index);
}

void FailSafeConfig::fsLongClicked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_LONG_ACTN",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_LONG_ACTN",0);
    }
}

void FailSafeConfig::fsShortClicked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_SHORT_ACTN",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_SHORT_ACTN",0);
    }
}

void FailSafeConfig::batteryFailChecked(bool checked)
{
    if (!m_uas)
    {
        showNullMAVErrorMessageBox();
        return;
    }
    if (checked)
    {
        m_uas->setParameter(1,"FS_BATT_ENABLE",1);
    }
    else
    {
        m_uas->setParameter(1,"FS_BATT_ENABLE",0);
    }
}

FailSafeConfig::~FailSafeConfig()
{
}
void FailSafeConfig::activeUASSet(UASInterface *uas)
{
    if (m_uas)
    {
        disconnect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float)));
        disconnect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)));
        disconnect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool)));
    }
    AP2ConfigWidget::activeUASSet(uas);
    if (!uas)
    {
        return;
    }
    connect(m_uas,SIGNAL(remoteControlChannelRawChanged(int,float)),this,SLOT(remoteControlChannelRawChanges(int,float)));
    connect(m_uas,SIGNAL(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)),this,SLOT(hilActuatorsChanged(uint64_t,float,float,float,float,float,float,float,float)));
    connect(m_uas,SIGNAL(armingChanged(bool)),this,SLOT(armingChanged(bool)));
    connect(m_uas,SIGNAL(gpsLocalizationChanged(UASInterface*,int)),this,SLOT(gpsStatusChanged(UASInterface*,int)));
    if (m_uas->getSystemType() == MAV_TYPE_FIXED_WING)
    {
        ui.batteryFailCheckBox->setVisible(false);
        ui.throttleFailSafeComboBox->setVisible(false);
        ui.batteryVoltSpinBox->setVisible(false);
        ui.label_6->setVisible(false);

        ui.throttlePwmSpinBox->setVisible(true); //Both

        ui.throttleCheckBox->setVisible(true);
        ui.throttleActionCheckBox->setVisible(true);
        ui.gcsCheckBox->setVisible(true);
        ui.fsLongCheckBox->setVisible(true);
        ui.fsShortCheckBox->setVisible(true);
    }
    else if (m_uas->getSystemType() == MAV_TYPE_QUADROTOR)
    {
        ui.batteryFailCheckBox->setVisible(true);
        ui.throttleFailSafeComboBox->setVisible(true);
        ui.batteryVoltSpinBox->setVisible(true);
        ui.label_6->setVisible(true);

        ui.throttlePwmSpinBox->setVisible(true); //Both

        ui.throttleCheckBox->setVisible(false);
        ui.throttleActionCheckBox->setVisible(false);
        ui.gcsCheckBox->setVisible(false);
        ui.fsLongCheckBox->setVisible(false);
        ui.fsShortCheckBox->setVisible(false);
    }
    else
    {
        //Show all, just in case
        ui.batteryFailCheckBox->setVisible(true);
        ui.throttleFailSafeComboBox->setVisible(true);
        ui.batteryVoltSpinBox->setVisible(true);
        ui.throttlePwmSpinBox->setVisible(true); //Both
        ui.throttleCheckBox->setVisible(true);
        ui.throttleActionCheckBox->setVisible(true);
        ui.gcsCheckBox->setVisible(true);
        ui.fsLongCheckBox->setVisible(true);
        ui.fsShortCheckBox->setVisible(true);
    }

}
void FailSafeConfig::parameterChanged(int uas, int component, QString parameterName, QVariant value)
{
    //Arducopter
    if (parameterName == "FS_THR_ENABLE")
    {
        ui.throttleFailSafeComboBox->setCurrentIndex(value.toInt());
    }
    else if (parameterName == "FS_THR_VALUE")
    {
        ui.throttlePwmSpinBox->setValue(value.toFloat());
    }
    else if (parameterName == "FS_BATT_ENABLE")
    {
        if (value.toInt() == 0)
        {
            ui.batteryFailCheckBox->setChecked(false);
        }
        else
        {
            ui.batteryFailCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "LOW_VOLT")
    {
        ui.batteryVoltSpinBox->setValue(value.toFloat());
    }
    //Arduplane
    else if (parameterName == "THR_FAILSAFE")
    {
        if (value.toInt() == 0)
        {
            ui.throttleCheckBox->setChecked(false);
        }
        else
        {
            ui.throttleCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "THR_FS_VALUE")
    {
        ui.throttlePwmSpinBox->setValue(value.toFloat());
    }
    else if (parameterName == "THR_FS_ACTION")
    {
        if (value.toInt() == 0)
        {
            ui.throttleActionCheckBox->setChecked(false);
        }
        else
        {
            ui.throttleActionCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_GCS_ENABL")
    {
        if (value.toInt() == 0)
        {
            ui.gcsCheckBox->setChecked(false);
        }
        else
        {
            ui.gcsCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_SHORT_ACTN")
    {
        if (value.toInt() == 0)
        {
            ui.fsShortCheckBox->setChecked(false);
        }
        else
        {
            ui.fsShortCheckBox->setChecked(true);
        }
    }
    else if (parameterName == "FS_LONG_ACTN")
    {
        if (value.toInt() == 0)
        {
            ui.fsLongCheckBox->setChecked(false);
        }
        else
        {
            ui.fsLongCheckBox->setChecked(true);
        }
    }

}

void FailSafeConfig::armingChanged(bool armed)
{
    if (armed)
    {
        ui.armedLabel->setText("
ARMED
");
    }
    else
    {
        ui.armedLabel->setText("
DISARMED
");
    }
}

void FailSafeConfig::remoteControlChannelRawChanges(int chan,float value)
{
    if (chan == 0)
    {
        ui.radio1In->setValue(value);
    }
    else if (chan == 1)
    {
        ui.radio2In->setValue(value);
    }
    else if (chan == 2)
    {
        ui.radio3In->setValue(value);
    }
    else if (chan == 3)
    {
        ui.radio4In->setValue(value);
    }
    else if (chan == 4)
    {
        ui.radio5In->setValue(value);
    }
    else if (chan == 5)
    {
        ui.radio6In->setValue(value);
    }
    else if (chan == 6)
    {
        ui.radio7In->setValue(value);
    }
    else if (chan == 7)
    {
        ui.radio8In->setValue(value);
    }
}
void FailSafeConfig::hilActuatorsChanged(uint64_t time, float act1, float act2, float act3, float act4, float act5, float act6, float act7, float act8)
{
    ui.radio1Out->setValue(act1);
    ui.radio2Out->setValue(act2);
    ui.radio3Out->setValue(act3);
    ui.radio4Out->setValue(act4);
    ui.radio5Out->setValue(act5);
    ui.radio6Out->setValue(act6);
    ui.radio7Out->setValue(act7);
    ui.radio8Out->setValue(act8);
}
void FailSafeConfig::gpsStatusChanged(UASInterface* uas,int fixtype)
{
    if (fixtype == 0 || fixtype == 1)
    {
        ui.gpsLabel->setText("
GPS: No Fix
");
    }
    else if (fixtype == 2)
    {
        ui.gpsLabel->setText("
GPS: 2D Fix
");
    }
    else if (fixtype == 3)
    {
        ui.gpsLabel->setText("
GPS: 3D Fix
");
    }
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkDataStorage.h"

#include "mitkDataTreeNode.h"
#include "mitkProperties.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkGroupTagProperty.h"
#include "mitkDataTreeStorage.h"

#include "itkCommand.h"

mitk::DataStorage::Pointer mitk::DataStorage::s_Instance = NULL;

mitk::DataStorage::DataStorage()
: itk::Object()
, m_BlockNodeModifiedEvents(false)
{
}

mitk::DataStorage::~DataStorage()
{
  // workaround for bug #343: do another UnRegister in case we re-create a DataStorage
  // which happens when a PlugIn is re-initialized within Chili
  if(s_Instance.IsNotNull())
  {
    mitk::DataTreeStorage* dts = dynamic_cast<mitk::DataTreeStorage*>(s_Instance.GetPointer());
    if(dts)
      dts->m_DataTree->UnRegister();
  }
}

mitk::DataStorage* mitk::DataStorage::CreateInstance(mitk::DataTree* tree)
{
  // workaround for bug #343: do another UnRegister in case we re-create a DataStorage
  // which happens when a PlugIn is re-initialized within Chili
  if(s_Instance.IsNotNull())
  {
    mitk::DataTreeStorage* dts = dynamic_cast<mitk::DataTreeStorage*>(s_Instance.GetPointer());
    if (dts != NULL)
      dts->m_DataTree->UnRegister();
  }
  s_Instance = NULL;
  try
  {
    mitk::DataTreeStorage::Pointer dts = mitk::DataTreeStorage::New();
    dts->Initialize(tree);   // If no DataStorage created yet, and tree is NULL, then this will raise an exception, because the DataStorage must be initialized with a DataTree
    /// \todo additional register on tree needed to prevent crash in itkTimeStamp.cxx (see bug #343)
    tree->Register();
    s_Instance = dts;
  }
  catch(...)
  {
    s_Instance = NULL;
    throw 1;  // insert exception handling here
  }
  return s_Instance;
}

mitk::DataStorage* mitk::DataStorage::GetInstance()
{
  if (DataStorage::s_Instance.IsNull())
  {
      itkGenericOutputMacro("Trying to use mitk::DataStorage::GetInstance() "
        << "without an available singleton instance. Either no instance has "
        << "been created (use DataStorage::CreateInstance) or it has already "
        << "been destroyed.");
      return NULL;
  }
  else
    return s_Instance;
}

void mitk::DataStorage::Add(mitk::DataTreeNode* node, mitk::DataTreeNode* parent)
{
  mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New();
  parents->InsertElement(0, parent);
  this->Add(node, parents);
}

void mitk::DataStorage::Remove(const mitk::DataStorage::SetOfObjects* nodes)
{
  if (nodes == NULL)
    return;
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++)
    this->Remove(it.Value());
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase& condition) const
{
  mitk::DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), &condition);
  return result;
}

mitk::DataTreeNode* mitk::DataStorage::GetNamedNode(const char* name) const
{
  if (name == NULL)
    return NULL;

  mitk::StringProperty::Pointer s(mitk::StringProperty::New(name));
  mitk::NodePredicateProperty p("name", s);
  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

mitk::DataTreeNode* mitk::DataStorage::GetNode(const NodePredicateBase* condition) const
{
  if (condition == NULL)
    return NULL;

  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(*condition);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

mitk::DataTreeNode* mitk::DataStorage::GetNamedDerivedNode(const char* name, const mitk::DataTreeNode* sourceNode, bool onlyDirectDerivations) const
{
  if (name == NULL)
    return NULL;

  mitk::StringProperty::Pointer s(mitk::StringProperty::New(name));
  mitk::NodePredicateProperty p("name", s);
  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, &p, onlyDirectDerivations);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

void mitk::DataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  //Superclass::PrintSelf(os, indent);
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetAll();
  os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl;
  for (mitk::DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++)
  {
    std::string name;
    allIt.Value()->GetName(name);
    std::string datatype;
    if (allIt.Value()->GetData() != NULL)
      datatype = allIt.Value()->GetData()->GetNameOfClass();
    os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl;
    mitk::DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value());
    if (parents->Size() > 0)
    {
      os << indent << "  Direct sources: ";
      for (mitk::DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++)
        os << parentIt.Value().GetPointer() << ", ";
      os << std::endl;
    }
    mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value());
    if (derivations->Size() > 0)
    {
      os << indent << "  Direct derivations: ";
      for (mitk::DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++)
        os << derivationIt.Value().GetPointer() << ", ";
      os << std::endl;
    }
  }
  os << std::endl;
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects* set, const NodePredicateBase* condition) const
{
  if (set == NULL)
    return NULL;
  if (condition == NULL)
    return set;
  mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++)
    if (condition->CheckNode(it.Value()) == true)
      result->InsertElement(result->Size(), it.Value());
  return mitk::DataStorage::SetOfObjects::ConstPointer(result);
}

const mitk::DataTreeNode::GroupTagList mitk::DataStorage::GetGroupTags() const
{
  DataTreeNode::GroupTagList result;
  SetOfObjects::ConstPointer all = this->GetAll();
  if (all.IsNull())
    return result;

  for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++)  // for each node
  {
    mitk::PropertyList* pl = nodeIt.Value()->GetPropertyList();
    for (mitk::PropertyList::PropertyMap::const_iterator propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); propIt++)
      if (dynamic_cast<mitk::GroupTagProperty*>(propIt->second.first.GetPointer()) != NULL)
        result.insert(propIt->first);
  }

  return result;
}

void mitk::DataStorage::ShutdownSingleton()
{
  if(s_Instance.IsNotNull())
  {
    mitk::DataTreeStorage* dts = dynamic_cast<mitk::DataTreeStorage*>(s_Instance.GetPointer());
    dts->m_DataTree->UnRegister();
  }
  s_Instance = NULL;
}

void mitk::DataStorage::EmitAddNodeEvent(const mitk::DataTreeNode* node)
{
  AddNodeEvent.Send(node);
}

void mitk::DataStorage::EmitRemoveNodeEvent(const mitk::DataTreeNode* node)
{
  RemoveNodeEvent.Send(node);
}

void mitk::DataStorage::OnNodeModified( const itk::Object *caller, const itk::EventObject &event )
{
  if(m_BlockNodeModifiedEvents)
    return;

  const mitk::DataTreeNode* modifiedNode = dynamic_cast<const mitk::DataTreeNode*>(caller);
  if(modifiedNode)
  {
    ChangedNodeEvent.Send(modifiedNode);
  }
}

void mitk::DataStorage::AddModifiedListener( const mitk::DataTreeNode* _Node )
{
  // node must not be 0 and must not be yet registered
  if(_Node && m_NodeModifiedObserverTags.find(_Node) == m_NodeModifiedObserverTags.end())
  {
    itk::MemberCommand<mitk::DataStorage>::Pointer nodeModifiedCommand =
      itk::MemberCommand<mitk::DataStorage>::New();
    nodeModifiedCommand->SetCallbackFunction(this, &DataStorage::OnNodeModified);
    m_NodeModifiedObserverTags[_Node]
      = _Node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand);
  }
}

void mitk::DataStorage::RemoveModifiedListener( const mitk::DataTreeNode* _Node )
{
  // node must not be 0 and must be registered
  if(_Node && m_NodeModifiedObserverTags.find(_Node) != m_NodeModifiedObserverTags.end())
  {
    unsigned long tag = m_NodeModifiedObserverTags.find(_Node)->second;
    // const cast is bad! but sometimes it is necessary. removing an observer does not really
    // touch the internal state
    (const_cast<mitk::DataTreeNode*>(_Node))->RemoveObserver(tag);
  }
}<commit_msg>CHG (#343): removed additional register on tree in CreateDataStore<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkDataStorage.h"

#include "mitkDataTreeNode.h"
#include "mitkProperties.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkGroupTagProperty.h"
#include "mitkDataTreeStorage.h"

#include "itkCommand.h"

mitk::DataStorage::Pointer mitk::DataStorage::s_Instance = NULL;

mitk::DataStorage::DataStorage()
: itk::Object()
, m_BlockNodeModifiedEvents(false)
{
}

mitk::DataStorage::~DataStorage()
{
  // workaround for bug #343: do another UnRegister in case we re-create a DataStorage
  // which happens when a PlugIn is re-initialized within Chili
  if(s_Instance.IsNotNull())
  {
    mitk::DataTreeStorage* dts = dynamic_cast<mitk::DataTreeStorage*>(s_Instance.GetPointer());
    if(dts)
      dts->m_DataTree->UnRegister();
  }
}

mitk::DataStorage* mitk::DataStorage::CreateInstance(mitk::DataTree* tree)
{
  if(s_Instance.IsNotNull())
  {
    throw std::exception("__FILE__ __LINE__ : DataStorage instance already exists! CreateInstance should only be called once.");
  }
  try
  {
    mitk::DataTreeStorage::Pointer dts = mitk::DataTreeStorage::New();
    dts->Initialize(tree);   // If no DataStorage created yet, and tree is NULL, then this will raise an exception, because the DataStorage must be initialized with a DataTree
    s_Instance = dts;
  }
  catch(...)
  {
    s_Instance = NULL;
    throw 1;  // insert exception handling here
  }
  return s_Instance;
}

mitk::DataStorage* mitk::DataStorage::GetInstance()
{
  if (DataStorage::s_Instance.IsNull())
  {
      itkGenericOutputMacro("Trying to use mitk::DataStorage::GetInstance() "
        << "without an available singleton instance. Either no instance has "
        << "been created (use DataStorage::CreateInstance) or it has already "
        << "been destroyed.");
      return NULL;
  }
  else
    return s_Instance;
}

void mitk::DataStorage::Add(mitk::DataTreeNode* node, mitk::DataTreeNode* parent)
{
  mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New();
  parents->InsertElement(0, parent);
  this->Add(node, parents);
}

void mitk::DataStorage::Remove(const mitk::DataStorage::SetOfObjects* nodes)
{
  if (nodes == NULL)
    return;
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++)
    this->Remove(it.Value());
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase& condition) const
{
  mitk::DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), &condition);
  return result;
}

mitk::DataTreeNode* mitk::DataStorage::GetNamedNode(const char* name) const
{
  if (name == NULL)
    return NULL;

  mitk::StringProperty::Pointer s(mitk::StringProperty::New(name));
  mitk::NodePredicateProperty p("name", s);
  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

mitk::DataTreeNode* mitk::DataStorage::GetNode(const NodePredicateBase* condition) const
{
  if (condition == NULL)
    return NULL;

  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(*condition);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

mitk::DataTreeNode* mitk::DataStorage::GetNamedDerivedNode(const char* name, const mitk::DataTreeNode* sourceNode, bool onlyDirectDerivations) const
{
  if (name == NULL)
    return NULL;

  mitk::StringProperty::Pointer s(mitk::StringProperty::New(name));
  mitk::NodePredicateProperty p("name", s);
  mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, &p, onlyDirectDerivations);
  if (rs->Size() >= 1)
    return rs->GetElement(0);
  else
    return NULL;
}

void mitk::DataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  //Superclass::PrintSelf(os, indent);
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetAll();
  os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl;
  for (mitk::DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++)
  {
    std::string name;
    allIt.Value()->GetName(name);
    std::string datatype;
    if (allIt.Value()->GetData() != NULL)
      datatype = allIt.Value()->GetData()->GetNameOfClass();
    os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl;
    mitk::DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value());
    if (parents->Size() > 0)
    {
      os << indent << "  Direct sources: ";
      for (mitk::DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++)
        os << parentIt.Value().GetPointer() << ", ";
      os << std::endl;
    }
    mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value());
    if (derivations->Size() > 0)
    {
      os << indent << "  Direct derivations: ";
      for (mitk::DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++)
        os << derivationIt.Value().GetPointer() << ", ";
      os << std::endl;
    }
  }
  os << std::endl;
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects* set, const NodePredicateBase* condition) const
{
  if (set == NULL)
    return NULL;
  if (condition == NULL)
    return set;
  mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++)
    if (condition->CheckNode(it.Value()) == true)
      result->InsertElement(result->Size(), it.Value());
  return mitk::DataStorage::SetOfObjects::ConstPointer(result);
}

const mitk::DataTreeNode::GroupTagList mitk::DataStorage::GetGroupTags() const
{
  DataTreeNode::GroupTagList result;
  SetOfObjects::ConstPointer all = this->GetAll();
  if (all.IsNull())
    return result;

  for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++)  // for each node
  {
    mitk::PropertyList* pl = nodeIt.Value()->GetPropertyList();
    for (mitk::PropertyList::PropertyMap::const_iterator propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); propIt++)
      if (dynamic_cast<mitk::GroupTagProperty*>(propIt->second.first.GetPointer()) != NULL)
        result.insert(propIt->first);
  }

  return result;
}

void mitk::DataStorage::ShutdownSingleton()
{
  s_Instance = NULL;
}

void mitk::DataStorage::EmitAddNodeEvent(const mitk::DataTreeNode* node)
{
  AddNodeEvent.Send(node);
}

void mitk::DataStorage::EmitRemoveNodeEvent(const mitk::DataTreeNode* node)
{
  RemoveNodeEvent.Send(node);
}

void mitk::DataStorage::OnNodeModified( const itk::Object *caller, const itk::EventObject &event )
{
  if(m_BlockNodeModifiedEvents)
    return;

  const mitk::DataTreeNode* modifiedNode = dynamic_cast<const mitk::DataTreeNode*>(caller);
  if(modifiedNode)
  {
    ChangedNodeEvent.Send(modifiedNode);
  }
}

void mitk::DataStorage::AddModifiedListener( const mitk::DataTreeNode* _Node )
{
  // node must not be 0 and must not be yet registered
  if(_Node && m_NodeModifiedObserverTags.find(_Node) == m_NodeModifiedObserverTags.end())
  {
    itk::MemberCommand<mitk::DataStorage>::Pointer nodeModifiedCommand =
      itk::MemberCommand<mitk::DataStorage>::New();
    nodeModifiedCommand->SetCallbackFunction(this, &DataStorage::OnNodeModified);
    m_NodeModifiedObserverTags[_Node]
      = _Node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand);
  }
}

void mitk::DataStorage::RemoveModifiedListener( const mitk::DataTreeNode* _Node )
{
  // node must not be 0 and must be registered
  if(_Node && m_NodeModifiedObserverTags.find(_Node) != m_NodeModifiedObserverTags.end())
  {
    unsigned long tag = m_NodeModifiedObserverTags.find(_Node)->second;
    // const cast is bad! but sometimes it is necessary. removing an observer does not really
    // touch the internal state
    (const_cast<mitk::DataTreeNode*>(_Node))->RemoveObserver(tag);
  }
}<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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 <atomic>

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <android/log.h>
#include <android/looper.h>

#define LOGE(fmt...) do { \
    fprintf(stderr, fmt); \
    __android_log_print(ANDROID_LOG_ERROR, "REALM", fmt); \
} while (0)

namespace realm {
namespace util {
template<typename Callback>
class EventLoopSignal : std::enable_shared_from_this() {
public:
    EventLoopSignal(Callback&& callback)
    : m_callback(std::move(callback))
    {
        ALooper* looper = ALooper_forThread();
        if (!looper) {
            return;
        }

        int message_pipe[2];
        if (pipe2(message_pipe, O_CLOEXEC | O_NONBLOCK)) {
            int err = errno;
            LOGE("could not create WeakRealmNotifier ALooper message pipe: %s", strerror(err));
            return;
        }

        if (ALooper_addFd(looper, message_pipe[0], 3 /* LOOPER_ID_USER */,
                          LOOPER_EVENT_INPUT | ALOOPER_EVENT_HANGUP,
                          &looper_callback, nullptr) != 1) {
            LOGE("Error adding WeakRealmNotifier callback to looper.");
            ::close(message_pipe[0]);
            ::close(message_pipe[1]);

            return;
        }

        m_message_pipe.read = message_pipe[0];
        m_message_pipe.write = message_pipe[1];
        m_thread_has_looper = true;
    }

    ~EventLoopSignal()
    {
        bool flag = true;
        if (m_thread_has_looper.compare_exchange_strong(flag, false)) {
            // closing one end of the pipe here will trigger ALOOPER_EVENT_HANGUP
            //in the callback which will do the rest of the cleanup
            ::close(m_message_pipe.write);
        }
    }

    EventLoopSignal(EventLoopSignal&&) = delete;
    EventLoopSignal& operator=(EventLoopSignal&&) = delete;
    EventLoopSignal(EventLoopSignal const&) = delete;
    EventLoopSignal& operator=(EventLoopSignal const&) = delete;

    void notify()
    {
        if (m_thread_has_looper) {
            // Pass ourself over the pipe so that we can od work on the target
            // thread. This requires forming a new shared_ptr to ensure we
            // continue to exist until then.
            auto ptr = new shared_ptr<EventLoopSignal>(shared_from_this());
            if (write(m_message_pipe.write, &ptr, sizeof(ptr)) != sizeof(ptr)) {
                delete ptr;
                LOGE("Buffer overrun when writing to WeakRealmNotifier's ALooper message pipe.");
            }
        }
    }

private:
    Callback m_callback;
    std::atomic<bool> m_thread_has_looper{false};

    // pipe file descriptor pair we use to signal ALooper
    struct {
      int read = -1;
      int write = -1;
    } m_message_pipe;

    static int looper_callback(int fd, int events, void* data)
    {
        if ((events & ALOOPER_EVENT_INPUT) != 0) {
            std::shared_ptr<EventLoopSignal>* ptr = nullptr;
            while (read(fd, &ptr, sizeof(ptr)) == sizeof(ptr)) {
                ptr->m_callback();
                delete ptr;
            }
        }

        if ((events & ALOOPER_EVENT_HANGUP) != 0) {
            // this callback is always invoked on the looper thread so it's fine to get the looper like this
            ALooper_removeFd(ALooper_forThread(), fd);
            ::close(fd);
        }

        if ((events & ALOOPER_EVENT_ERROR) != 0) {
            LOGE("Unexpected error on WeakRealmNotifier's ALooper message pipe.");
        }

        // return 1 to continue receiving events
        return 1;
    }
};
} // namespace util
} // namespace realm
<commit_msg>Fix compilation of the Android implementation<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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 <atomic>
#include <memory>

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <android/log.h>
#include <android/looper.h>

#define LOGE(fmt...) do { \
    fprintf(stderr, fmt); \
    __android_log_print(ANDROID_LOG_ERROR, "REALM", fmt); \
} while (0)

namespace realm {
namespace util {
template<typename Callback>
class EventLoopSignal : public std::enable_shared_from_this<EventLoopSignal<Callback>> {
public:
    EventLoopSignal(Callback&& callback)
    : m_callback(std::move(callback))
    {
        ALooper* looper = ALooper_forThread();
        if (!looper) {
            return;
        }

        int message_pipe[2];
        if (pipe2(message_pipe, O_CLOEXEC | O_NONBLOCK)) {
            int err = errno;
            LOGE("could not create WeakRealmNotifier ALooper message pipe: %s", strerror(err));
            return;
        }

        if (ALooper_addFd(looper, message_pipe[0], 3 /* LOOPER_ID_USER */,
                          ALOOPER_EVENT_INPUT | ALOOPER_EVENT_HANGUP,
                          &looper_callback, nullptr) != 1) {
            LOGE("Error adding WeakRealmNotifier callback to looper.");
            ::close(message_pipe[0]);
            ::close(message_pipe[1]);

            return;
        }

        m_message_pipe.read = message_pipe[0];
        m_message_pipe.write = message_pipe[1];
        m_thread_has_looper = true;
    }

    ~EventLoopSignal()
    {
        bool flag = true;
        if (m_thread_has_looper.compare_exchange_strong(flag, false)) {
            // closing one end of the pipe here will trigger ALOOPER_EVENT_HANGUP
            //in the callback which will do the rest of the cleanup
            ::close(m_message_pipe.write);
        }
    }

    EventLoopSignal(EventLoopSignal&&) = delete;
    EventLoopSignal& operator=(EventLoopSignal&&) = delete;
    EventLoopSignal(EventLoopSignal const&) = delete;
    EventLoopSignal& operator=(EventLoopSignal const&) = delete;

    void notify()
    {
        if (m_thread_has_looper) {
            // Pass ourself over the pipe so that we can od work on the target
            // thread. This requires forming a new shared_ptr to ensure we
            // continue to exist until then.
            auto ptr = new std::shared_ptr<EventLoopSignal>(this->shared_from_this());
            if (write(m_message_pipe.write, &ptr, sizeof(ptr)) != sizeof(ptr)) {
                delete ptr;
                LOGE("Buffer overrun when writing to WeakRealmNotifier's ALooper message pipe.");
            }
        }
    }

private:
    Callback m_callback;
    std::atomic<bool> m_thread_has_looper{false};

    // pipe file descriptor pair we use to signal ALooper
    struct {
      int read = -1;
      int write = -1;
    } m_message_pipe;

    static int looper_callback(int fd, int events, void* data)
    {
        if ((events & ALOOPER_EVENT_INPUT) != 0) {
            std::shared_ptr<EventLoopSignal>* ptr = nullptr;
            while (read(fd, &ptr, sizeof(ptr)) == sizeof(ptr)) {
                (*ptr)->m_callback();
                delete ptr;
            }
        }

        if ((events & ALOOPER_EVENT_HANGUP) != 0) {
            // this callback is always invoked on the looper thread so it's fine to get the looper like this
            ALooper_removeFd(ALooper_forThread(), fd);
            ::close(fd);
        }

        if ((events & ALOOPER_EVENT_ERROR) != 0) {
            LOGE("Unexpected error on WeakRealmNotifier's ALooper message pipe.");
        }

        // return 1 to continue receiving events
        return 1;
    }
};
} // namespace util
} // namespace realm
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>

#include "DOMStringPool.hpp"
#include "DOMDocumentImpl.hpp"

XERCES_CPP_NAMESPACE_BEGIN

//
//  DStringPoolEntry - one of these structs is allocated for each
//                      XMLCh String in the pool.  Each slot in the
//                      hash table array itself is a pointer to the head
//                      of a singly-linked list of these structs.
//
//                      Although this struct is delcared with a string length of one,
//                      the factory method allocates enough storage to hold the full
//                      string length.
//
struct DOMStringPoolEntry
{
    DOMStringPoolEntry    *fNext;
    XMLCh                 fString[1];
};

//
// createSPE - factory method for creating sting pool entry structs.
//             Allocates sufficient storage to hold the entire string
//
static DOMStringPoolEntry *createSPE(const XMLCh *str, DOMDocumentImpl *doc)
{
    //  Compute size to allocate.  Note that there's 1 char of string declared in the
    //       struct, so we don't need to add one again to account for the trailing null.
    //
    size_t sizeToAllocate = sizeof(DOMStringPoolEntry) + XMLString::stringLen(str)*sizeof(XMLCh);
    DOMStringPoolEntry *newSPE = (DOMStringPoolEntry *)doc->allocate(sizeToAllocate);
    newSPE->fNext = 0;
    XMLCh * nonConstStr = (XMLCh *)newSPE->fString;
    XMLString::copyString(nonConstStr, str);
    return newSPE;
}

DOMStringPool::DOMStringPool(int hashTableSize, DOMDocumentImpl *doc)
:   fDoc(doc)
,   fHashTableSize(hashTableSize)
{
    // needed to get access to the doc's storage allocator.

    //fHashTable = new (fDoc) DOMStringPoolEntry *[hashTableSize];
    void* p = doc->allocate(sizeof(DOMStringPoolEntry*) * hashTableSize);
    fHashTable = (DOMStringPoolEntry**) p;
    for (int i=0; i<fHashTableSize; i++)
        fHashTable[i] = 0;
}

//  Destructor.    Nothing to do, since storage all belongs to the document.
//
DOMStringPool::~DOMStringPool()
{
}

const XMLCh *DOMStringPool::getPooledString(const XMLCh *in)
{
    DOMStringPoolEntry    **pspe;
    DOMStringPoolEntry    *spe;

    int    inHash     = XMLString::hash(in, fHashTableSize, fDoc->getMemoryManager());
    pspe = &fHashTable[inHash];
    while (*pspe != 0)
    {
        if (XMLString::equals((*pspe)->fString, in))
            return (*pspe)->fString;
        pspe = &((*pspe)->fNext);
    }

    // This string hasn't been seen before.  Add it to the pool.
    *pspe = spe = createSPE(in, fDoc);
    return spe->fString;
}

// -----------------------------------------------------------------------
//  DOMBuffer: Constructors
// -----------------------------------------------------------------------
DOMBuffer::DOMBuffer(DOMDocumentImpl *doc, int capacity) :
    fBuffer(0)
    , fIndex(0)
    , fCapacity(capacity)
    , fDoc(doc)
{
    // Buffer is one larger than capacity, to allow for zero term
    fBuffer = (XMLCh*) doc->allocate((fCapacity+1)*sizeof(XMLCh));

    // Keep it null terminated
    fBuffer[0] = XMLCh(0);
}

DOMBuffer::DOMBuffer(DOMDocumentImpl *doc, const XMLCh* string) :
    fBuffer(0)
    , fIndex(0)
    , fCapacity(0)
    , fDoc(doc)
{
    unsigned int actualCount = XMLString::stringLen(string);
    fCapacity = actualCount + 15;

    // Buffer is one larger than capacity, to allow for zero term
    fBuffer = (XMLCh*) doc->allocate((fCapacity+1)*sizeof(XMLCh));

    memcpy(fBuffer, string, actualCount * sizeof(XMLCh));
    fIndex = actualCount;

    // Keep it null terminated
    fBuffer[fIndex] = 0;
}

// ---------------------------------------------------------------------------
//  DOMBuffer: Buffer management
// ---------------------------------------------------------------------------
void DOMBuffer::append(const XMLCh* const chars, const unsigned int count)
{
    unsigned int actualCount = count;
    if (!count)
        actualCount = XMLString::stringLen(chars);
    if (fIndex + actualCount >= fCapacity)
        expandCapacity(actualCount);
    memcpy(&fBuffer[fIndex], chars, actualCount * sizeof(XMLCh));
    fIndex += actualCount;
}

void DOMBuffer::set(const XMLCh* const chars, const unsigned int count)
{
    unsigned int actualCount = count;
    if (!count)
        actualCount = XMLString::stringLen(chars);
    fIndex = 0;
    if (fIndex + actualCount >= fCapacity)
        expandCapacity(actualCount);
    memcpy(fBuffer, chars, actualCount * sizeof(XMLCh));
    fIndex = actualCount;
}

// ---------------------------------------------------------------------------
//  DOMBuffer: Private helper methods
// ---------------------------------------------------------------------------
void DOMBuffer::expandCapacity(const unsigned int extraNeeded)
{
    //not enough room. Calc new capacity and allocate new buffer
    const unsigned int newCap = (unsigned int)((fIndex + extraNeeded) * 1.25);
    XMLCh* newBuf = (XMLCh*) fDoc->allocate((newCap+1)*sizeof(XMLCh));

    // Copy over the old stuff
    memcpy(newBuf, fBuffer, fCapacity * sizeof(XMLCh));

    // revisit: Leave the old buffer in document heap, yes, this is a leak, but live with it!
    // store new stuff
    fBuffer = newBuf;
    fCapacity = newCap;
}

XERCES_CPP_NAMESPACE_END

<commit_msg>set() and append() were not NULL-terminating the buffer (jira#1236)<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>

#include "DOMStringPool.hpp"
#include "DOMDocumentImpl.hpp"

XERCES_CPP_NAMESPACE_BEGIN

//
//  DStringPoolEntry - one of these structs is allocated for each
//                      XMLCh String in the pool.  Each slot in the
//                      hash table array itself is a pointer to the head
//                      of a singly-linked list of these structs.
//
//                      Although this struct is delcared with a string length of one,
//                      the factory method allocates enough storage to hold the full
//                      string length.
//
struct DOMStringPoolEntry
{
    DOMStringPoolEntry    *fNext;
    XMLCh                 fString[1];
};

//
// createSPE - factory method for creating sting pool entry structs.
//             Allocates sufficient storage to hold the entire string
//
static DOMStringPoolEntry *createSPE(const XMLCh *str, DOMDocumentImpl *doc)
{
    //  Compute size to allocate.  Note that there's 1 char of string declared in the
    //       struct, so we don't need to add one again to account for the trailing null.
    //
    size_t sizeToAllocate = sizeof(DOMStringPoolEntry) + XMLString::stringLen(str)*sizeof(XMLCh);
    DOMStringPoolEntry *newSPE = (DOMStringPoolEntry *)doc->allocate(sizeToAllocate);
    newSPE->fNext = 0;
    XMLCh * nonConstStr = (XMLCh *)newSPE->fString;
    XMLString::copyString(nonConstStr, str);
    return newSPE;
}

DOMStringPool::DOMStringPool(int hashTableSize, DOMDocumentImpl *doc)
:   fDoc(doc)
,   fHashTableSize(hashTableSize)
{
    // needed to get access to the doc's storage allocator.

    //fHashTable = new (fDoc) DOMStringPoolEntry *[hashTableSize];
    void* p = doc->allocate(sizeof(DOMStringPoolEntry*) * hashTableSize);
    fHashTable = (DOMStringPoolEntry**) p;
    for (int i=0; i<fHashTableSize; i++)
        fHashTable[i] = 0;
}

//  Destructor.    Nothing to do, since storage all belongs to the document.
//
DOMStringPool::~DOMStringPool()
{
}

const XMLCh *DOMStringPool::getPooledString(const XMLCh *in)
{
    DOMStringPoolEntry    **pspe;
    DOMStringPoolEntry    *spe;

    int    inHash     = XMLString::hash(in, fHashTableSize, fDoc->getMemoryManager());
    pspe = &fHashTable[inHash];
    while (*pspe != 0)
    {
        if (XMLString::equals((*pspe)->fString, in))
            return (*pspe)->fString;
        pspe = &((*pspe)->fNext);
    }

    // This string hasn't been seen before.  Add it to the pool.
    *pspe = spe = createSPE(in, fDoc);
    return spe->fString;
}

// -----------------------------------------------------------------------
//  DOMBuffer: Constructors
// -----------------------------------------------------------------------
DOMBuffer::DOMBuffer(DOMDocumentImpl *doc, int capacity) :
    fBuffer(0)
    , fIndex(0)
    , fCapacity(capacity)
    , fDoc(doc)
{
    // Buffer is one larger than capacity, to allow for zero term
    fBuffer = (XMLCh*) doc->allocate((fCapacity+1)*sizeof(XMLCh));

    // Keep it null terminated
    fBuffer[0] = XMLCh(0);
}

DOMBuffer::DOMBuffer(DOMDocumentImpl *doc, const XMLCh* string) :
    fBuffer(0)
    , fIndex(0)
    , fCapacity(0)
    , fDoc(doc)
{
    unsigned int actualCount = XMLString::stringLen(string);
    fCapacity = actualCount + 15;

    // Buffer is one larger than capacity, to allow for zero term
    fBuffer = (XMLCh*) doc->allocate((fCapacity+1)*sizeof(XMLCh));

    memcpy(fBuffer, string, actualCount * sizeof(XMLCh));
    fIndex = actualCount;

    // Keep it null terminated
    fBuffer[fIndex] = 0;
}

// ---------------------------------------------------------------------------
//  DOMBuffer: Buffer management
// ---------------------------------------------------------------------------
void DOMBuffer::append(const XMLCh* const chars, const unsigned int count)
{
    unsigned int actualCount = count;
    if (!count)
        actualCount = XMLString::stringLen(chars);
    if (fIndex + actualCount >= fCapacity)
        expandCapacity(actualCount);
    memcpy(&fBuffer[fIndex], chars, actualCount * sizeof(XMLCh));
    fIndex += actualCount;

    // Keep it null terminated
    fBuffer[fIndex] = 0;
}

void DOMBuffer::set(const XMLCh* const chars, const unsigned int count)
{
    unsigned int actualCount = count;
    if (!count)
        actualCount = XMLString::stringLen(chars);
    fIndex = 0;
    if (fIndex + actualCount >= fCapacity)
        expandCapacity(actualCount);
    memcpy(fBuffer, chars, actualCount * sizeof(XMLCh));
    fIndex = actualCount;

    // Keep it null terminated
    fBuffer[fIndex] = 0;
}

// ---------------------------------------------------------------------------
//  DOMBuffer: Private helper methods
// ---------------------------------------------------------------------------
void DOMBuffer::expandCapacity(const unsigned int extraNeeded)
{
    //not enough room. Calc new capacity and allocate new buffer
    const unsigned int newCap = (unsigned int)((fIndex + extraNeeded) * 1.25);
    XMLCh* newBuf = (XMLCh*) fDoc->allocate((newCap+1)*sizeof(XMLCh));

    // Copy over the old stuff
    memcpy(newBuf, fBuffer, fCapacity * sizeof(XMLCh));

    // revisit: Leave the old buffer in document heap, yes, this is a leak, but live with it!
    // store new stuff
    fBuffer = newBuf;
    fCapacity = newCap;
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>