<commit_before>/*************************************************************************
 *
 *  $RCSfile: ZipPackageFolder.hxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: mtg $ $Date: 2001-04-27 14:56:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_PACKAGE_FOLDER_HXX
#define _ZIP_PACKAGE_FOLDER_HXX

#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XENUMERATIONACCESS_HPP_
#include <com/sun/star/container/XEnumerationAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _HASHMAPS_HXX
#include <HashMaps.hxx>
#endif
#ifndef _ZIP_PACKAGE_ENTRY_HXX
#include <ZipPackageEntry.hxx>
#endif

class ZipFile;
class ZipPackage;
class ZipOutputStream;
class ZipPackageFolder : public ZipPackageEntry,
                         public ::cppu::OWeakObject,
                         public ::com::sun::star::container::XNameContainer,
                         public ::com::sun::star::container::XEnumerationAccess
{
protected:
    TunnelHash aContents;
public:

    ZipPackageFolder ();
    virtual ~ZipPackageFolder();

    static void copyZipEntry( com::sun::star::packages::ZipEntry &rDest, const com::sun::star::packages::ZipEntry &rSource);
    // Recursive functions
    void  saveContents(rtl::OUString &rPath, std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList, ZipOutputStream & rZipOut)
        throw(::com::sun::star::uno::RuntimeException);
    void  releaseUpwardRef();

    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType )
        throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL acquire(  )
        throw();
    virtual void SAL_CALL release(  )
        throw();

    // XNameContainer
    virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement )
        throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeByName( const ::rtl::OUString& Name )
        throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XEnumerationAccess
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration(  )
        throw(::com::sun::star::uno::RuntimeException);

    // XElementAccess
    virtual ::com::sun::star::uno::Type SAL_CALL getElementType(  )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL hasElements(  )
        throw(::com::sun::star::uno::RuntimeException);

    // XNameAccess
    virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::uno::RuntimeException);

    // XNameReplace
    virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement )
        throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue )
        throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName )
        throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    static ::com::sun::star::uno::Sequence < sal_Int8 > getUnoTunnelImplementationId( void )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier )
        throw(::com::sun::star::uno::RuntimeException);
};
#endif
<commit_msg>Pass the encryption key as a parameter to saveContents<commit_after>/*************************************************************************
 *
 *  $RCSfile: ZipPackageFolder.hxx,v $
 *
 *  $Revision: 1.20 $
 *
 *  last change: $Author: mtg $ $Date: 2001-05-08 13:51:29 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _ZIP_PACKAGE_FOLDER_HXX
#define _ZIP_PACKAGE_FOLDER_HXX

#ifndef _COM_SUN_STAR_CONTAINER_XNAMECONTAINER_HPP_
#include <com/sun/star/container/XNameContainer.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XENUMERATIONACCESS_HPP_
#include <com/sun/star/container/XEnumerationAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _HASHMAPS_HXX
#include <HashMaps.hxx>
#endif
#ifndef _ZIP_PACKAGE_ENTRY_HXX
#include <ZipPackageEntry.hxx>
#endif

class ZipFile;
class ZipPackage;
class ZipOutputStream;
class ZipPackageFolder : public ZipPackageEntry,
                         public ::cppu::OWeakObject,
                         public ::com::sun::star::container::XNameContainer,
                         public ::com::sun::star::container::XEnumerationAccess
{
protected:
    TunnelHash aContents;
public:

    ZipPackageFolder ();
    virtual ~ZipPackageFolder();

    static void copyZipEntry( com::sun::star::packages::ZipEntry &rDest, const com::sun::star::packages::ZipEntry &rSource);
    // Recursive functions
    void  saveContents(rtl::OUString &rPath, std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList, ZipOutputStream & rZipOut, com::sun::star::uno::Sequence < sal_Int8 > &rEncryptionKey)
        throw(::com::sun::star::uno::RuntimeException);
    void  releaseUpwardRef();

    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& rType )
        throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL acquire(  )
        throw();
    virtual void SAL_CALL release(  )
        throw();

    // XNameContainer
    virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement )
        throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeByName( const ::rtl::OUString& Name )
        throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XEnumerationAccess
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL createEnumeration(  )
        throw(::com::sun::star::uno::RuntimeException);

    // XElementAccess
    virtual ::com::sun::star::uno::Type SAL_CALL getElementType(  )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL hasElements(  )
        throw(::com::sun::star::uno::RuntimeException);

    // XNameAccess
    virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
        throw(::com::sun::star::uno::RuntimeException);

    // XNameReplace
    virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement )
        throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue )
        throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName )
        throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    static ::com::sun::star::uno::Sequence < sal_Int8 > getUnoTunnelImplementationId( void )
        throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier )
        throw(::com::sun::star::uno::RuntimeException);
};
#endif
<|endoftext|>


<commit_before>#include <numeric>
#include <set>

#include <arbiter/util/time.hpp>
#include <arbiter/arbiter.hpp>
#include <arbiter/util/transforms.hpp>

#include "config.hpp"

#include "gtest/gtest.h"

using namespace arbiter;

TEST(Env, HomeDir)
{
    std::string home;

    ASSERT_NO_THROW(home = arbiter::fs::expandTilde("~"));
    EXPECT_NE(home, "~");
    EXPECT_FALSE(home.empty());
}

TEST(Arbiter, HttpDerivation)
{
    Arbiter a;
    EXPECT_TRUE(a.isHttpDerived("http://arbitercpp.com"));
    EXPECT_FALSE(a.isHttpDerived("~/data"));
    EXPECT_FALSE(a.isHttpDerived("."));
}

TEST(Arbiter, Time)
{
    Time a;
    Time b(a.str());

    EXPECT_EQ(a.str(), b.str());
    EXPECT_EQ(a - b, 0);

    Time x("2016-03-18T03:14:42Z");
    Time y("2016-03-18T04:24:54Z");
    const int64_t delta(1 * 60 * 60 + 10 * 60 + 12);

    EXPECT_EQ(y - x, delta);
    EXPECT_EQ(x - y, -delta);
}

TEST(Arbiter, Base64)
{
    EXPECT_EQ(crypto::encodeBase64(""), "");
    EXPECT_EQ(crypto::encodeBase64("f"), "Zg==");
    EXPECT_EQ(crypto::encodeBase64("fo"), "Zm8=");
    EXPECT_EQ(crypto::encodeBase64("foo"), "Zm9v");
    EXPECT_EQ(crypto::encodeBase64("foob"), "Zm9vYg==");
    EXPECT_EQ(crypto::encodeBase64("fooba"), "Zm9vYmE=");
    EXPECT_EQ(crypto::encodeBase64("foobar"), "Zm9vYmFy");
}

class DriverTest : public ::testing::TestWithParam<std::string> { };

TEST_P(DriverTest, PutGet)
{
    Arbiter a;

    const std::string root(GetParam());
    const std::string path(root + "test.txt");
    const std::string data("Testing path " + path);

    if (a.isLocal(root)) fs::mkdirp(root);

    EXPECT_NO_THROW(a.put(path, data));
    EXPECT_EQ(a.get(path), data);
}

TEST_P(DriverTest, HttpRange)
{
    Arbiter a;

    const std::string root(GetParam());
    const std::string path(root + "test.txt");
    const std::string data("0123456789");
    const http::Headers headers{ { "Range", "bytes=0-5" } };

    // Dropbox is slow to update files, so we'd get failures here without a
    // timeout since the old file will often be returned.  Just skip it.
    if (!a.isHttpDerived(root) || a.getDriver(root).type() == "dropbox")
    {
        return;
    }

    EXPECT_NO_THROW(a.put(path, data));
    EXPECT_EQ(a.get(path, headers), "012345");
}

TEST_P(DriverTest, Glob)
{
    using Paths = std::set<std::string>;
    Arbiter a;

    const std::string rawRoot(GetParam());

    // Local directories explicitly prefixed with file:// will be returned
    // without that prefix, so strip that off.
    const std::string root(
            a.isLocal(rawRoot) ? Arbiter::stripType(rawRoot) : rawRoot);
    const std::string type(Arbiter::getType(root));

    // No `ls` for plain HTTP/s.
    if (type == "http" || type == "https") return;

    auto put([&a, root](std::string p)
    {
        EXPECT_NO_THROW(a.put(root + p, p));
    });

    if (a.isLocal(root))
    {
        fs::mkdirp(root + "a");
        fs::mkdirp(root + "a/b");
    }

    put("one.txt");
    put("two.txt");
    put("a/one.txt");
    put("a/two.txt");
    put("a/b/one.txt");
    put("a/b/two.txt");

    auto resolve([&a, root](std::string p)
    {
        const auto v = a.resolve(root + p);
        return Paths(v.begin(), v.end());
    });

    auto check([&](std::string p, Paths exp)
    {
        const auto got(resolve(p));
        EXPECT_GE(got.size(), exp.size());

        for (const auto& s : exp)
        {
            EXPECT_TRUE(got.count(root + s)) << p << ": " << root << s;
        }
    });

    // Non-recursive.
    check("*", Paths { "one.txt", "two.txt" });
    check("a/*", Paths { "a/one.txt", "a/two.txt" });
    check("a/b/*", Paths { "a/b/one.txt", "a/b/two.txt" });

    // Recursive.
    check("**", Paths {
            "one.txt", "two.txt",
            "a/one.txt", "a/two.txt",
            "a/b/one.txt", "a/b/two.txt"
        }
    );

    check("a/**", Paths {
            "a/one.txt", "a/two.txt",
            "a/b/one.txt", "a/b/two.txt"
        }
    );

    check("a/b/**", Paths { "a/b/one.txt", "a/b/two.txt" });

    // Not globs - files resolve to themselves.
    check("", Paths { "" });
    check("asdf", Paths { "asdf" });
    check("asdf.txt", Paths { "asdf.txt" });
}

const auto tests = std::accumulate(
        Config::get().begin(),
        Config::get().end(),
        std::vector<std::string>(),
        [](const std::vector<std::string>& in, const Json::Value& entry)
        {
            if (in.empty())
            {
                std::cout << "Testing PUT/GET/LS with:" << std::endl;
            }

            auto out(in);
            const std::string path(entry.asString());
            out.push_back(path + (path.back() != '/' ? "/" : ""));
            std::cout << "\t" << out.back() << std::endl;
            return out;
        });

INSTANTIATE_TEST_CASE_P(
        ConfiguredTests,
        DriverTest,
        ::testing::ValuesIn(tests));

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

<commit_msg>Enable ranged dropbox test.<commit_after>#include <numeric>
#include <set>

#include <arbiter/util/time.hpp>
#include <arbiter/arbiter.hpp>
#include <arbiter/util/transforms.hpp>

#include "config.hpp"

#include "gtest/gtest.h"

using namespace arbiter;

TEST(Env, HomeDir)
{
    std::string home;

    ASSERT_NO_THROW(home = arbiter::fs::expandTilde("~"));
    EXPECT_NE(home, "~");
    EXPECT_FALSE(home.empty());
}

TEST(Arbiter, HttpDerivation)
{
    Arbiter a;
    EXPECT_TRUE(a.isHttpDerived("http://arbitercpp.com"));
    EXPECT_FALSE(a.isHttpDerived("~/data"));
    EXPECT_FALSE(a.isHttpDerived("."));
}

TEST(Arbiter, Time)
{
    Time a;
    Time b(a.str());

    EXPECT_EQ(a.str(), b.str());
    EXPECT_EQ(a - b, 0);

    Time x("2016-03-18T03:14:42Z");
    Time y("2016-03-18T04:24:54Z");
    const int64_t delta(1 * 60 * 60 + 10 * 60 + 12);

    EXPECT_EQ(y - x, delta);
    EXPECT_EQ(x - y, -delta);
}

TEST(Arbiter, Base64)
{
    EXPECT_EQ(crypto::encodeBase64(""), "");
    EXPECT_EQ(crypto::encodeBase64("f"), "Zg==");
    EXPECT_EQ(crypto::encodeBase64("fo"), "Zm8=");
    EXPECT_EQ(crypto::encodeBase64("foo"), "Zm9v");
    EXPECT_EQ(crypto::encodeBase64("foob"), "Zm9vYg==");
    EXPECT_EQ(crypto::encodeBase64("fooba"), "Zm9vYmE=");
    EXPECT_EQ(crypto::encodeBase64("foobar"), "Zm9vYmFy");
}

class DriverTest : public ::testing::TestWithParam<std::string> { };

TEST_P(DriverTest, PutGet)
{
    Arbiter a;

    const std::string root(GetParam());
    const std::string path(root + "test.txt");
    const std::string data("Testing path " + path);

    if (a.isLocal(root)) fs::mkdirp(root);

    EXPECT_NO_THROW(a.put(path, data));
    EXPECT_EQ(a.get(path), data);
}

TEST_P(DriverTest, HttpRange)
{
    Arbiter a;

    const std::string root(GetParam());
    const std::string path(root + "range.txt");
    const std::string data("0123456789");
    const http::Headers headers{ { "Range", "bytes=0-5" } };

    if (!a.isHttpDerived(root)) return;

    EXPECT_NO_THROW(a.put(path, data));
    EXPECT_EQ(a.get(path, headers), "012345");
}

TEST_P(DriverTest, Glob)
{
    using Paths = std::set<std::string>;
    Arbiter a;

    const std::string rawRoot(GetParam());

    // Local directories explicitly prefixed with file:// will be returned
    // without that prefix, so strip that off.
    const std::string root(
            a.isLocal(rawRoot) ? Arbiter::stripType(rawRoot) : rawRoot);
    const std::string type(Arbiter::getType(root));

    // No `ls` for plain HTTP/s.
    if (type == "http" || type == "https") return;

    auto put([&a, root](std::string p)
    {
        EXPECT_NO_THROW(a.put(root + p, p));
    });

    if (a.isLocal(root))
    {
        fs::mkdirp(root + "a");
        fs::mkdirp(root + "a/b");
    }

    put("one.txt");
    put("two.txt");
    put("a/one.txt");
    put("a/two.txt");
    put("a/b/one.txt");
    put("a/b/two.txt");

    auto resolve([&a, root](std::string p)
    {
        const auto v = a.resolve(root + p);
        return Paths(v.begin(), v.end());
    });

    auto check([&](std::string p, Paths exp)
    {
        const auto got(resolve(p));
        EXPECT_GE(got.size(), exp.size());

        for (const auto& s : exp)
        {
            EXPECT_TRUE(got.count(root + s)) << p << ": " << root << s;
        }
    });

    // Non-recursive.
    check("*", Paths { "one.txt", "two.txt" });
    check("a/*", Paths { "a/one.txt", "a/two.txt" });
    check("a/b/*", Paths { "a/b/one.txt", "a/b/two.txt" });

    // Recursive.
    check("**", Paths {
            "one.txt", "two.txt",
            "a/one.txt", "a/two.txt",
            "a/b/one.txt", "a/b/two.txt"
        }
    );

    check("a/**", Paths {
            "a/one.txt", "a/two.txt",
            "a/b/one.txt", "a/b/two.txt"
        }
    );

    check("a/b/**", Paths { "a/b/one.txt", "a/b/two.txt" });

    // Not globs - files resolve to themselves.
    check("", Paths { "" });
    check("asdf", Paths { "asdf" });
    check("asdf.txt", Paths { "asdf.txt" });
}

const auto tests = std::accumulate(
        Config::get().begin(),
        Config::get().end(),
        std::vector<std::string>(),
        [](const std::vector<std::string>& in, const Json::Value& entry)
        {
            if (in.empty())
            {
                std::cout << "Testing PUT/GET/LS with:" << std::endl;
            }

            auto out(in);
            const std::string path(entry.asString());
            out.push_back(path + (path.back() != '/' ? "/" : ""));
            std::cout << "\t" << out.back() << std::endl;
            return out;
        });

INSTANTIATE_TEST_CASE_P(
        ConfiguredTests,
        DriverTest,
        ::testing::ValuesIn(tests));

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

<|endoftext|>


<commit_before>//===-- WebAssemblyFixFunctionBitcasts.cpp - Fix function bitcasts --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Fix bitcasted functions.
///
/// WebAssembly requires caller and callee signatures to match, however in LLVM,
/// some amount of slop is vaguely permitted. Detect mismatch by looking for
/// bitcasts of functions and rewrite them to use wrapper functions instead.
///
/// This doesn't catch all cases, such as when a function's address is taken in
/// one place and casted in another, but it works for many common cases.
///
/// Note that LLVM already optimizes away function bitcasts in common cases by
/// dropping arguments as needed, so this pass only ends up getting used in less
/// common cases.
///
//===----------------------------------------------------------------------===//

#include "WebAssembly.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "wasm-fix-function-bitcasts"

namespace {
class FixFunctionBitcasts final : public ModulePass {
  StringRef getPassName() const override {
    return "WebAssembly Fix Function Bitcasts";
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    ModulePass::getAnalysisUsage(AU);
  }

  bool runOnModule(Module &M) override;

  SmallVector<std::pair<Use *, Function *>, 0> Uses;

public:
  static char ID;
  FixFunctionBitcasts() : ModulePass(ID) {}
};
} // End anonymous namespace

char FixFunctionBitcasts::ID = 0;
ModulePass *llvm::createWebAssemblyFixFunctionBitcasts() {
  return new FixFunctionBitcasts();
}

// Recursively descend the def-use lists from V to find non-bitcast users of
// bitcasts of V.
static void FindUses(Value *V, Function &F,
                     SmallVectorImpl<std::pair<Use *, Function *>> &Uses) {
  for (Use &U : V->uses()) {
    if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser()))
      FindUses(BC, F, Uses);
    else if (U.get()->getType() != F.getType())
      Uses.push_back(std::make_pair(&U, &F));
  }
}

// Create a wrapper function with type Ty that calls F (which may have a
// different type). Attempt to support common bitcasted function idioms:
//  - Call with more arguments than needed: arguments are dropped
//  - Call with fewer arguments than needed: arguments are filled in with undef
//  - Return value is not needed: drop it
//  - Return value needed but not present: supply an undef
static Function *CreateWrapper(Function *F, FunctionType *Ty) {
  Module *M = F->getParent();

  Function *Wrapper =
      Function::Create(Ty, Function::PrivateLinkage, "bitcast", M);
  BasicBlock *BB = BasicBlock::Create(M->getContext(), "body", Wrapper);

  // Determine what arguments to pass.
  SmallVector<Value *, 4> Args;
  Function::arg_iterator AI = Wrapper->arg_begin();
  FunctionType::param_iterator PI = F->getFunctionType()->param_begin();
  FunctionType::param_iterator PE = F->getFunctionType()->param_end();
  for (; AI != Wrapper->arg_end() && PI != PE; ++AI, ++PI) {
    assert(AI->getType() == *PI &&
           "mismatched argument types not supported yet");
    Args.push_back(&*AI);
  }
  for (; PI != PE; ++PI)
    Args.push_back(UndefValue::get(*PI));

  CallInst *Call = CallInst::Create(F, Args, "", BB);

  // Determine what value to return.
  if (Ty->getReturnType()->isVoidTy())
    ReturnInst::Create(M->getContext(), BB);
  else if (F->getFunctionType()->getReturnType()->isVoidTy())
    ReturnInst::Create(M->getContext(), UndefValue::get(Ty->getReturnType()),
                       BB);
  else if (F->getFunctionType()->getReturnType() == Ty->getReturnType())
    ReturnInst::Create(M->getContext(), Call, BB);
  else
    llvm_unreachable("mismatched return types not supported yet");

  return Wrapper;
}

bool FixFunctionBitcasts::runOnModule(Module &M) {
  // Collect all the places that need wrappers.
  for (Function &F : M)
    FindUses(&F, F, Uses);

  DenseMap<std::pair<Function *, FunctionType *>, Function *> Wrappers;

  for (auto &UseFunc : Uses) {
    Use *U = UseFunc.first;
    Function *F = UseFunc.second;
    PointerType *PTy = cast<PointerType>(U->get()->getType());
    FunctionType *Ty = dyn_cast<FunctionType>(PTy->getElementType());

    // If the function is casted to something like i8* as a "generic pointer"
    // to be later casted to something else, we can't generate a wrapper for it.
    // Just ignore such casts for now.
    if (!Ty)
      continue;

    auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr));
    if (Pair.second)
      Pair.first->second = CreateWrapper(F, Ty);

    if (isa<Constant>(U->get()))
      U->get()->replaceAllUsesWith(Pair.first->second);
    else
      U->set(Pair.first->second);
  }

  return true;
}
<commit_msg>[WebAssembly] Move a SmallVector to a more specific scope. NFC.<commit_after>//===-- WebAssemblyFixFunctionBitcasts.cpp - Fix function bitcasts --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Fix bitcasted functions.
///
/// WebAssembly requires caller and callee signatures to match, however in LLVM,
/// some amount of slop is vaguely permitted. Detect mismatch by looking for
/// bitcasts of functions and rewrite them to use wrapper functions instead.
///
/// This doesn't catch all cases, such as when a function's address is taken in
/// one place and casted in another, but it works for many common cases.
///
/// Note that LLVM already optimizes away function bitcasts in common cases by
/// dropping arguments as needed, so this pass only ends up getting used in less
/// common cases.
///
//===----------------------------------------------------------------------===//

#include "WebAssembly.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "wasm-fix-function-bitcasts"

namespace {
class FixFunctionBitcasts final : public ModulePass {
  StringRef getPassName() const override {
    return "WebAssembly Fix Function Bitcasts";
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    ModulePass::getAnalysisUsage(AU);
  }

  bool runOnModule(Module &M) override;

public:
  static char ID;
  FixFunctionBitcasts() : ModulePass(ID) {}
};
} // End anonymous namespace

char FixFunctionBitcasts::ID = 0;
ModulePass *llvm::createWebAssemblyFixFunctionBitcasts() {
  return new FixFunctionBitcasts();
}

// Recursively descend the def-use lists from V to find non-bitcast users of
// bitcasts of V.
static void FindUses(Value *V, Function &F,
                     SmallVectorImpl<std::pair<Use *, Function *>> &Uses) {
  for (Use &U : V->uses()) {
    if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser()))
      FindUses(BC, F, Uses);
    else if (U.get()->getType() != F.getType())
      Uses.push_back(std::make_pair(&U, &F));
  }
}

// Create a wrapper function with type Ty that calls F (which may have a
// different type). Attempt to support common bitcasted function idioms:
//  - Call with more arguments than needed: arguments are dropped
//  - Call with fewer arguments than needed: arguments are filled in with undef
//  - Return value is not needed: drop it
//  - Return value needed but not present: supply an undef
static Function *CreateWrapper(Function *F, FunctionType *Ty) {
  Module *M = F->getParent();

  Function *Wrapper =
      Function::Create(Ty, Function::PrivateLinkage, "bitcast", M);
  BasicBlock *BB = BasicBlock::Create(M->getContext(), "body", Wrapper);

  // Determine what arguments to pass.
  SmallVector<Value *, 4> Args;
  Function::arg_iterator AI = Wrapper->arg_begin();
  FunctionType::param_iterator PI = F->getFunctionType()->param_begin();
  FunctionType::param_iterator PE = F->getFunctionType()->param_end();
  for (; AI != Wrapper->arg_end() && PI != PE; ++AI, ++PI) {
    assert(AI->getType() == *PI &&
           "mismatched argument types not supported yet");
    Args.push_back(&*AI);
  }
  for (; PI != PE; ++PI)
    Args.push_back(UndefValue::get(*PI));

  CallInst *Call = CallInst::Create(F, Args, "", BB);

  // Determine what value to return.
  if (Ty->getReturnType()->isVoidTy())
    ReturnInst::Create(M->getContext(), BB);
  else if (F->getFunctionType()->getReturnType()->isVoidTy())
    ReturnInst::Create(M->getContext(), UndefValue::get(Ty->getReturnType()),
                       BB);
  else if (F->getFunctionType()->getReturnType() == Ty->getReturnType())
    ReturnInst::Create(M->getContext(), Call, BB);
  else
    llvm_unreachable("mismatched return types not supported yet");

  return Wrapper;
}

bool FixFunctionBitcasts::runOnModule(Module &M) {
  SmallVector<std::pair<Use *, Function *>, 0> Uses;

  // Collect all the places that need wrappers.
  for (Function &F : M)
    FindUses(&F, F, Uses);

  DenseMap<std::pair<Function *, FunctionType *>, Function *> Wrappers;

  for (auto &UseFunc : Uses) {
    Use *U = UseFunc.first;
    Function *F = UseFunc.second;
    PointerType *PTy = cast<PointerType>(U->get()->getType());
    FunctionType *Ty = dyn_cast<FunctionType>(PTy->getElementType());

    // If the function is casted to something like i8* as a "generic pointer"
    // to be later casted to something else, we can't generate a wrapper for it.
    // Just ignore such casts for now.
    if (!Ty)
      continue;

    auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr));
    if (Pair.second)
      Pair.first->second = CreateWrapper(F, Ty);

    if (isa<Constant>(U->get()))
      U->get()->replaceAllUsesWith(Pair.first->second);
    else
      U->set(Pair.first->second);
  }

  return true;
}
<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------
//   Painting with Flowsnakes
// fsnake program modified to use open gl vertex arrays  Brian Wyvill October 2012
// added save/restore and postscript driver November 2012
// fixed memory management November 2012 delete works properly now.
// added progress bar to show memory usage.
//-------------------------------------------------------------------------------------------

#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    double ambience[3] = {0.6,0.6,0.6};
    double diffusal[3] = {0.6,0.6,0.6};
    double spec[3] = {0.6,0.6,0.6};
    double intensity[3] = {0.6,0.6,0.6};

   // QVector3D circlepoint(5.0,5.0,5.0);

    sceneAmbience = 0.2;

    spheres.append(Sphere(QVector3D(5.0,5.0,5.0),1.0,ambience,diffusal,spec));
    //spheres.append(Sphere(QVector3D(5.0,7.0,5.0),1.0,ambience,diffusal,spec));
    //Spheres.append()

    lightBulbs.append(LightBulb(QVector3D(2.0,2.0,4.0),0.5,intensity));

}

GLWidget::~GLWidget()
{

}

void GLWidget::clear()
{
     updateGL();
}

void GLWidget::initializeGL()
{
    //Background color will be white
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glShadeModel( GL_FLAT );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glPointSize(5);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    displayImage();
}

/* 2D */
void GLWidget::resizeGL( int w, int h )
{
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho(0.0,GLdouble(w),0,GLdouble(h),-10.0,10.0);
    glFlush();
    glMatrixMode(GL_MODELVIEW);
    glViewport( 0, 0, (GLint)w, (GLint)h );
    cerr << "gl new size "<< w SEP h NL;
    renderWidth = w;
    renderHeight = h;
}

// no mouse events in this demo
void GLWidget::mousePressEvent( QMouseEvent * )
{
}

void GLWidget::mouseReleaseEvent( QMouseEvent *)
{
}

void GLWidget::mouseMoveEvent ( QMouseEvent * )
{
}

// wheel event
void GLWidget::wheelEvent(QWheelEvent *)
{
}

void GLWidget::openImage(QString fileBuf)
{
    QImage myImage;
    myImage.load(fileBuf);
    prepareImageDisplay(&myImage);
}

void GLWidget::prepareImageDisplay(QImage* myimage)
{
    glimage = QGLWidget::convertToGLFormat( *myimage );  // flipped 32bit RGBA stored as mi
    updateGL();
}

void GLWidget::displayImage()
{
    if (glimage.width()==0) {
        cerr << "Null Image\n";
        return;
    } else {
        glRasterPos2i(0,0);
        glDrawPixels(glimage.width(), glimage.height(), GL_RGBA, GL_UNSIGNED_BYTE, glimage.bits());
        glFlush();
    }
}

void GLWidget::saveImage( QString fileBuf )
{
    // there is no conversion  back toQImage
    // hence the need to keep qtimage as well as glimage
    qtimage.save ( fileBuf );   // note it is the qtimage in the right format for saving
}

void GLWidget::makeImage( )
{
    QImage myimage(renderWidth, renderHeight, QImage::Format_RGB32);
    qDebug() << renderWidth;
    qDebug() << renderHeight;
    double widthratio = 10.0;
    double heightratio = renderHeight / (renderWidth/widthratio);

    QVector3D camera(widthratio/2, heightratio/2, 20);

    qDebug() << camera;

    QVector3D pixelposition;
    QVector3D ray;
    QVector<double> rayTraceResult;

    for(int i=0;i<renderWidth;i++)
    {
        for(int j=0;j<renderHeight;j++)
        {
            pixelposition = QVector3D(double(i)*widthratio/renderWidth,double(j)*heightratio/renderHeight,10.0);
            ray = (pixelposition-camera).normalized();
            //qDebug() << "ray: " << ray;
            if(i == renderWidth/2 && j == renderHeight/2)
                qDebug() << "ray: " << ray;

            rayTraceResult = rayTracer(ray,camera);

            double r = rayTraceResult[1]*255;
            double g = rayTraceResult[2]*255;
            double b = rayTraceResult[3]*255;
            myimage.setPixel(i,renderHeight-1-j,qRgb(r,g,b));
        }
    }

    //myimage.setPixel(i,	j,	qRgb(R,	G,	B));

    qtimage=myimage.copy(0, 0,  myimage.width(), myimage.height());

    prepareImageDisplay(&myimage);
}

QVector<double> GLWidget::intersectionSpheres(QVector3D ray, QVector3D camera, double closestPolygon)
{
    QVector<double> result;
    QVector3D pointOfIntersection,sphereNormal,lightVector,lightPosition,spherePosition,EO;
    result = QVector<double>(5);

    double r,cc,v,disc,d, shadeR,shadeG,shadeB;

    result[0] = 0;

    for(int i=0;i<spheres.length();i++)//sphere index
    {
        r = spheres[i].radius;
        spherePosition = spheres[i].position;

        EO = spherePosition-camera;

        cc = QVector3D::dotProduct(EO,EO);
        v = QVector3D::dotProduct(EO,ray);

        disc = r*r - (cc-v*v);

        if(disc>0)
        {
            d = sqrt(disc);
            if(v-d<closestPolygon)
            {
                closestPolygon = v-d;
                result[0] = 1;
                pointOfIntersection = camera + (v-d)*ray;

                //Ambience

                shadeR = spheres[i].ambience[0]*sceneAmbience;
                shadeG = spheres[i].ambience[1]*sceneAmbience;
                shadeB = spheres[i].ambience[2]*sceneAmbience;

                for(int j=0;j<lightBulbs.size();j++)
                {

                    lightPosition = lightBulbs[j].position;

                    //Lambertian

                    sphereNormal = (pointOfIntersection - spherePosition).normalized();
                    lightVector = (lightPosition - pointOfIntersection).normalized();
                    double lightmagnitude = QVector3D::dotProduct(sphereNormal,lightVector);
                    double l = max(0.0,(lightmagnitude));

                    shadeR += spheres[i].diffuse[0]*lightBulbs[j].intensity[0]*l;
                    shadeG += spheres[i].diffuse[1]*lightBulbs[j].intensity[1]*l;
                    shadeB += spheres[i].diffuse[2]*lightBulbs[j].intensity[2]*l;

                }
                result[1] = shadeR;
                result[2] = shadeG;
                result[3] = shadeB;
            }
        }

    }

    result[4] = closestPolygon;
    return result;

}

QVector<double> GLWidget::rayTracer(QVector3D ray, QVector3D camera)
{
    QVector<double> result(5),intersectionResult;
    double closestPolygon = pow(10,10);
    QVector3D EO;

    double rr,cc,v,disc;

    intersectionResult = intersectionSpheres(ray,camera,closestPolygon);
    if(intersectionResult[0] = 1)
    {
        result[1] = intersectionResult[1];
        result[2] = intersectionResult[2];
        result[3] = intersectionResult[3];
        closestPolygon = intersectionResult[4];

    }

    return result;

//    if(disc<=0)//ray =! intersect sphere
//    {
//        result.append(0.0);
//        return result;
//    }

//    else//intersected
//    {
//        result.append(1.0);
//        return result;
//    }

}

void GLWidget::about()
{
    QString vnum;
    QString mess, notes;
    QString title="Images in Qt and Opengl ";

    vnum.setNum ( MYVERSION );
    mess="Qt OpenGl image demo Release Version: ";
    mess = mess+vnum;
    notes = "\n\n News: Every QImage is now on stack, there is no way for memory leak. -- Lucky";
    mess = mess+notes;
    QMessageBox::information( this, title, mess, QMessageBox::Ok );
}

void GLWidget::help()
{
    QString vnum;
    QString mess, notes;
    QString title="qtglimages";

    vnum.setNum ( MYVERSION);
    mess="Simple Image Handling in Qt/Opengl by Brian Wyvill Release Version: ";
    mess = mess+vnum;
    notes = "\n\n Save and Load images for display.  Also Make an image such as output from a ray tracer. ";
    mess = mess+notes;
    QMessageBox::information( this, title, mess, QMessageBox::Ok );
}

<commit_msg>Finished Phong Shading<commit_after>//-------------------------------------------------------------------------------------------
//   Painting with Flowsnakes
// fsnake program modified to use open gl vertex arrays  Brian Wyvill October 2012
// added save/restore and postscript driver November 2012
// fixed memory management November 2012 delete works properly now.
// added progress bar to show memory usage.
//-------------------------------------------------------------------------------------------

#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    double ambience[3] = {0.6,0.6,0.6};
    double diffusal[3] = {0.6,0.6,0.6};
    double spec[3] = {0.6,0.6,0.6};
    double intensity[3] = {0.6,0.6,0.6};

   // QVector3D circlepoint(5.0,5.0,5.0);

    sceneAmbience = 0.2;

    spheres.append(Sphere(QVector3D(5.0,5.0,5.0),1.0,ambience,diffusal,spec));
    //spheres.append(Sphere(QVector3D(5.0,7.0,5.0),1.0,ambience,diffusal,spec));
    //Spheres.append()

    lightBulbs.append(LightBulb(QVector3D(4.0,2.0,7.0),0.5,intensity));

}

GLWidget::~GLWidget()
{

}

void GLWidget::clear()
{
     updateGL();
}

void GLWidget::initializeGL()
{
    //Background color will be white
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glShadeModel( GL_FLAT );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glPointSize(5);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    displayImage();
}

/* 2D */
void GLWidget::resizeGL( int w, int h )
{
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho(0.0,GLdouble(w),0,GLdouble(h),-10.0,10.0);
    glFlush();
    glMatrixMode(GL_MODELVIEW);
    glViewport( 0, 0, (GLint)w, (GLint)h );
    cerr << "gl new size "<< w SEP h NL;
    renderWidth = w;
    renderHeight = h;
}

// no mouse events in this demo
void GLWidget::mousePressEvent( QMouseEvent * )
{
}

void GLWidget::mouseReleaseEvent( QMouseEvent *)
{
}

void GLWidget::mouseMoveEvent ( QMouseEvent * )
{
}

// wheel event
void GLWidget::wheelEvent(QWheelEvent *)
{
}

void GLWidget::openImage(QString fileBuf)
{
    QImage myImage;
    myImage.load(fileBuf);
    prepareImageDisplay(&myImage);
}

void GLWidget::prepareImageDisplay(QImage* myimage)
{
    glimage = QGLWidget::convertToGLFormat( *myimage );  // flipped 32bit RGBA stored as mi
    updateGL();
}

void GLWidget::displayImage()
{
    if (glimage.width()==0) {
        cerr << "Null Image\n";
        return;
    } else {
        glRasterPos2i(0,0);
        glDrawPixels(glimage.width(), glimage.height(), GL_RGBA, GL_UNSIGNED_BYTE, glimage.bits());
        glFlush();
    }
}

void GLWidget::saveImage( QString fileBuf )
{
    // there is no conversion  back toQImage
    // hence the need to keep qtimage as well as glimage
    qtimage.save ( fileBuf );   // note it is the qtimage in the right format for saving
}

void GLWidget::makeImage( )
{
    QImage myimage(renderWidth, renderHeight, QImage::Format_RGB32);
    qDebug() << renderWidth;
    qDebug() << renderHeight;
    double widthratio = 10.0;
    double heightratio = renderHeight / (renderWidth/widthratio);

    QVector3D camera(widthratio/2, heightratio/2, 20);

    qDebug() << camera;

    QVector3D pixelposition;
    QVector3D ray;
    QVector<double> rayTraceResult;

    for(int i=0;i<renderWidth;i++)
    {
        for(int j=0;j<renderHeight;j++)
        {
            pixelposition = QVector3D(double(i)*widthratio/renderWidth,double(j)*heightratio/renderHeight,10.0);
            ray = (pixelposition-camera).normalized();
            //qDebug() << "ray: " << ray;
            if(i == renderWidth/2 && j == renderHeight/2)
                qDebug() << "ray: " << ray;

            rayTraceResult = rayTracer(ray,camera);

            double r = rayTraceResult[1]*255;
            double g = rayTraceResult[2]*255;
            double b = rayTraceResult[3]*255;
            myimage.setPixel(i,renderHeight-1-j,qRgb(r,g,b));
        }
    }

    //myimage.setPixel(i,	j,	qRgb(R,	G,	B));

    qtimage=myimage.copy(0, 0,  myimage.width(), myimage.height());

    prepareImageDisplay(&myimage);
}

QVector<double> GLWidget::intersectionSpheres(QVector3D ray, QVector3D camera, double closestPolygon)
{
    QVector<double> result;
    QVector3D pointOfIntersection,sphereNormal,lightVector,lightPosition,spherePosition,EO,cameraVector,h;
    result = QVector<double>(5);

    double r,cc,v,disc,d, shadeR,shadeG,shadeB;

    result[0] = 0;

    for(int i=0;i<spheres.length();i++)//sphere index
    {
        r = spheres[i].radius;
        spherePosition = spheres[i].position;

        EO = spherePosition-camera;

        cc = QVector3D::dotProduct(EO,EO);
        v = QVector3D::dotProduct(EO,ray);

        disc = r*r - (cc-v*v);

        if(disc>0)
        {
            d = sqrt(disc);
            if(v-d<closestPolygon)
            {
                closestPolygon = v-d;
                result[0] = 1;
                pointOfIntersection = camera + (v-d)*ray;

                //Ambience

                shadeR = spheres[i].ambience[0]*sceneAmbience;
                shadeG = spheres[i].ambience[1]*sceneAmbience;
                shadeB = spheres[i].ambience[2]*sceneAmbience;

                for(int j=0;j<lightBulbs.size();j++)
                {

                    lightPosition = lightBulbs[j].position;

                    //Lambertian

                    sphereNormal = (pointOfIntersection - spherePosition).normalized();
                    lightVector = (lightPosition - pointOfIntersection).normalized();
                    double lightmagnitude = QVector3D::dotProduct(sphereNormal,lightVector);
                    double l = max(0.0,(lightmagnitude));

                    shadeR += spheres[i].diffuse[0]*lightBulbs[j].intensity[0]*l;
                    shadeG += spheres[i].diffuse[1]*lightBulbs[j].intensity[1]*l;
                    shadeB += spheres[i].diffuse[2]*lightBulbs[j].intensity[2]*l;

                    //Blinn-Phong

                    cameraVector = (camera-pointOfIntersection).normalized();
                    h = (cameraVector + lightVector).normalized();
                    double specularmagnitude = QVector3D::dotProduct(sphereNormal,h);
                    double s = pow(max(0.0,specularmagnitude),100);

                    shadeR += spheres[i].specular[0]*lightBulbs[j].intensity[0]*s;
                    shadeG += spheres[i].specular[1]*lightBulbs[j].intensity[1]*s;
                    shadeB += spheres[i].specular[2]*lightBulbs[j].intensity[2]*s;

                }
                result[1] = shadeR;
                result[2] = shadeG;
                result[3] = shadeB;
            }
        }

    }

    result[4] = closestPolygon;
    return result;

}

QVector<double> GLWidget::rayTracer(QVector3D ray, QVector3D camera)
{
    QVector<double> result(5),intersectionResult;
    double closestPolygon = pow(10,10);
    QVector3D EO;

    double rr,cc,v,disc;

    intersectionResult = intersectionSpheres(ray,camera,closestPolygon);
    if(intersectionResult[0] = 1)
    {
        result[1] = intersectionResult[1];
        result[2] = intersectionResult[2];
        result[3] = intersectionResult[3];
        closestPolygon = intersectionResult[4];

    }

    return result;

//    if(disc<=0)//ray =! intersect sphere
//    {
//        result.append(0.0);
//        return result;
//    }

//    else//intersected
//    {
//        result.append(1.0);
//        return result;
//    }

}

void GLWidget::about()
{
    QString vnum;
    QString mess, notes;
    QString title="Images in Qt and Opengl ";

    vnum.setNum ( MYVERSION );
    mess="Qt OpenGl image demo Release Version: ";
    mess = mess+vnum;
    notes = "\n\n News: Every QImage is now on stack, there is no way for memory leak. -- Lucky";
    mess = mess+notes;
    QMessageBox::information( this, title, mess, QMessageBox::Ok );
}

void GLWidget::help()
{
    QString vnum;
    QString mess, notes;
    QString title="qtglimages";

    vnum.setNum ( MYVERSION);
    mess="Simple Image Handling in Qt/Opengl by Brian Wyvill Release Version: ";
    mess = mess+vnum;
    notes = "\n\n Save and Load images for display.  Also Make an image such as output from a ray tracer. ";
    mess = mess+notes;
    QMessageBox::information( this, title, mess, QMessageBox::Ok );
}

<|endoftext|>


<commit_before>/*
 *  ******************************************************************************
 *  *
 *  *
 *  * This program and the accompanying materials are made available under the
 *  * terms of the Apache License, Version 2.0 which is available at
 *  * https://www.apache.org/licenses/LICENSE-2.0.
 *  *
 *  * See the NOTICE file distributed with this work for additional
 *  * information regarding copyright ownership.
 *  * 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.
 *  *
 *  * SPDX-License-Identifier: Apache-2.0
 *  *****************************************************************************
 */

//
// Created by raver119 on 29/10/17.
//

#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_randomuniform)

#include <ops/declarable/CustomOperations.h>
#include <helpers/RandomLauncher.h>
#include <ops/declarable/helpers/random.h>

namespace sd {
    namespace ops {
        ///////////////////////
        /**
         * uniform distribution
         * takes 1 ndarray
         *
         * T arguments map:
         * TArgs[0] - min for rng
         * TArgs[1] - max for rng
         */
        CUSTOM_OP_IMPL(randomuniform, -1, 1, true, 0, -1) {
            // uniform distribution
            auto rng = block.randomGenerator();
            auto dtype = DataType::FLOAT32;
            if (block.getIArguments()->size())
                dtype = (DataType)INT_ARG(0);

            if(block.getIArguments()->size() > 1) {
                auto seed = INT_ARG(1);
                rng.setStates(seed,seed ^ 0xdeadbeef);
                nd4j_debug("randomuniform: Setting seed %d\n",seed);
                //rng.setSeed(seed);
            }

            auto min = block.width() > 1 ? INPUT_VARIABLE(1) : (NDArray*) nullptr;
            auto max = block.width() > 2 ? INPUT_VARIABLE(2) : (NDArray*) nullptr;
            bool disposable = false;

            if (min == nullptr && max == nullptr && block.numT() >= 2) {
                min = NDArrayFactory::create_(dtype, block.launchContext());
                max = NDArrayFactory::create_(dtype, block.launchContext());
                min->p(0, T_ARG(0));
                max->p(0, T_ARG(1));
                disposable = true;
            }

            auto output = OUTPUT_VARIABLE(0);
            REQUIRE_TRUE(output->dataType() == dtype, 0, "RandomUniform: data type of output should be equals to given.");

            helpers::fillRandomUniform(block.launchContext(), rng, min, max, output);

            if (disposable) {
                delete min;
                delete max;
            }
            return Status::OK();
        }

        DECLARE_SHAPE_FN(randomuniform) {
            auto in = INPUT_VARIABLE(0);
            //auto min = INPUT_VARIABLE(1);
            auto shape = in->template asVectorT<Nd4jLong>();
            auto dtype = DataType::FLOAT32; //ArrayOptions::dataType(inputShape->at(1)); // output type is by given min

            if (block.getIArguments()->size())
                dtype = (DataType)INT_ARG(0);
            if (block.width() > 1)
                REQUIRE_TRUE(dtype == INPUT_VARIABLE(1)->dataType(), 0, "RandomUniform: data type of output and min/max args should be the same");

            auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(dtype, 'c', shape);
            return SHAPELIST(newShape);
        }

        DECLARE_TYPES(randomuniform) {
            getOpDescriptor()
                    ->setAllowedInputTypes(0, {ALL_INTS})
                    ->setAllowedInputTypes(1, {ALL_INTS, ALL_FLOATS})
                    ->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
                    ->setAllowedOutputTypes({ALL_FLOATS, ALL_INTS});
        }
    }
}

#endif<commit_msg>uniform: change description. -2 (or values below -1 ) means unknown number of arguments or no arguments at all.<commit_after>/*
 *  ******************************************************************************
 *  *
 *  *
 *  * This program and the accompanying materials are made available under the
 *  * terms of the Apache License, Version 2.0 which is available at
 *  * https://www.apache.org/licenses/LICENSE-2.0.
 *  *
 *  * See the NOTICE file distributed with this work for additional
 *  * information regarding copyright ownership.
 *  * 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.
 *  *
 *  * SPDX-License-Identifier: Apache-2.0
 *  *****************************************************************************
 */

//
// Created by raver119 on 29/10/17.
//

#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_randomuniform)

#include <ops/declarable/CustomOperations.h>
#include <helpers/RandomLauncher.h>
#include <ops/declarable/helpers/random.h>

namespace sd {
    namespace ops {
        ///////////////////////
        /**
         * uniform distribution
         * takes 1 ndarray
         *
         * T arguments map:
         * TArgs[0] - min for rng
         * TArgs[1] - max for rng
         */
        CUSTOM_OP_IMPL(randomuniform, -1, 1, true, 0, -2) {
            // uniform distribution
            auto rng = block.randomGenerator();
            auto dtype = DataType::FLOAT32;
            if (block.getIArguments()->size())
                dtype = (DataType)INT_ARG(0);

            if(block.getIArguments()->size() > 1) {
                auto seed = INT_ARG(1);
                rng.setStates(seed,seed ^ 0xdeadbeef);
                nd4j_debug("randomuniform: Setting seed %d\n",seed);
                //rng.setSeed(seed);
            }

            auto min = block.width() > 1 ? INPUT_VARIABLE(1) : (NDArray*) nullptr;
            auto max = block.width() > 2 ? INPUT_VARIABLE(2) : (NDArray*) nullptr;
            bool disposable = false;

            if (min == nullptr && max == nullptr && block.numT() >= 2) {
                min = NDArrayFactory::create_(dtype, block.launchContext());
                max = NDArrayFactory::create_(dtype, block.launchContext());
                min->p(0, T_ARG(0));
                max->p(0, T_ARG(1));
                disposable = true;
            }

            auto output = OUTPUT_VARIABLE(0);
            REQUIRE_TRUE(output->dataType() == dtype, 0, "RandomUniform: data type of output should be equals to given.");

            helpers::fillRandomUniform(block.launchContext(), rng, min, max, output);

            if (disposable) {
                delete min;
                delete max;
            }
            return Status::OK();
        }

        DECLARE_SHAPE_FN(randomuniform) {
            auto in = INPUT_VARIABLE(0);
            //auto min = INPUT_VARIABLE(1);
            auto shape = in->template asVectorT<Nd4jLong>();
            auto dtype = DataType::FLOAT32; //ArrayOptions::dataType(inputShape->at(1)); // output type is by given min

            if (block.getIArguments()->size())
                dtype = (DataType)INT_ARG(0);
            if (block.width() > 1)
                REQUIRE_TRUE(dtype == INPUT_VARIABLE(1)->dataType(), 0, "RandomUniform: data type of output and min/max args should be the same");

            auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(dtype, 'c', shape);
            return SHAPELIST(newShape);
        }

        DECLARE_TYPES(randomuniform) {
            getOpDescriptor()
                    ->setAllowedInputTypes(0, {ALL_INTS})
                    ->setAllowedInputTypes(1, {ALL_INTS, ALL_FLOATS})
                    ->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
                    ->setAllowedOutputTypes({ALL_FLOATS, ALL_INTS});
        }
    }
}

#endif<|endoftext|>


<commit_before>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 <ctype.h>
#include <assert.h>
#include <string.h>
// offsetof macro
#include <stddef.h>

#include "port_malloc.h"
#include "port_unwind.h"
#include "port_modules.h"

#include "port_crash_handler.h"
#include "port_frame_info.h"
#include "stack_dump.h"

static native_module_t* g_modules = NULL;

// Is called to fill modules list (should be called under lock)
static void sd_fill_modules()
{
    if (g_modules)
        return;

    int count;
    bool res = port_get_all_modules(&g_modules, &count);
    assert(res && g_modules && count);
}

// "%s::%s (%s): %s:%d" - class::name (signature): file:line
static const char* vm_fmt_tbl[] = {
// method_class_name is present
    "%s::%s (%s): %s:%d\n",
    "%s::%s (%s)\n", // No sourcefile
    "%s::%s: %s:%d\n", // No signature
    "%s::%s\n", // No signature no sourcefile
// method_class_name is absent
    "%s (%s): %s:%d\n",
    "%s (%s)\n", // No sourcefile
    "%s: %s:%d\n", // No signature
    "%s\n", // No signature no sourcefile
};

static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi)
{
    if (!fi->method_name)
        return;

    if (count >= 0)
        fprintf(file, "%3d: ", count);
    else
        fprintf(file, "     "); // additional VM info - indent

    const void* args[5] = {fi->method_class_name, fi->method_name,
                     fi->method_signature, fi->source_file_name,
                     (const void*)(size_t)fi->source_line_number};
    const void** pargs = args;
    int fmt_num = 0;

    if (!fi->method_class_name)
    {
        fmt_num += 4;
        pargs++;
    }
    if (!fi->method_signature)
    {
        fmt_num += 2;
        args[2] = args[3];
        args[3] = args[4];
    }
    if (!fi->source_file_name)
        fmt_num += 1;

    fprintf(file, vm_fmt_tbl[fmt_num],
                  pargs[0], pargs[1], pargs[2], pargs[3], pargs[4]);
}

static void sd_print_c_line(FILE* file, int count, CFunInfo* cfi)
{
    if (!cfi->name)
        return;

    fprintf(file, "%3d: %s (%s:%d)\n",
        count, cfi->name,
        cfi->filename ? cfi->filename : "??",
        cfi->line);
}

static void sd_print_modules()
{
    sd_fill_modules(); // Fill modules table if needed
    fprintf(stderr, "\nLoaded modules:\n\n");
    port_dump_modules(g_modules, stderr);
}

static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind)
{
    if (!regs)
    {
        fprintf(stderr, "\nNo stack trace due to registers info absence\n");
        return;
    }

    fprintf(stderr, "\nStack trace:\n");

    Registers locregs = *regs;
    UnwindContext uwcontext;
    bool hasnative = false;

    if (port_init_unwind_context(&uwcontext, g_modules, &locregs))
        hasnative = true;

    port_stack_frame_info uwinfo;

    int framenum = 0;
    int uwresult = -1;

    // Prepare VM-specific struct for stack iteration
    if (unwind)
    {
        memset(&uwinfo, 0, sizeof(port_stack_frame_info));
        uwresult = unwind(&locregs, &uwinfo);
    }

    if (uwresult > 0)
    {
        uwinfo.iteration_state = STD_ALLOCA(uwresult);
        memset(uwinfo.iteration_state, 0, uwresult);
        uwresult = unwind(&locregs, &uwinfo);
        assert(uwresult <= 0);
    }

    while (true)
    {
        // Unwinding with VM callback
        if (unwind && uwresult == 0)
        {
            sd_print_vm_line(stderr, framenum++, &uwinfo);
            // Cleanup frame info except 'iteration_state'
            memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state));
            // Try unwinding by the callback for next iteration
            uwresult = unwind(&locregs, &uwinfo);
            continue;
        }

        // Print native frame info
        CFunInfo cfi = {0};
        native_module_t* module = port_find_module(g_modules, locregs.get_ip());
        sd_get_c_method_info(&cfi, module, locregs.get_ip());
        sd_print_c_line(stderr, framenum++, &cfi);

        if (unwind && uwresult < 0 && uwinfo.method_name)
        { // VM has not unwound but has provided additional frame info
            sd_print_vm_line(stderr, -1, &uwinfo); // Print as additional info
        }

        if (!hasnative) // Native unwinding is not initialized
            break;

        // Try native unwinding
        bool nativeres = port_unwind_frame(&uwcontext, &locregs);

        if (!nativeres)
            break; // Neither VM calback nor native unwinding can unwind the frame

        // Cleanup frame info except 'iteration_state'
        memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state));
        // Try unwinding by the callback for next iteration
        uwresult = unwind(&locregs, &uwinfo);
    }

    if (hasnative)
        port_clean_unwind_context(&uwcontext);

    fprintf(stderr, "<end of stack trace>\n");
    fflush(stderr);
}

struct sig_name_t
{
    int    num;
    char*  name;
};

static sig_name_t sig_names[] =
{
    {PORT_SIGNAL_GPF,            "GENERAL_PROTECTION_FAULT"},
    {PORT_SIGNAL_STACK_OVERFLOW, "STACK_OVERFLOW"},
    {PORT_SIGNAL_ABORT,          "ABORT" },
    {PORT_SIGNAL_QUIT,           "QUIT"},
    {PORT_SIGNAL_CTRL_C,         "CTRL_C" },
    {PORT_SIGNAL_CTRL_BREAK,     "CTRL_BREAK" },
    {PORT_SIGNAL_BREAKPOINT,     "BREAKPOINT"},
    {PORT_SIGNAL_ARITHMETIC,     "ARITHMETIC_EXCEPTION" },
    {PORT_SIGNAL_UNKNOWN,        "UNKNOWN"}
};

static const char* get_sig_name(int signum)
{
    for (int i = 0; i < sizeof(sig_names)/sizeof(sig_names[0]); i++)
    {
        if (signum == sig_names[i].num)
            return sig_names[i].name;
    }

    return "unknown signal";
}

static void print_name_and_context(int signum, Registers* regs)
{
    // Print signal name
    fprintf(stderr, "\nSignal reported: %s\n", get_sig_name(signum));

    // Print register state
    if (regs)
        print_reg_state(regs);
    else
        fprintf(stderr, "\nRegisters info is absent\n");
}

void sd_print_crash_info(int signum, Registers* regs, port_unwind_compiled_frame unwind)
{
    // Print signal name and register info
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_REGISTERS)
        print_name_and_context(signum, regs);

    // Print command line and working directory
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_COMMAND_LINE)
        sd_print_cmdline_cwd();

    // Print program environment info
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_ENVIRONMENT)
        sd_print_environment();

    // Print the whole list of modules
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_MODULES)
        sd_print_modules();

    // Print stack of crashed module
    if (port_crash_handler_get_flags() & PORT_CRASH_STACK_DUMP)
        sd_print_stack(regs, unwind);
}
<commit_msg>Applied patch from HARMONY-5685 [drlvm][port][signals] Crash handler does not print stack dump when list of modules was not printed<commit_after>/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 <ctype.h>
#include <assert.h>
#include <string.h>
// offsetof macro
#include <stddef.h>

#include "port_malloc.h"
#include "port_unwind.h"
#include "port_modules.h"

#include "port_crash_handler.h"
#include "port_frame_info.h"
#include "stack_dump.h"

static native_module_t* g_modules = NULL;

// Is called to fill modules list (should be called under lock)
static void sd_fill_modules()
{
    if (g_modules)
        return;

    int count;
    bool res = port_get_all_modules(&g_modules, &count);
    assert(res && g_modules && count);
}

// "%s::%s (%s): %s:%d" - class::name (signature): file:line
static const char* vm_fmt_tbl[] = {
// method_class_name is present
    "%s::%s (%s): %s:%d\n",
    "%s::%s (%s)\n", // No sourcefile
    "%s::%s: %s:%d\n", // No signature
    "%s::%s\n", // No signature no sourcefile
// method_class_name is absent
    "%s (%s): %s:%d\n",
    "%s (%s)\n", // No sourcefile
    "%s: %s:%d\n", // No signature
    "%s\n", // No signature no sourcefile
};

static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi)
{
    if (!fi->method_name)
        return;

    if (count >= 0)
        fprintf(file, "%3d: ", count);
    else
        fprintf(file, "     "); // additional VM info - indent

    const void* args[5] = {fi->method_class_name, fi->method_name,
                     fi->method_signature, fi->source_file_name,
                     (const void*)(size_t)fi->source_line_number};
    const void** pargs = args;
    int fmt_num = 0;

    if (!fi->method_class_name)
    {
        fmt_num += 4;
        pargs++;
    }
    if (!fi->method_signature)
    {
        fmt_num += 2;
        args[2] = args[3];
        args[3] = args[4];
    }
    if (!fi->source_file_name)
        fmt_num += 1;

    fprintf(file, vm_fmt_tbl[fmt_num],
                  pargs[0], pargs[1], pargs[2], pargs[3], pargs[4]);
}

static void sd_print_c_line(FILE* file, int count, CFunInfo* cfi)
{
    if (!cfi->name)
        return;

    fprintf(file, "%3d: %s (%s:%d)\n",
        count, cfi->name,
        cfi->filename ? cfi->filename : "??",
        cfi->line);
}

static void sd_print_modules()
{
    sd_fill_modules(); // Fill modules table if needed
    fprintf(stderr, "\nLoaded modules:\n\n");
    port_dump_modules(g_modules, stderr);
}

static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind)
{
    if (!regs)
    {
        fprintf(stderr, "\nNo stack trace due to registers info absence\n");
        return;
    }

    fprintf(stderr, "\nStack trace:\n");

    Registers locregs = *regs;
    UnwindContext uwcontext;
    bool hasnative = false;

    if (port_init_unwind_context(&uwcontext, g_modules, &locregs))
        hasnative = true;

    port_stack_frame_info uwinfo;

    int framenum = 0;
    int uwresult = -1;

    // Prepare VM-specific struct for stack iteration
    if (unwind)
    {
        memset(&uwinfo, 0, sizeof(port_stack_frame_info));
        uwresult = unwind(&locregs, &uwinfo);
    }

    if (uwresult > 0)
    {
        uwinfo.iteration_state = STD_ALLOCA(uwresult);
        memset(uwinfo.iteration_state, 0, uwresult);
        uwresult = unwind(&locregs, &uwinfo);
        assert(uwresult <= 0);
    }

    while (true)
    {
        // Unwinding with VM callback
        if (unwind && uwresult == 0)
        {
            sd_print_vm_line(stderr, framenum++, &uwinfo);
            // Cleanup frame info except 'iteration_state'
            memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state));
            // Try unwinding by the callback for next iteration
            uwresult = unwind(&locregs, &uwinfo);
            continue;
        }

        // Print native frame info
        CFunInfo cfi = {0};
        native_module_t* module = port_find_module(uwcontext.modules, locregs.get_ip());
        sd_get_c_method_info(&cfi, module, locregs.get_ip());
        sd_print_c_line(stderr, framenum++, &cfi);

        if (unwind && uwresult < 0 && uwinfo.method_name)
        { // VM has not unwound but has provided additional frame info
            sd_print_vm_line(stderr, -1, &uwinfo); // Print as additional info
        }

        if (!hasnative) // Native unwinding is not initialized
            break;

        // Try native unwinding
        bool nativeres = port_unwind_frame(&uwcontext, &locregs);

        if (!nativeres)
            break; // Neither VM calback nor native unwinding can unwind the frame

        // Cleanup frame info except 'iteration_state'
        memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state));
        // Try unwinding by the callback for next iteration
        uwresult = unwind(&locregs, &uwinfo);
    }

    if (hasnative)
        port_clean_unwind_context(&uwcontext);

    fprintf(stderr, "<end of stack trace>\n");
    fflush(stderr);
}

struct sig_name_t
{
    int    num;
    char*  name;
};

static sig_name_t sig_names[] =
{
    {PORT_SIGNAL_GPF,            "GENERAL_PROTECTION_FAULT"},
    {PORT_SIGNAL_STACK_OVERFLOW, "STACK_OVERFLOW"},
    {PORT_SIGNAL_ABORT,          "ABORT" },
    {PORT_SIGNAL_QUIT,           "QUIT"},
    {PORT_SIGNAL_CTRL_C,         "CTRL_C" },
    {PORT_SIGNAL_CTRL_BREAK,     "CTRL_BREAK" },
    {PORT_SIGNAL_BREAKPOINT,     "BREAKPOINT"},
    {PORT_SIGNAL_ARITHMETIC,     "ARITHMETIC_EXCEPTION" },
    {PORT_SIGNAL_UNKNOWN,        "UNKNOWN"}
};

static const char* get_sig_name(int signum)
{
    for (int i = 0; i < sizeof(sig_names)/sizeof(sig_names[0]); i++)
    {
        if (signum == sig_names[i].num)
            return sig_names[i].name;
    }

    return "unknown signal";
}

static void print_name_and_context(int signum, Registers* regs)
{
    // Print signal name
    fprintf(stderr, "\nSignal reported: %s\n", get_sig_name(signum));

    // Print register state
    if (regs)
        print_reg_state(regs);
    else
        fprintf(stderr, "\nRegisters info is absent\n");
}

void sd_print_crash_info(int signum, Registers* regs, port_unwind_compiled_frame unwind)
{
    // Print signal name and register info
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_REGISTERS)
        print_name_and_context(signum, regs);

    // Print command line and working directory
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_COMMAND_LINE)
        sd_print_cmdline_cwd();

    // Print program environment info
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_ENVIRONMENT)
        sd_print_environment();

    // Print the whole list of modules
    if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_MODULES)
        sd_print_modules();

    // Print stack of crashed module
    if (port_crash_handler_get_flags() & PORT_CRASH_STACK_DUMP)
        sd_print_stack(regs, unwind);
}
<|endoftext|>