<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#include "../StroikaPreComp.h"

#include "../Characters/Format.h"
#include "../Characters/String_Constant.h"
#include "../Characters/ToString.h"
#include "../Containers/Bijection.h"
#include "../DataExchange/Variant/CharacterDelimitedLines/Reader.h"
#include "../Debug/Trace.h"
#if qPlatform_Windows
#include "../Execution/Platform/Windows/Exception.h"
#endif
#include "../IO/FileSystem/FileInputStream.h"
#include "../IO/FileSystem/PathName.h"

#include "InternetMediaTypeRegistry.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Containers;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::Execution;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

using FileSuffixType = InternetMediaTypeRegistry::FileSuffixType;

#if qPlatform_Windows
using Stroika::Foundation::Execution::Platform::Windows::ThrowIfNotERROR_SUCCESS;
#endif

#if qPlatform_Linux
// not sure what platforms have this
namespace {
    Mapping<FileSuffixType, InternetMediaType> GetGlobsFile_ ()
    {
        auto readGlobsFile = []() -> Mapping<FileSuffixType, InternetMediaType> {
#if USE_NOISY_TRACE_IN_THIS_MODULE_
            Debug::TraceContextBumper ctx{L"{}readGlobsFile"};
#endif
            Mapping<FileSuffixType, InternetMediaType> results{};
            for (Sequence<String> line : DataExchange::Variant::CharacterDelimitedLines::Reader{{':'}}.ReadMatrix (IO::FileSystem::FileInputStream::New (L"/usr/share/mime/globs"))) {
                if (line.length () == 2) {
                    String glob = line[1];
                    if (glob.StartsWith ('*')) {
                        glob = glob.SubString (1);
                    }
                    results.Add (glob, InternetMediaType{line[0]});
                }
            }
#if USE_NOISY_TRACE_IN_THIS_MODULE_
            DbgTrace (L"returning %s", Characters::ToString (results).c_str ());
#endif
            return results;
        };
        static const Mapping<FileSuffixType, InternetMediaType> kData_ = readGlobsFile ();
        return kData_;
    }
}
#endif

#if qPlatform_Windows
namespace {
    // Based on code from HealthFrame. MAYBE someday do more generic version of this - as helper
    // @see https://stroika.atlassian.net/browse/STK-575
    struct OptionsFileHelper_ {
        OptionsFileHelper_ (HKEY hkey)
            : fKey (hkey)
        {
            Assert (nullptr != INVALID_HANDLE_VALUE);
            if (hkey == INVALID_HANDLE_VALUE or hkey == nullptr)
                [[UNLIKELY_ATTR]]
                {
                    Execution::Throw (SystemErrorException<> (ERROR_INVALID_HANDLE, system_category ()), "OptionsFileHelper::CTOR - bad handle");
                }
        }
        OptionsFileHelper_ (HKEY parentKey, const String& path, REGSAM samDesired = KEY_READ | KEY_WRITE)
            : fKey (OpenWithCreateAlongPath (parentKey, path, samDesired))
        {
            if (parentKey == INVALID_HANDLE_VALUE or parentKey == nullptr)
                [[UNLIKELY_ATTR]]
                {
                    Execution::Throw (SystemErrorException<> (ERROR_INVALID_HANDLE, system_category ()), "OptionsFileHelper::CTOR - bad handle");
                }
        }
        OptionsFileHelper_ ()                          = delete;
        OptionsFileHelper_ (const OptionsFileHelper_&) = delete;
        const OptionsFileHelper_& operator= (const OptionsFileHelper_&) const = delete;
        ~OptionsFileHelper_ ()
        {
            Assert (nullptr != INVALID_HANDLE_VALUE);
            Assert (fKey != nullptr);
            Assert (fKey != INVALID_HANDLE_VALUE);
            ::RegCloseKey (fKey);
        }
        /*
         * Walk the given path (in segments) - and make sure each exists, and create each segment if it doesn't
         * exist.Finally - do a regular registry open with access permissions 'samDesired'.< / p>
         */
        static HKEY OpenWithCreateAlongPath (HKEY parentKey, const String& path, REGSAM samDesired = KEY_READ | KEY_WRITE)
        {
#if USE_NOISY_TRACE_IN_THIS_MODULE_
            Debug::TraceContextBumper trcCtx{Stroika_Foundation_Debug_OptionalizeTraceArgs (L"{}::OptionsFileHelper_::OpenWithCreateAlongPath", L"parentKey=%p, path='%s'", parentKey, path.c_str ())};
#endif
            Require (parentKey != nullptr);
            size_t prevPos = 0;
            HKEY   curPar  = parentKey;
            for (;;) {
                size_t    endPos    = path.find ('\\', prevPos);
                SDKString segName   = path.AsSDKString ().substr (prevPos, endPos == SDKString::npos ? endPos : (endPos - prevPos));
                REGSAM    createSAM = (endPos == SDKString::npos) ? samDesired : KEY_READ;
                HKEY      newKey    = static_cast<HKEY> (INVALID_HANDLE_VALUE);

                ThrowIfNotERROR_SUCCESS (::RegCreateKeyEx (curPar, segName.c_str (), 0, REG_NONE, REG_OPTION_NON_VOLATILE, createSAM, nullptr, &newKey, nullptr));
                if (curPar != parentKey) {
                    ::RegCloseKey (curPar);
                }
                curPar = newKey;
                if (endPos == SDKString::npos) {
                    return newKey;
                }
                prevPos = endPos + 1;
            }
        }

        nonvirtual bool LookupPref (const String& prefName, string* value, DWORD* regStrType = nullptr) const
        {
            RequireNotNull (value);
            Assert (fKey != INVALID_HANDLE_VALUE);
            string strValue;
            DWORD  dwType  = 0;
            DWORD  dwCount = 0;
            LONG   lResult = ::RegQueryValueExA (fKey, prefName.AsNarrowSDKString ().c_str (), nullptr, &dwType, nullptr, &dwCount);
            if (lResult == ERROR_SUCCESS) {
                if (dwType == REG_SZ or dwType == REG_EXPAND_SZ) {
                    if (dwCount != 0) {
                        strValue.resize (dwCount);
                        lResult = ::RegQueryValueExA (fKey, prefName.AsNarrowSDKString ().c_str (), nullptr, &dwType, (LPBYTE) & (*strValue.begin ()), &dwCount);
                    }
                }
                else {
                    lResult = !ERROR_SUCCESS;
                }
            }
            if (lResult == ERROR_SUCCESS) {
                if (dwType == REG_SZ or dwType == REG_EXPAND_SZ) {
                    *value = strValue.c_str (); // copying like this loses xtra NUL-byte if there is one from read...
                    if (regStrType != nullptr) {
                        *regStrType = dwType;
                    }
                    return true;
                }
            }
            return false;
        }
        nonvirtual bool LookupPref (const String& prefName, wstring* value, DWORD* regStrType = nullptr) const
        {
            RequireNotNull (value);
            Assert (fKey != INVALID_HANDLE_VALUE);
            wstring strValue;
            DWORD   dwType  = 0;
            DWORD   dwCount = 0;
            LONG    lResult = ::RegQueryValueExW (fKey, prefName.c_str (), nullptr, &dwType, nullptr, &dwCount);
            if (lResult == ERROR_SUCCESS) {
                if (dwType == REG_SZ or dwType == REG_EXPAND_SZ) {
                    if (dwCount != 0) {
                        strValue.resize (dwCount);
                        lResult = ::RegQueryValueExW (fKey, prefName.c_str (), nullptr, &dwType, (LPBYTE) & (*strValue.begin ()), &dwCount);
                    }
                }
                else {
                    lResult = !ERROR_SUCCESS;
                }
            }
            if (lResult == ERROR_SUCCESS) {
                if (dwType == REG_SZ or dwType == REG_EXPAND_SZ) {
                    *value = strValue.c_str (); // copying like this loses xtra NUL-byte if there is one from read...
                    if (regStrType != nullptr) {
                        *regStrType = dwType;
                    }
                    return true;
                }
            }
            // If not success - then maybe cuz non-UNICODE functions not available - so try to read a non-UNICODE string
            {
                string tmp;
                if (LookupPref (prefName, &tmp, regStrType)) {
                    *value = NarrowSDKStringToWide (tmp);
                    return true;
                }
            }
            return false;
        }

    private:
        HKEY fKey;
    };
    optional<String> GrabRegistryStringValue_ (HKEY parentKey, const String& path)
    {
        try {
            String eltPath = path;
            String parentPath;
            {
                size_t i = path.rfind ('\\');
                if (i != SDKString::npos) {
                    parentPath = path.substr (0, i);
                    eltPath    = path.substr (i + 1);
                }
            }
            OptionsFileHelper_ ofh (parentKey, parentPath, KEY_READ);
            wstring            result;
            if (ofh.LookupPref (eltPath, &result)) {
                return result;
            }
        }
        catch (...) {
            // ignore
        }
        return {};
    }
}
#endif

/*
 ********************************************************************************
 *************************** InternetMediaTypeRegistry **************************
 ********************************************************************************
 */
optional<FileSuffixType> InternetMediaTypeRegistry::GetPreferredAssociatedFileSuffix (const InternetMediaType& ct) const
{
#if qPlatform_Windows
    return GrabRegistryStringValue_ (HKEY_CLASSES_ROOT, Characters::Format (L"MIME\\Database\\Content Type\\%s\\Extension", ct.As<String> ().c_str ()));
#else
    AssertNotImplemented ();
    return {};
#endif
}

Sequence<String> InternetMediaTypeRegistry::GetAssociatedFileSuffixes (const InternetMediaType& ct, bool includeMoreGeneralTypes) const
{
#if qPlatform_Windows
    Sequence<String> tmp;
    // @todo - hack - inadequate, but good enough to start
    if (auto i = GetPreferredAssociatedFileSuffix (ct)) {
        tmp += *i;
    }
    return tmp;
#else
    AssertNotImplemented ();
    return {};
#endif
}

optional<String> InternetMediaTypeRegistry::GetAssociatedPrettyName (const InternetMediaType& ct) const
{
#if qPlatform_Windows
    if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
        if (optional<String> fileTypeID = GrabRegistryStringValue_ (HKEY_CLASSES_ROOT, *fileSuffix)) {
            return GrabRegistryStringValue_ (HKEY_CLASSES_ROOT, *fileTypeID);
        }
    }
#else
    AssertNotImplemented ();
#endif
    return {};
}

optional<InternetMediaType> InternetMediaTypeRegistry::GetAssociatedContentType (const FileSuffixType& fileNameOrSuffix) const
{
    FileSuffixType suffix = IO::FileSystem::GetFileSuffix (fileNameOrSuffix);
#if qPlatform_Linux
    return GetGlobsFile_ ().Lookup (suffix);
#elif qPlatform_Windows
    if (optional<String> oct = GrabRegistryStringValue_ (HKEY_CLASSES_ROOT, Characters::Format (L"%s\\Content Type", suffix.c_str ()))) {
        return InternetMediaType{*oct};
    }
#else
    AssertNotImplemented ();
#endif
    return {};
}<commit_msg>rewote InternetMediaTypeRegistry using new Configuration::Platform::Windows::RegistryKey; Slightly differnt semantics so now some lookups on registry could result in exception instead of empty string - may want to revist that but I think reasonable for now.<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#include "../StroikaPreComp.h"

#include "../Characters/Format.h"
#include "../Characters/String_Constant.h"
#include "../Characters/ToString.h"
#include "../Containers/Bijection.h"
#include "../DataExchange/Variant/CharacterDelimitedLines/Reader.h"
#if qPlatform_Windows
#include "../Configuration/Platform/Windows/Registry.h"
#endif
#include "../Debug/Trace.h"
#if qPlatform_Windows
#include "../Execution/Platform/Windows/Exception.h"
#endif
#include "../IO/FileSystem/FileInputStream.h"
#include "../IO/FileSystem/PathName.h"

#include "InternetMediaTypeRegistry.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Characters;
using namespace Stroika::Foundation::Containers;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::Execution;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

using FileSuffixType = InternetMediaTypeRegistry::FileSuffixType;

#if qPlatform_Windows
using Stroika::Foundation::Execution::Platform::Windows::ThrowIfNotERROR_SUCCESS;
#endif

#if qPlatform_Linux
// not sure what platforms have this
namespace {
    Mapping<FileSuffixType, InternetMediaType> GetGlobsFile_ ()
    {
        auto readGlobsFile = []() -> Mapping<FileSuffixType, InternetMediaType> {
#if USE_NOISY_TRACE_IN_THIS_MODULE_
            Debug::TraceContextBumper ctx{L"{}readGlobsFile"};
#endif
            Mapping<FileSuffixType, InternetMediaType> results{};
            for (Sequence<String> line : DataExchange::Variant::CharacterDelimitedLines::Reader{{':'}}.ReadMatrix (IO::FileSystem::FileInputStream::New (L"/usr/share/mime/globs"))) {
                if (line.length () == 2) {
                    String glob = line[1];
                    if (glob.StartsWith ('*')) {
                        glob = glob.SubString (1);
                    }
                    results.Add (glob, InternetMediaType{line[0]});
                }
            }
#if USE_NOISY_TRACE_IN_THIS_MODULE_
            DbgTrace (L"returning %s", Characters::ToString (results).c_str ());
#endif
            return results;
        };
        static const Mapping<FileSuffixType, InternetMediaType> kData_ = readGlobsFile ();
        return kData_;
    }
}
#endif

/*
 ********************************************************************************
 *************************** InternetMediaTypeRegistry **************************
 ********************************************************************************
 */
optional<FileSuffixType> InternetMediaTypeRegistry::GetPreferredAssociatedFileSuffix (const InternetMediaType& ct) const
{
#if qPlatform_Windows
    if (auto fs = Configuration::Platform::Windows::RegistryKey{HKEY_CLASSES_ROOT}.LookupPref (Characters::Format (L"MIME\\Database\\Content Type\\%s\\Extension", ct.As<String> ().c_str ()))) {
        return fs.As<String> ();
    }
#else
    AssertNotImplemented ();
#endif
    return nullopt;
}

Sequence<String> InternetMediaTypeRegistry::GetAssociatedFileSuffixes (const InternetMediaType& ct, bool includeMoreGeneralTypes) const
{
#if qPlatform_Windows
    Sequence<String> tmp;
    // @todo - hack - inadequate, but good enough to start
    if (auto i = GetPreferredAssociatedFileSuffix (ct)) {
        tmp += *i;
    }
    return tmp;
#else
    AssertNotImplemented ();
    return {};
#endif
}

optional<String> InternetMediaTypeRegistry::GetAssociatedPrettyName (const InternetMediaType& ct) const
{
#if qPlatform_Windows
    if (optional<FileSuffixType> fileSuffix = GetPreferredAssociatedFileSuffix (ct)) {
        if (auto fileTypeID = Configuration::Platform::Windows::RegistryKey{HKEY_CLASSES_ROOT}.LookupPref (*fileSuffix)) {
            if (auto prettyName = Configuration::Platform::Windows::RegistryKey{HKEY_CLASSES_ROOT}.LookupPref (fileTypeID.As<String> ())) {
                return prettyName.As<String> ();
            }
        }
    }
#else
    AssertNotImplemented ();
#endif
    return nullopt;
}

optional<InternetMediaType> InternetMediaTypeRegistry::GetAssociatedContentType (const FileSuffixType& fileNameOrSuffix) const
{
    FileSuffixType suffix = IO::FileSystem::GetFileSuffix (fileNameOrSuffix);
#if qPlatform_Linux
    return GetGlobsFile_ ().Lookup (suffix);
#elif qPlatform_Windows
    using Characters::Format;
    using Configuration::Platform::Windows::RegistryKey;
    if (auto oct = RegistryKey{HKEY_CLASSES_ROOT}.LookupPref (Format (L"%s\\Content Type", suffix.c_str ()))) {
        return InternetMediaType{oct.As<String> ()};
    }
#else
    AssertNotImplemented ();
#endif
    return {};
}<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_
#define _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             ******************* ObjectVariantMapper::StructureFieldInfo ********************
             ********************************************************************************
             */
            inline  ObjectVariantMapper::StructureFieldInfo::StructureFieldInfo (size_t fieldOffset, type_index typeInfo, const String& serializedFieldName)
                : fOffset (fieldOffset)
                , fTypeInfo (typeInfo)
                , fSerializedFieldName (serializedFieldName)
            {
            }

            /*
             ********************************************************************************
             ******************************** ObjectVariantMapper ***************************
             ********************************************************************************
             */
            template    <typename CLASS>
            void    ObjectVariantMapper::RegisterClass (const Sequence<StructureFieldInfo>& fieldDescriptions)
            {
                RegisterSerializer (mkSerializerForStruct (typeid (CLASS), sizeof (CLASS), typeInfo));
            }
            template    <typename CLASS>
            void    ObjectVariantMapper::Deserialize (const Memory::VariantValue& v, CLASS* into)
            {
                Deserialize  (typeid (CLASS), v, reinterpret_cast<Byte*> (into));
            }
            template    <typename CLASS>
            CLASS    ObjectVariantMapper::Deserialize (const Memory::VariantValue& v)
            {
                CLASS tmp;
                Deserialize  (v, &tmp);
                return tmp;
            }
            template    <typename CLASS>
            VariantValue    ObjectVariantMapper::Serialize (const CLASS& from)
            {
                return Serialize  (typeid (CLASS), reinterpret_cast<const Byte*> (&from));
            }

        }
    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_*/
<commit_msg>fixed typo in ObjectVariantMapper changes<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_
#define _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             ******************* ObjectVariantMapper::StructureFieldInfo ********************
             ********************************************************************************
             */
            inline  ObjectVariantMapper::StructureFieldInfo::StructureFieldInfo (size_t fieldOffset, type_index typeInfo, const String& serializedFieldName)
                : fOffset (fieldOffset)
                , fTypeInfo (typeInfo)
                , fSerializedFieldName (serializedFieldName)
            {
            }

            /*
             ********************************************************************************
             ******************************** ObjectVariantMapper ***************************
             ********************************************************************************
             */
            template    <typename CLASS>
            void    ObjectVariantMapper::RegisterClass (const Sequence<StructureFieldInfo>& fieldDescriptions)
            {
                RegisterSerializer (mkSerializerForStruct (typeid (CLASS), sizeof (CLASS), fieldDescriptions));
            }
            template    <typename CLASS>
            void    ObjectVariantMapper::Deserialize (const Memory::VariantValue& v, CLASS* into)
            {
                Deserialize  (typeid (CLASS), v, reinterpret_cast<Byte*> (into));
            }
            template    <typename CLASS>
            CLASS    ObjectVariantMapper::Deserialize (const Memory::VariantValue& v)
            {
                CLASS tmp;
                Deserialize  (v, &tmp);
                return tmp;
            }
            template    <typename CLASS>
            VariantValue    ObjectVariantMapper::Serialize (const CLASS& from)
            {
                return Serialize  (typeid (CLASS), reinterpret_cast<const Byte*> (&from));
            }

        }
    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_*/
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    "../../Characters/Format.h"
#include    "../BadFormatException.h"

#include    "SAXObjectReader.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::DataExchangeFormat;
using   namespace   Stroika::Foundation::DataExchangeFormat::XML;

/*
 ********************************************************************************
 ****************************** XML::SAXObjectReader ****************************
 ********************************************************************************
 */
#if     qDefaultTracingOn
wstring SAXObjectReader::TraceLeader_ () const
{
    wstring l;
    l.reserve (fStack_.size ());
    for (size_t i = 0; i < fStack_.size (); ++i) {
        l += L" ";
    }
    return l;
}
#endif
class   SAXObjectReader::MyCallback_ : public SAXCallbackInterface {
public:
    MyCallback_ (SAXObjectReader& r)
        : fSAXObjectReader_ (r) {
    }
private:
    SAXObjectReader&    fSAXObjectReader_;
public:
    virtual void    StartDocument () override {
    }
    virtual void    EndDocument () override {
    }
    virtual void    StartElement (const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling HandleChildStart ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), localName.c_str ());
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleChildStart (fSAXObjectReader_, uri, localName, qname, attrs);
    }
    virtual void    EndElement (const String& uri, const String& localName, const String& qname) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling EndElement ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), localName.c_str ());
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleEndTag (fSAXObjectReader_);
    }
    virtual void    CharactersInsideElement (const String& text) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling CharactersInsideElement ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), text.c_str () );
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleTextInside (fSAXObjectReader_, text);
    }
};

namespace   {
    struct DocumentReader_ : public SAXObjectReader::ObjectBase {
        shared_ptr<ObjectBase>          fDocEltBuilder;
        bool                            fAnyDocElt;
        String                          fDocEltURI;
        String                          fDocEltName;
        DocumentReader_ (const shared_ptr<ObjectBase>& docEltBuilder)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (true)
            , fDocEltURI ()
            , fDocEltName () {
        }
        DocumentReader_ (const shared_ptr<ObjectBase>& docEltBuilder, const String& checkURI, const String& checkDocEltName)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (false)
            , fDocEltURI (checkURI)
            , fDocEltName (checkDocEltName) {
        }
        virtual void    HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs) override {
            if (not fAnyDocElt) {
                if (localName != fDocEltName or uri != fDocEltURI) {
                    ThrowUnRecognizedStartElt (uri, localName);
                }
            }
            r.Push (fDocEltBuilder);
        }
        virtual void    HandleTextInside (SAXObjectReader& r, const String& text)  override {
            // OK so long as text is whitespace - or comment. Probably should check/assert, but KISS..., and count on validation to
            // assure input is valid
            Assert (text.IsWhitespace ());
        }
        virtual void    HandleEndTag (SAXObjectReader& r) override {
            r.Pop ();
        }
    };
}
void    SAXObjectReader::Run (const shared_ptr<ObjectBase>& docEltBuilder, const Streams::BinaryInputStream& in)
{
    RequireNotNull (docEltBuilder);
    Require (fStack_.size () == 0);

    Push (shared_ptr<ObjectBase> (DEBUG_NEW DocumentReader_ (docEltBuilder)));

    MyCallback_ cb (*this);
    SAXParse (in, cb);

    Pop (); // the docuemnt reader we just added

    Ensure (fStack_.size () == 0);
}

void    SAXObjectReader::Run (const shared_ptr<ObjectBase>& docEltBuilder, const String& docEltUri, const String& docEltLocalName, const Streams::BinaryInputStream& in)
{
    RequireNotNull (docEltBuilder);
    Require (fStack_.size () == 0);

    Push (shared_ptr<ObjectBase> (DEBUG_NEW DocumentReader_ (docEltBuilder, docEltUri, docEltLocalName)));

    MyCallback_ cb (*this);
    SAXParse (in, cb);

    Pop (); // the docuemnt reader we just added

    Ensure (fStack_.size () == 0);
}

/*
 ********************************************************************************
 ********************* XML::SAXObjectReader::ObjectBase *************************
 ********************************************************************************
 */
SAXObjectReader::ObjectBase::~ObjectBase ()
{
}

/*
 ********************************************************************************
 ************************* XML::BuiltinReader<String> ***************************
 ********************************************************************************
 */
BuiltinReader<String>::BuiltinReader (String* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = String ();
}

void    BuiltinReader<String>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<String>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    (*value_) += text;
}

void    BuiltinReader<String>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 **************************** XML::BuiltinReader<int> ***************************
 ********************************************************************************
 */
BuiltinReader<int>::BuiltinReader (int* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<int>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<int>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<int>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************* XML::BuiltinReader<unsigned int> ***************************
 ********************************************************************************
 */
BuiltinReader<unsigned int>::BuiltinReader (unsigned int* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<unsigned int>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<unsigned int>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<unsigned int>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************************** XML::BuiltinReader<bool> ***************************
 ********************************************************************************
 */
BuiltinReader<bool>::BuiltinReader (bool* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<bool>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<bool>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    String  tmp =   tmpVal_.Trim ().ToLowerCase ();
    (*value_) = (tmp == L"true");
}

void    BuiltinReader<bool>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************************** XML::BuiltinReader<float> ***************************
 ********************************************************************************
 */
BuiltinReader<float>::BuiltinReader (float* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<float>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<float>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = static_cast<float> (Characters::String2Float (tmpVal_.As<wstring> ()));
}

void    BuiltinReader<float>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************************** XML::BuiltinReader<double> **************************
 ********************************************************************************
 */
BuiltinReader<double>::BuiltinReader (double* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<double>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<double>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Float (tmpVal_.As<wstring> ());
}

void    BuiltinReader<double>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ********************** XML::BuiltinReader<Time::DateTime> **********************
 ********************************************************************************
 */
BuiltinReader<Time::DateTime>::BuiltinReader (Time::DateTime* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
    , tmpVal_ ()
{
    RequireNotNull (intoVal);
    *intoVal = Time::DateTime ();
}

void    BuiltinReader<Time::DateTime>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<Time::DateTime>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    // not 100% right to ignore exceptions, but tricky to do more right (cuz not necesarily all text given us at once)
    IgnoreExceptionsForCall ((*value_) = Time::DateTime::Parse (tmpVal_.As<wstring> (), Time::DateTime::ParseFormat::eXML));
}

void    BuiltinReader<Time::DateTime>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************************* XML::IgnoreNodeReader **************************
 ********************************************************************************
 */
IgnoreNodeReader::IgnoreNodeReader ()
    : fDepth_ (0)
{
}

void    IgnoreNodeReader::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    Require (fDepth_ >= 0);
    fDepth_++;
}

void    IgnoreNodeReader::HandleTextInside (SAXObjectReader& r, const String& text)
{
    // Ignore text
}

void    IgnoreNodeReader::HandleEndTag (SAXObjectReader& r)
{
    Require (fDepth_ >= 0);
    --fDepth_;
    if (fDepth_ < 0) {
        r.Pop ();
    }
}

/*
 ********************************************************************************
 ************************** XML::ThrowUnRecognizedStartElt **********************
 ********************************************************************************
 */
void    XML::ThrowUnRecognizedStartElt (const String& uri, const String& localName)
{
    Execution::DoThrow (BadFormatException (Characters::Format (L"Unrecognized start tag '%s'", localName.c_str ())));
}

<commit_msg>correct a few more warnings for gcc<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    "../../Characters/Format.h"
#include    "../BadFormatException.h"

#include    "SAXObjectReader.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::DataExchangeFormat;
using   namespace   Stroika::Foundation::DataExchangeFormat::XML;

/*
 ********************************************************************************
 ****************************** XML::SAXObjectReader ****************************
 ********************************************************************************
 */
#if     qDefaultTracingOn
wstring SAXObjectReader::TraceLeader_ () const
{
    wstring l;
    l.reserve (fStack_.size ());
    for (size_t i = 0; i < fStack_.size (); ++i) {
        l += L" ";
    }
    return l;
}
#endif
class   SAXObjectReader::MyCallback_ : public SAXCallbackInterface {
public:
    MyCallback_ (SAXObjectReader& r)
        : fSAXObjectReader_ (r) {
    }
private:
    SAXObjectReader&    fSAXObjectReader_;
public:
    virtual void    StartDocument () override {
    }
    virtual void    EndDocument () override {
    }
    virtual void    StartElement (const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling HandleChildStart ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), localName.c_str ());
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleChildStart (fSAXObjectReader_, uri, localName, qname, attrs);
    }
    virtual void    EndElement (const String& uri, const String& localName, const String& qname) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling EndElement ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), localName.c_str ());
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleEndTag (fSAXObjectReader_);
    }
    virtual void    CharactersInsideElement (const String& text) override {
        AssertNotNull (fSAXObjectReader_.GetTop ());
#if     qDefaultTracingOn
        if (fSAXObjectReader_.fTraceThisReader) {
            DbgTrace (L"%sCalling CharactersInsideElement ('%s',...)...", fSAXObjectReader_.TraceLeader_ ().c_str (), text.c_str () );
        }
#endif
        fSAXObjectReader_.GetTop ()->HandleTextInside (fSAXObjectReader_, text);
    }
};

namespace   {
    struct DocumentReader_ : public SAXObjectReader::ObjectBase {
        shared_ptr<ObjectBase>          fDocEltBuilder;
        bool                            fAnyDocElt;
        String                          fDocEltURI;
        String                          fDocEltName;
        DocumentReader_ (const shared_ptr<ObjectBase>& docEltBuilder)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (true)
            , fDocEltURI ()
            , fDocEltName () {
        }
        DocumentReader_ (const shared_ptr<ObjectBase>& docEltBuilder, const String& checkURI, const String& checkDocEltName)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (false)
            , fDocEltURI (checkURI)
            , fDocEltName (checkDocEltName) {
        }
        virtual void    HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs) override {
            if (not fAnyDocElt) {
                if (localName != fDocEltName or uri != fDocEltURI) {
                    ThrowUnRecognizedStartElt (uri, localName);
                }
            }
            r.Push (fDocEltBuilder);
        }
        virtual void    HandleTextInside (SAXObjectReader& r, const String& text)  override {
            // OK so long as text is whitespace - or comment. Probably should check/assert, but KISS..., and count on validation to
            // assure input is valid
            Assert (text.IsWhitespace ());
        }
        virtual void    HandleEndTag (SAXObjectReader& r) override {
            r.Pop ();
        }
    };
}
void    SAXObjectReader::Run (const shared_ptr<ObjectBase>& docEltBuilder, const Streams::BinaryInputStream& in)
{
    RequireNotNull (docEltBuilder);
    Require (fStack_.size () == 0);

    Push (shared_ptr<ObjectBase> (DEBUG_NEW DocumentReader_ (docEltBuilder)));

    MyCallback_ cb (*this);
    SAXParse (in, cb);

    Pop (); // the docuemnt reader we just added

    Ensure (fStack_.size () == 0);
}

void    SAXObjectReader::Run (const shared_ptr<ObjectBase>& docEltBuilder, const String& docEltUri, const String& docEltLocalName, const Streams::BinaryInputStream& in)
{
    RequireNotNull (docEltBuilder);
    Require (fStack_.size () == 0);

    Push (shared_ptr<ObjectBase> (DEBUG_NEW DocumentReader_ (docEltBuilder, docEltUri, docEltLocalName)));

    MyCallback_ cb (*this);
    SAXParse (in, cb);

    Pop (); // the docuemnt reader we just added

    Ensure (fStack_.size () == 0);
}

/*
 ********************************************************************************
 ********************* XML::SAXObjectReader::ObjectBase *************************
 ********************************************************************************
 */
SAXObjectReader::ObjectBase::~ObjectBase ()
{
}

/*
 ********************************************************************************
 ************************* XML::BuiltinReader<String> ***************************
 ********************************************************************************
 */
BuiltinReader<String>::BuiltinReader (String* intoVal, const Mapping<String, VariantValue>& attrs)
    : value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = String ();
}

void    BuiltinReader<String>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<String>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    (*value_) += text;
}

void    BuiltinReader<String>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 **************************** XML::BuiltinReader<int> ***************************
 ********************************************************************************
 */
BuiltinReader<int>::BuiltinReader (int* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<int>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<int>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<int>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************* XML::BuiltinReader<unsigned int> ***************************
 ********************************************************************************
 */
BuiltinReader<unsigned int>::BuiltinReader (unsigned int* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<unsigned int>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<unsigned int>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<unsigned int>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************************** XML::BuiltinReader<bool> ***************************
 ********************************************************************************
 */
BuiltinReader<bool>::BuiltinReader (bool* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<bool>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<bool>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    String  tmp =   tmpVal_.Trim ().ToLowerCase ();
    (*value_) = (tmp == L"true");
}

void    BuiltinReader<bool>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************************** XML::BuiltinReader<float> ***************************
 ********************************************************************************
 */
BuiltinReader<float>::BuiltinReader (float* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<float>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<float>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = static_cast<float> (Characters::String2Float (tmpVal_.As<wstring> ()));
}

void    BuiltinReader<float>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************************** XML::BuiltinReader<double> **************************
 ********************************************************************************
 */
BuiltinReader<double>::BuiltinReader (double* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<double>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<double>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Float (tmpVal_.As<wstring> ());
}

void    BuiltinReader<double>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ********************** XML::BuiltinReader<Time::DateTime> **********************
 ********************************************************************************
 */
BuiltinReader<Time::DateTime>::BuiltinReader (Time::DateTime* intoVal, const Mapping<String, VariantValue>& attrs)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = Time::DateTime ();
}

void    BuiltinReader<Time::DateTime>::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    ThrowUnRecognizedStartElt (uri, localName);
}

void    BuiltinReader<Time::DateTime>::HandleTextInside (SAXObjectReader& r, const String& text)
{
    tmpVal_ += text;
    // not 100% right to ignore exceptions, but tricky to do more right (cuz not necesarily all text given us at once)
    IgnoreExceptionsForCall ((*value_) = Time::DateTime::Parse (tmpVal_.As<wstring> (), Time::DateTime::ParseFormat::eXML));
}

void    BuiltinReader<Time::DateTime>::HandleEndTag (SAXObjectReader& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************************* XML::IgnoreNodeReader **************************
 ********************************************************************************
 */
IgnoreNodeReader::IgnoreNodeReader ()
    : fDepth_ (0)
{
}

void    IgnoreNodeReader::HandleChildStart (SAXObjectReader& r, const String& uri, const String& localName, const String& qname, const Mapping<String, VariantValue>& attrs)
{
    Require (fDepth_ >= 0);
    fDepth_++;
}

void    IgnoreNodeReader::HandleTextInside (SAXObjectReader& r, const String& text)
{
    // Ignore text
}

void    IgnoreNodeReader::HandleEndTag (SAXObjectReader& r)
{
    Require (fDepth_ >= 0);
    --fDepth_;
    if (fDepth_ < 0) {
        r.Pop ();
    }
}

/*
 ********************************************************************************
 ************************** XML::ThrowUnRecognizedStartElt **********************
 ********************************************************************************
 */
void    XML::ThrowUnRecognizedStartElt (const String& uri, const String& localName)
{
    Execution::DoThrow (BadFormatException (Characters::Format (L"Unrecognized start tag '%s'", localName.c_str ())));
}

<|endoftext|>


<commit_before>/*****************************************************************************************
*                                                                                *
* OpenSpace                                                                             *
*                                                                                *
* Copyright (c) 2014-2019                                                               *
*                                                                                *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify,    *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
* permit persons to whom the Software is furnished to do so, subject to the following   *
* conditions:                                                                           *
*                                                                                *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software.                                              *
*                                                                                *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
****************************************************************************************/

#include <modules/autonavigation/pathcurves.h>

#include <modules/autonavigation/helperfunctions.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>

namespace {
constexpr const char* _loggerCat = "PathCurve";
} // namespace

namespace openspace::autonavigation {

PathCurve::~PathCurve() {}

const double PathCurve::length() const {
    return _length;
}

// Approximate the curve length using Simpson's rule
double PathCurve::arcLength(double limit) {
    const int n = 30; // resolution, must be even for Simpson's rule
    const double h = limit / (double)n;

    // Points to be multiplied by 1
    double endPoints = glm::length(valueAt(0.0 + h) - valueAt(0.0)) + glm::length(valueAt(1.0) - valueAt(1.0 - h));

    // Points to be multiplied by 4
    double times4 = 0.0;
    for (int i = 1; i < n; i += 2) {
        float t = h * i;
        times4 += glm::length(valueAt(t + h) - valueAt(t));
    }

    // Points to be multiplied by 2
    double times2 = 0.0;
    for (int i = 2; i < n; i += 2) {
        float t = h * i;
        times2 += glm::length(valueAt(t + h) - valueAt(t));
    }

    return (h / 3.0) * (endPoints + 4.0 * times4 + 2.0 *times2);
}

// TODO: remove when not needed
// Created for debugging
std::vector<glm::dvec3> PathCurve::getPoints() {
    return _points;
}

Bezier3Curve::Bezier3Curve(CameraState& start, CameraState& end) {
    glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
    glm::dvec3 endNodePos = sceneGraphNode(end.referenceNode)->worldPosition();
    double startNodeRadius = sceneGraphNode(start.referenceNode)->boundingSphere();
    double endNodeRadius = sceneGraphNode(end.referenceNode)->boundingSphere();

    glm::dvec3 startNodeToStartPos = start.position - startNodePos;
    glm::dvec3 endNodeToEndPos = end.position - endNodePos;

    double startTangentLength = 2.0 * startNodeRadius;
    double endTangentLength = 2.0 * endNodeRadius;
    glm::dvec3 startTangentDirection = normalize(startNodeToStartPos);
    glm::dvec3 endTangentDirection = normalize(endNodeToEndPos);

    // Start by going outwards
    _points.push_back(start.position);
    _points.push_back(start.position + startTangentLength * startTangentDirection);

    if (start.referenceNode != end.referenceNode) {

        glm::dvec3 startNodeToEndNode = endNodePos - startNodePos;
        glm::dvec3 startToEndDirection = normalize(end.position - start.position);

        // Assuming we move straigh out to point to a distance proportional to radius, angle is enough to check collision risk
        double cosStartAngle = glm::dot(startTangentDirection, startToEndDirection);
        double cosEndAngle = glm::dot(endTangentDirection, startToEndDirection);
        double cosStartDir = glm::dot(startTangentDirection, endTangentDirection);

        //TODO: investigate suitable values, could be risky close to surface..
        bool TARGET_BEHIND_STARTNODE = cosStartAngle < -0.8;
        bool TARGET_BEHIND_ENDNODE = cosEndAngle > 0.8;
        bool TARGET_IN_OPPOSITE_DIRECTION = cosStartAngle > 0.7;

        // Avoid collision with startnode by adding control points on the side of it
        if (TARGET_BEHIND_STARTNODE) {
            glm::dvec3 parallell = glm::proj(startNodeToStartPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(startNodeToStartPos - parallell);
            double dist = 5.0 * startNodeRadius;
            glm::dvec3 extraKnot = startNodePos + dist * orthogonal;

            _points.push_back(extraKnot + parallell);
            _points.push_back(extraKnot);
            _points.push_back(extraKnot - parallell);
        }

        // Zoom out, to get a better understanding in a 180 degree turn situation
        if (TARGET_IN_OPPOSITE_DIRECTION) {
            glm::dvec3 parallell = glm::proj(startNodeToStartPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(startNodeToStartPos - parallell);
            double dist = 0.5 * glm::length(startNodeToEndNode);
            // Distant middle point
            glm::dvec3 extraKnot = startNodePos + dist * normalize(parallell) + 3.0 * dist * orthogonal;

            _points.push_back(extraKnot - 0.3 * dist *  normalize(parallell));
            _points.push_back(extraKnot);
            _points.push_back(extraKnot + 0.3 * dist *  normalize(parallell));
        }

        // Avoid collision with endnode by adding control points on the side of it
        if (TARGET_BEHIND_ENDNODE) {
            glm::dvec3 parallell = glm::proj(endNodeToEndPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(endNodeToEndPos - parallell);
            double dist = 5.0 * endNodeRadius;
            glm::dvec3 extraKnot = endNodePos + dist * orthogonal;

            _points.push_back(extraKnot - parallell);
            _points.push_back(extraKnot);
            _points.push_back(extraKnot + parallell);
        }
    }

    _points.push_back(end.position + endTangentLength * endTangentDirection);
    _points.push_back(end.position);

    _nrSegments = (unsigned int)std::floor((_points.size() - 1) / 3.0);

    // default values for the curve parameter - equally spaced
    for (double t = 0.0; t <= 1.0; t += 1.0 / _nrSegments) {
        _parameterIntervals.push_back(t);
    }

    _length = arcLength(1.0);

    initParameterIntervals();
}

// Interpolate a list of control points and knot times
glm::dvec3 Bezier3Curve::valueAt(double u) {
    size_t nrPoints = _points.size();
    size_t nrTimes = _parameterIntervals.size();

    ghoul_assert(nrPoints > 4, "Minimum of four control points needed for interpolation!");
    ghoul_assert((nrPoints - 1) % 3 == 0, "A vector containing 3n + 1 control points must be provided!");
    ghoul_assert(_nrSegments == (nrTimes - 1), "Number of interval times must match number of intervals");

    if (abs(u) < 0.000001)
        return _points.front();

    if (abs(1.0 - u) < 0.000001)
        return _points.back();

    // compute current segment, by first finding iterator to the first value that is larger than s
    std::vector<double>::iterator segmentEndIt =
        std::lower_bound(_parameterIntervals.begin(), _parameterIntervals.end(), u);
    unsigned int segmentIdx = (segmentEndIt - 1) - _parameterIntervals.begin();

    double segmentStart = _parameterIntervals[segmentIdx];
    double segmentDuration = (_parameterIntervals[segmentIdx + 1] - _parameterIntervals[segmentIdx]);
    double sScaled = (u - segmentStart) / segmentDuration;

    unsigned int idx = segmentIdx * 3;

    // Interpolate using De Casteljau's algorithm
    return interpolation::cubicBezier(sScaled, _points[idx], _points[idx + 1],
        _points[idx + 2], _points[idx + 3]);
}

// compute curve parameter intervals based on relative arc length
void Bezier3Curve::initParameterIntervals() {
    std::vector<double> newIntervals;
    for (double t = 0.0; t <= 1.0; t += 1.0 / _nrSegments) {
        newIntervals.push_back(arcLength(t) / _length);
    }
    _parameterIntervals.swap(newIntervals);
}

LinearCurve::LinearCurve(CameraState& start, CameraState& end) {
    _points.push_back(start.position);
    _points.push_back(end.position);
}

glm::dvec3 LinearCurve::valueAt(double u) {
    return interpolation::linear(u, _points[0], _points[1]);
}

// TODO: Iprove handling of pauses
PauseCurve::PauseCurve(CameraState& state) {
    _points.push_back(state.position);
}

glm::dvec3 PauseCurve::valueAt(double u) {
    return _points[0];
}

} // namespace openspace::autonavigation
<commit_msg>Compute length for other curve types<commit_after>/*****************************************************************************************
*                                                                                *
* OpenSpace                                                                             *
*                                                                                *
* Copyright (c) 2014-2019                                                               *
*                                                                                *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify,    *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
* permit persons to whom the Software is furnished to do so, subject to the following   *
* conditions:                                                                           *
*                                                                                *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software.                                              *
*                                                                                *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
****************************************************************************************/

#include <modules/autonavigation/pathcurves.h>

#include <modules/autonavigation/helperfunctions.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/projection.hpp>

namespace {
constexpr const char* _loggerCat = "PathCurve";
} // namespace

namespace openspace::autonavigation {

PathCurve::~PathCurve() {}

const double PathCurve::length() const {
    return _length;
}

// Approximate the curve length using Simpson's rule
double PathCurve::arcLength(double limit) {
    const int n = 30; // resolution, must be even for Simpson's rule
    const double h = limit / (double)n;

    // Points to be multiplied by 1
    double endPoints = glm::length(valueAt(0.0 + h) - valueAt(0.0)) + glm::length(valueAt(1.0) - valueAt(1.0 - h));

    // Points to be multiplied by 4
    double times4 = 0.0;
    for (int i = 1; i < n; i += 2) {
        float t = h * i;
        times4 += glm::length(valueAt(t + h) - valueAt(t));
    }

    // Points to be multiplied by 2
    double times2 = 0.0;
    for (int i = 2; i < n; i += 2) {
        float t = h * i;
        times2 += glm::length(valueAt(t + h) - valueAt(t));
    }

    return (h / 3.0) * (endPoints + 4.0 * times4 + 2.0 *times2);
}

// TODO: remove when not needed
// Created for debugging
std::vector<glm::dvec3> PathCurve::getPoints() {
    return _points;
}

Bezier3Curve::Bezier3Curve(CameraState& start, CameraState& end) {
    glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
    glm::dvec3 endNodePos = sceneGraphNode(end.referenceNode)->worldPosition();
    double startNodeRadius = sceneGraphNode(start.referenceNode)->boundingSphere();
    double endNodeRadius = sceneGraphNode(end.referenceNode)->boundingSphere();

    glm::dvec3 startNodeToStartPos = start.position - startNodePos;
    glm::dvec3 endNodeToEndPos = end.position - endNodePos;

    double startTangentLength = 2.0 * startNodeRadius;
    double endTangentLength = 2.0 * endNodeRadius;
    glm::dvec3 startTangentDirection = normalize(startNodeToStartPos);
    glm::dvec3 endTangentDirection = normalize(endNodeToEndPos);

    // Start by going outwards
    _points.push_back(start.position);
    _points.push_back(start.position + startTangentLength * startTangentDirection);

    if (start.referenceNode != end.referenceNode) {

        glm::dvec3 startNodeToEndNode = endNodePos - startNodePos;
        glm::dvec3 startToEndDirection = normalize(end.position - start.position);

        // Assuming we move straigh out to point to a distance proportional to radius, angle is enough to check collision risk
        double cosStartAngle = glm::dot(startTangentDirection, startToEndDirection);
        double cosEndAngle = glm::dot(endTangentDirection, startToEndDirection);
        double cosStartDir = glm::dot(startTangentDirection, endTangentDirection);

        //TODO: investigate suitable values, could be risky close to surface..
        bool TARGET_BEHIND_STARTNODE = cosStartAngle < -0.8;
        bool TARGET_BEHIND_ENDNODE = cosEndAngle > 0.8;
        bool TARGET_IN_OPPOSITE_DIRECTION = cosStartAngle > 0.7;

        // Avoid collision with startnode by adding control points on the side of it
        if (TARGET_BEHIND_STARTNODE) {
            glm::dvec3 parallell = glm::proj(startNodeToStartPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(startNodeToStartPos - parallell);
            double dist = 5.0 * startNodeRadius;
            glm::dvec3 extraKnot = startNodePos + dist * orthogonal;

            _points.push_back(extraKnot + parallell);
            _points.push_back(extraKnot);
            _points.push_back(extraKnot - parallell);
        }

        // Zoom out, to get a better understanding in a 180 degree turn situation
        if (TARGET_IN_OPPOSITE_DIRECTION) {
            glm::dvec3 parallell = glm::proj(startNodeToStartPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(startNodeToStartPos - parallell);
            double dist = 0.5 * glm::length(startNodeToEndNode);
            // Distant middle point
            glm::dvec3 extraKnot = startNodePos + dist * normalize(parallell) + 3.0 * dist * orthogonal;

            _points.push_back(extraKnot - 0.3 * dist *  normalize(parallell));
            _points.push_back(extraKnot);
            _points.push_back(extraKnot + 0.3 * dist *  normalize(parallell));
        }

        // Avoid collision with endnode by adding control points on the side of it
        if (TARGET_BEHIND_ENDNODE) {
            glm::dvec3 parallell = glm::proj(endNodeToEndPos, startNodeToEndNode);
            glm::dvec3 orthogonal = normalize(endNodeToEndPos - parallell);
            double dist = 5.0 * endNodeRadius;
            glm::dvec3 extraKnot = endNodePos + dist * orthogonal;

            _points.push_back(extraKnot - parallell);
            _points.push_back(extraKnot);
            _points.push_back(extraKnot + parallell);
        }
    }

    _points.push_back(end.position + endTangentLength * endTangentDirection);
    _points.push_back(end.position);

    _nrSegments = (unsigned int)std::floor((_points.size() - 1) / 3.0);

    // default values for the curve parameter - equally spaced
    for (double t = 0.0; t <= 1.0; t += 1.0 / _nrSegments) {
        _parameterIntervals.push_back(t);
    }

    _length = arcLength(1.0);

    initParameterIntervals();
}

// Interpolate a list of control points and knot times
glm::dvec3 Bezier3Curve::valueAt(double u) {
    ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");

    size_t nrPoints = _points.size();
    size_t nrTimes = _parameterIntervals.size();

    ghoul_assert(nrPoints > 4, "Minimum of four control points needed for interpolation!");
    ghoul_assert((nrPoints - 1) % 3 == 0, "A vector containing 3n + 1 control points must be provided!");
    ghoul_assert(_nrSegments == (nrTimes - 1), "Number of interval times must match number of intervals");

    if (abs(u) < 0.000001)
        return _points.front();

    if (abs(1.0 - u) < 0.000001)
        return _points.back();

    // compute current segment, by first finding iterator to the first value that is larger than s
    std::vector<double>::iterator segmentEndIt =
        std::lower_bound(_parameterIntervals.begin(), _parameterIntervals.end(), u);
    unsigned int segmentIdx = (segmentEndIt - 1) - _parameterIntervals.begin();

    double segmentStart = _parameterIntervals[segmentIdx];
    double segmentDuration = (_parameterIntervals[segmentIdx + 1] - _parameterIntervals[segmentIdx]);
    double sScaled = (u - segmentStart) / segmentDuration;

    unsigned int idx = segmentIdx * 3;

    // Interpolate using De Casteljau's algorithm
    return interpolation::cubicBezier(sScaled, _points[idx], _points[idx + 1],
        _points[idx + 2], _points[idx + 3]);
}

// compute curve parameter intervals based on relative arc length
void Bezier3Curve::initParameterIntervals() {
    std::vector<double> newIntervals;
    for (double t = 0.0; t <= 1.0; t += 1.0 / _nrSegments) {
        newIntervals.push_back(arcLength(t) / _length);
    }
    _parameterIntervals.swap(newIntervals);
}

LinearCurve::LinearCurve(CameraState& start, CameraState& end) {
    _points.push_back(start.position);
    _points.push_back(end.position);
    _length = glm::distance(end.position, start.position);
}

glm::dvec3 LinearCurve::valueAt(double u) {
    ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");
    return interpolation::linear(u, _points[0], _points[1]);
}

// TODO: Iprove handling of pauses
PauseCurve::PauseCurve(CameraState& state) {
    _points.push_back(state.position);
    _length = 1.0; // OBS! Length of a pause curve makes no sense, but it also doesn't matter
}

glm::dvec3 PauseCurve::valueAt(double u) {
    ghoul_assert(u >= 0 && u <= 1.0, "Interpolation variable out of range [0, 1]");
    return _points[0];
}

} // namespace openspace::autonavigation
<|endoftext|>


<commit_before>// This file is part of Parsito <http://github.com/ufal/parsito/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//#include <cstring>

#include "tree_format.h"
#include "utils/iostreams.h"
#include "utils/parse_int.h"
#include "utils/split.h"

namespace ufal {
namespace parsito {

// Input CoNLL-U format
class tree_input_format_conllu : public tree_input_format {
 public:
  virtual bool read_block(istream& in, string& block) const override;
  virtual void set_block(string_piece block) override;
  virtual bool next_tree(tree& t, string& error) override;

 private:
  string_piece block;
};

bool tree_input_format_conllu::read_block(istream& in, string& block) const {
  return getpara(in, block);
}

void tree_input_format_conllu::set_block(string_piece block) {
  this->block = block;
}

bool tree_input_format_conllu::next_tree(tree& t, string& error) {
  t.clear();
  error.clear();

  vector<string_piece> tokens;
  while (block.len) {
    // Read line
    string_piece line(block.str, 0);
    while (line.len < block.len && line.str[line.len] != '\n') line.len++;
    block.str += line.len + (line.len < block.len);
    block.len -= line.len + (line.len < block.len);

    // Empty lines denote end of tree, unless at the beginning
    if (!line.len) {
      if (t.empty()) continue;
      break;
    }

    // Ignore comments
    if (*line.str == '#') continue;

    // Parse another tree node
    split(line, '\t', tokens);
    if (tokens.size() != 10)
      return error.assign("The CoNLL-U line '").append(line.str, line.len).append("' does not contain 10 columns!") , false;

    // Skip multiword tokens
    if (memchr(tokens[0].str, '-', tokens[0].len)) continue;

    // Parse node ID and head
    int id;
    if (!parse_int(tokens[0], "CoNLL-U id", id, error))
      return false;
    if (id != int(t.nodes.size()))
      return error.assign("Wrong numeric id value '").append(tokens[0].str, tokens[0].len).append("'!"), false;

    int head;
    if (tokens[6].len == 1 && tokens[6].str[0] == '_') {
      head = -1;
    } else {
      if (!parse_int(tokens[6], "CoNLL-U head", head, error))
        return false;
      if (head < 0)
        return error.assign("Numeric head value '").append(tokens[0].str, tokens[0].len).append("' cannot be negative!"), false;
    }

    // Add new node
    auto& node = t.add_node(string(tokens[1].str, tokens[1].len));
    if (!(tokens[2].len == 1 && tokens[2].str[0] == '_')) node.lemma.assign(tokens[2].str, tokens[2].len);
    if (!(tokens[3].len == 1 && tokens[3].str[0] == '_')) node.ctag.assign(tokens[3].str, tokens[3].len);
    if (!(tokens[4].len == 1 && tokens[4].str[0] == '_')) node.tag.assign(tokens[4].str, tokens[4].len);
    if (!(tokens[5].len == 1 && tokens[5].str[0] == '_')) node.feats.assign(tokens[5].str, tokens[5].len);
    node.head = head;
    if (!(tokens[7].len == 1 && tokens[7].str[0] == '_')) node.deprel.assign(tokens[7].str, tokens[7].len);
    if (!(tokens[8].len == 1 && tokens[8].str[0] == '_')) node.deps.assign(tokens[8].str, tokens[8].len);
    if (!(tokens[9].len == 1 && tokens[9].str[0] == '_')) node.misc.assign(tokens[9].str, tokens[9].len);
  }

  // Set heads correctly
  for (auto&& node : t.nodes)
    if (node.id && node.head >= 0)
      t.set_head(node.id, node.head, node.deprel);

  return !t.empty();
}

// Output CoNLL-U format
class tree_output_format_conllu : public tree_output_format {
 public:
  virtual void append_tree(const tree& t, string& block) const override;

 private:
  static const string underscore;
  const string& underscore_on_empty(const string& str) const { return str.empty() ? underscore : str; }
};
const string tree_output_format_conllu::underscore = "_";

void tree_output_format_conllu::append_tree(const tree& t, string& block) const {
  // Skip the root node
  for (size_t i = 1; i < t.nodes.size(); i++) {
    block.append(to_string(i)).push_back('\t');
    block.append(t.nodes[i].form).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].lemma)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].ctag)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].tag)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].feats)).push_back('\t');
    block.append(t.nodes[i].head < 0 ? "_" : to_string(t.nodes[i].head)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].deprel)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].deps)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].misc)).push_back('\n');
  }
  block.push_back('\n');
}

// Input Static factory methods
tree_input_format* tree_input_format::new_conllu_input_format() {
  return new tree_input_format_conllu();
}

tree_input_format* tree_input_format::new_input_format(const string& name) {
  if (name == "conllu") return new_conllu_input_format();
  return nullptr;
}

// Output static factory methods
tree_output_format* tree_output_format::new_conllu_output_format() {
  return new tree_output_format_conllu();
}

tree_output_format* tree_output_format::new_output_format(const string& name) {
  if (name == "conllu") return new_conllu_output_format();
  return nullptr;
}

} // namespace parsito
} // namespace ufal
<commit_msg>Add explicit bool conversion.<commit_after>// This file is part of Parsito <http://github.com/ufal/parsito/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//#include <cstring>

#include "tree_format.h"
#include "utils/iostreams.h"
#include "utils/parse_int.h"
#include "utils/split.h"

namespace ufal {
namespace parsito {

// Input CoNLL-U format
class tree_input_format_conllu : public tree_input_format {
 public:
  virtual bool read_block(istream& in, string& block) const override;
  virtual void set_block(string_piece block) override;
  virtual bool next_tree(tree& t, string& error) override;

 private:
  string_piece block;
};

bool tree_input_format_conllu::read_block(istream& in, string& block) const {
  return bool(getpara(in, block));
}

void tree_input_format_conllu::set_block(string_piece block) {
  this->block = block;
}

bool tree_input_format_conllu::next_tree(tree& t, string& error) {
  t.clear();
  error.clear();

  vector<string_piece> tokens;
  while (block.len) {
    // Read line
    string_piece line(block.str, 0);
    while (line.len < block.len && line.str[line.len] != '\n') line.len++;
    block.str += line.len + (line.len < block.len);
    block.len -= line.len + (line.len < block.len);

    // Empty lines denote end of tree, unless at the beginning
    if (!line.len) {
      if (t.empty()) continue;
      break;
    }

    // Ignore comments
    if (*line.str == '#') continue;

    // Parse another tree node
    split(line, '\t', tokens);
    if (tokens.size() != 10)
      return error.assign("The CoNLL-U line '").append(line.str, line.len).append("' does not contain 10 columns!") , false;

    // Skip multiword tokens
    if (memchr(tokens[0].str, '-', tokens[0].len)) continue;

    // Parse node ID and head
    int id;
    if (!parse_int(tokens[0], "CoNLL-U id", id, error))
      return false;
    if (id != int(t.nodes.size()))
      return error.assign("Wrong numeric id value '").append(tokens[0].str, tokens[0].len).append("'!"), false;

    int head;
    if (tokens[6].len == 1 && tokens[6].str[0] == '_') {
      head = -1;
    } else {
      if (!parse_int(tokens[6], "CoNLL-U head", head, error))
        return false;
      if (head < 0)
        return error.assign("Numeric head value '").append(tokens[0].str, tokens[0].len).append("' cannot be negative!"), false;
    }

    // Add new node
    auto& node = t.add_node(string(tokens[1].str, tokens[1].len));
    if (!(tokens[2].len == 1 && tokens[2].str[0] == '_')) node.lemma.assign(tokens[2].str, tokens[2].len);
    if (!(tokens[3].len == 1 && tokens[3].str[0] == '_')) node.ctag.assign(tokens[3].str, tokens[3].len);
    if (!(tokens[4].len == 1 && tokens[4].str[0] == '_')) node.tag.assign(tokens[4].str, tokens[4].len);
    if (!(tokens[5].len == 1 && tokens[5].str[0] == '_')) node.feats.assign(tokens[5].str, tokens[5].len);
    node.head = head;
    if (!(tokens[7].len == 1 && tokens[7].str[0] == '_')) node.deprel.assign(tokens[7].str, tokens[7].len);
    if (!(tokens[8].len == 1 && tokens[8].str[0] == '_')) node.deps.assign(tokens[8].str, tokens[8].len);
    if (!(tokens[9].len == 1 && tokens[9].str[0] == '_')) node.misc.assign(tokens[9].str, tokens[9].len);
  }

  // Set heads correctly
  for (auto&& node : t.nodes)
    if (node.id && node.head >= 0)
      t.set_head(node.id, node.head, node.deprel);

  return !t.empty();
}

// Output CoNLL-U format
class tree_output_format_conllu : public tree_output_format {
 public:
  virtual void append_tree(const tree& t, string& block) const override;

 private:
  static const string underscore;
  const string& underscore_on_empty(const string& str) const { return str.empty() ? underscore : str; }
};
const string tree_output_format_conllu::underscore = "_";

void tree_output_format_conllu::append_tree(const tree& t, string& block) const {
  // Skip the root node
  for (size_t i = 1; i < t.nodes.size(); i++) {
    block.append(to_string(i)).push_back('\t');
    block.append(t.nodes[i].form).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].lemma)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].ctag)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].tag)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].feats)).push_back('\t');
    block.append(t.nodes[i].head < 0 ? "_" : to_string(t.nodes[i].head)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].deprel)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].deps)).push_back('\t');
    block.append(underscore_on_empty(t.nodes[i].misc)).push_back('\n');
  }
  block.push_back('\n');
}

// Input Static factory methods
tree_input_format* tree_input_format::new_conllu_input_format() {
  return new tree_input_format_conllu();
}

tree_input_format* tree_input_format::new_input_format(const string& name) {
  if (name == "conllu") return new_conllu_input_format();
  return nullptr;
}

// Output static factory methods
tree_output_format* tree_output_format::new_conllu_output_format() {
  return new tree_output_format_conllu();
}

tree_output_format* tree_output_format::new_output_format(const string& name) {
  if (name == "conllu") return new_conllu_output_format();
  return nullptr;
}

} // namespace parsito
} // namespace ufal
<|endoftext|>


<commit_before><commit_msg>3rd iteration.<commit_after><|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// CoinVault
//
// unspenttxoutview.cpp
//
// Copyright (c) 2014 Eric Lombrozo
//
// All Rights Reserved.

#include "unspenttxoutview.h"
#include "unspenttxoutmodel.h"

#include <QMenu>
#include <QContextMenuEvent>

UnspentTxOutView::UnspentTxOutView(QWidget* parent)
    : QTreeView(parent), model(nullptr), menu(nullptr)
{
}

void UnspentTxOutView::setModel(UnspentTxOutModel* model)
{
    QTreeView::setModel(model);
    this->model = model;
}

void UnspentTxOutView::update()
{
    for (int i = 0; i < model->columnCount(); i++) { resizeColumnToContents(i); }
}

void UnspentTxOutView::contextMenuEvent(QContextMenuEvent* event)
{
    if (menu) menu->exec(event->globalPos());
}

<commit_msg>Enable multiselection in UnspentTxOutView<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// CoinVault
//
// unspenttxoutview.cpp
//
// Copyright (c) 2014 Eric Lombrozo
//
// All Rights Reserved.

#include "unspenttxoutview.h"
#include "unspenttxoutmodel.h"

#include <QMenu>
#include <QContextMenuEvent>

UnspentTxOutView::UnspentTxOutView(QWidget* parent)
    : QTreeView(parent), model(nullptr), menu(nullptr)
{
    setSelectionMode(UnspentTxOutView::MultiSelection);
}

void UnspentTxOutView::setModel(UnspentTxOutModel* model)
{
    QTreeView::setModel(model);
    this->model = model;
}

void UnspentTxOutView::update()
{
    for (int i = 0; i < model->columnCount(); i++) { resizeColumnToContents(i); }
}

void UnspentTxOutView::contextMenuEvent(QContextMenuEvent* event)
{
    if (menu) menu->exec(event->globalPos());
}

<|endoftext|>


<commit_before>/*
  Copyright (C) 2008-2016 The Communi Project

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the copyright holder nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "irclagtimer.h"
#include "irclagtimer_p.h"
#include "ircconnection.h"
#include "ircmessage.h"
#include "irccommand.h"
#include <QDateTime>

IRC_BEGIN_NAMESPACE

static const int DEFAULT_INTERVAL = 60;

/*!
    \file irclagtimer.h
    \brief \#include <IrcLagTimer>
 */

/*!
    \class IrcLagTimer irclagtimer.h <IrcLagTimer>
    \ingroup util
    \brief Provides a timer for measuring lag.

    \note IrcLagTimer relies on functionality introduced in Qt 4.7.0, and is
          therefore not functional when built against earlier versions of Qt.
 */

/*!
    \fn void IrcLagTimer::lagChanged(qint64 lag)

    This signal is emitted when the \a lag has changed.
 */

#ifndef IRC_DOXYGEN
IrcLagTimerPrivate::IrcLagTimerPrivate() : q_ptr(0), connection(0), interval(DEFAULT_INTERVAL), pendingPings(0), lag(-1)
{
}

bool IrcLagTimerPrivate::messageFilter(IrcMessage* msg)
{
    if (msg->type() == IrcMessage::Pong)
        return processPongReply(static_cast<IrcPongMessage*>(msg));
    return false;
}

bool IrcLagTimerPrivate::processPongReply(IrcPongMessage* msg)
{
#if QT_VERSION >= 0x040700
    // TODO: configurable format?
    if (msg->argument().startsWith("communi/")) {
        bool ok = false;
        qint64 timestamp = msg->argument().mid(8).toLongLong(&ok);
        if (ok) {
            pendingPings--;
            updateLag(QDateTime::currentMSecsSinceEpoch() - timestamp);
            return true;
        }
    }
#endif // QT_VERSION
    return false;
}

void IrcLagTimerPrivate::_irc_connected()
{
#if QT_VERSION >= 0x040700
    pendingPings = 0;
    if (interval > 0)
        timer.start();
#endif // QT_VERSION
}

void IrcLagTimerPrivate::_irc_pingServer()
{
#if QT_VERSION >= 0x040700
    // TODO: configurable format?
    QString cmd = QString("PING communi/%1").arg(QDateTime::currentMSecsSinceEpoch());
    connection->sendData(cmd.toUtf8());
    qint64 pingLag = pendingPings * interval * 1000;
    if (pingLag > lag) {
        updateLag(pingLag);
    }
    pendingPings++;
#endif // QT_VERSION
}

void IrcLagTimerPrivate::_irc_disconnected()
{
#if QT_VERSION >= 0x040700
    updateLag(-1);
    pendingPings = 0;
    if (timer.isActive())
        timer.stop();
#endif // QT_VERSION
}

void IrcLagTimerPrivate::updateTimer()
{
#if QT_VERSION >= 0x040700
    if (connection && interval > 0) {
        timer.setInterval(interval * 1000);
        if (!timer.isActive() && connection->isConnected())
            timer.start();
    } else {
        if (timer.isActive())
            timer.stop();
        updateLag(-1);
    }
#endif // QT_VERSION
}

void IrcLagTimerPrivate::updateLag(qint64 value)
{
    Q_Q(IrcLagTimer);
    if (lag != value) {
        lag = qMax(-1ll, value);
        emit q->lagChanged(lag);
    }
}
#endif // IRC_DOXYGEN

/*!
    Constructs a new lag timer with \a parent.

    \note If \a parent is an instance of IrcConnection, it will be
    automatically assigned to \ref IrcLagTimer::connection "connection".
 */
IrcLagTimer::IrcLagTimer(QObject* parent) : QObject(parent), d_ptr(new IrcLagTimerPrivate)
{
    Q_D(IrcLagTimer);
    d->q_ptr = this;
    connect(&d->timer, SIGNAL(timeout()), this, SLOT(_irc_pingServer()));
    setConnection(qobject_cast<IrcConnection*>(parent));
}

/*!
    Destructs the lag timer.
 */
IrcLagTimer::~IrcLagTimer()
{
}

/*!
    This property holds the associated connection.

    \par Access functions:
    \li IrcConnection* connection() const
    \li void setConnection(IrcConnection* connection)
 */
IrcConnection* IrcLagTimer::connection() const
{
    Q_D(const IrcLagTimer);
    return d->connection;
}

void IrcLagTimer::setConnection(IrcConnection* connection)
{
    Q_D(IrcLagTimer);
    if (d->connection != connection) {
        if (d->connection) {
            d->connection->removeMessageFilter(d);
            disconnect(d->connection, SIGNAL(connected()), this, SLOT(_irc_connected()));
            disconnect(d->connection, SIGNAL(disconnected()), this, SLOT(_irc_disconnected()));
        }
        d->connection = connection;
        if (connection) {
            connection->installMessageFilter(d);
            connect(connection, SIGNAL(connected()), this, SLOT(_irc_connected()));
            connect(connection, SIGNAL(disconnected()), this, SLOT(_irc_disconnected()));
        }
        d->updateLag(-1);
        d->updateTimer();
    }
}

/*!
    This property holds the current lag in milliseconds.

    The value is \c -1 when
    \li the connection is not connected,
    \li the lag has not yet been measured,
    \li the lag timer is disabled (interval <= 0s), or
    \li the Qt version is too old (4.7.0 or later is required).

    \par Access function:
    \li qint64 lag() const

    \par Notifier signal:
    \li void lagChanged(qint64 lag)
 */
qint64 IrcLagTimer::lag() const
{
    Q_D(const IrcLagTimer);
    return d->lag;
}

/*!
    This property holds the lag measurement interval in seconds.

    The default value is \c 60 seconds. A value equal to or
    less than \c 0 seconds disables the lag measurement.

    \par Access functions:
    \li int interval() const
    \li void setInterval(int seconds)
 */
int IrcLagTimer::interval() const
{
    Q_D(const IrcLagTimer);
    return d->interval;
}

void IrcLagTimer::setInterval(int seconds)
{
    Q_D(IrcLagTimer);
    if (d->interval != seconds) {
        d->interval = seconds;
        d->updateTimer();
    }
}

#include "moc_irclagtimer.cpp"
#include "moc_irclagtimer_p.cpp"

IRC_END_NAMESPACE
<commit_msg>Fix IrcLagTimer to pass the auto tests again<commit_after>/*
  Copyright (C) 2008-2016 The Communi Project

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the copyright holder nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "irclagtimer.h"
#include "irclagtimer_p.h"
#include "ircconnection.h"
#include "ircmessage.h"
#include "irccommand.h"
#include <QDateTime>

IRC_BEGIN_NAMESPACE

static const int DEFAULT_INTERVAL = 60;

/*!
    \file irclagtimer.h
    \brief \#include <IrcLagTimer>
 */

/*!
    \class IrcLagTimer irclagtimer.h <IrcLagTimer>
    \ingroup util
    \brief Provides a timer for measuring lag.

    \note IrcLagTimer relies on functionality introduced in Qt 4.7.0, and is
          therefore not functional when built against earlier versions of Qt.
 */

/*!
    \fn void IrcLagTimer::lagChanged(qint64 lag)

    This signal is emitted when the \a lag has changed.
 */

#ifndef IRC_DOXYGEN
IrcLagTimerPrivate::IrcLagTimerPrivate() : q_ptr(0), connection(0), interval(DEFAULT_INTERVAL), pendingPings(0), lag(-1)
{
}

bool IrcLagTimerPrivate::messageFilter(IrcMessage* msg)
{
    if (msg->type() == IrcMessage::Pong)
        return processPongReply(static_cast<IrcPongMessage*>(msg));
    return false;
}

bool IrcLagTimerPrivate::processPongReply(IrcPongMessage* msg)
{
#if QT_VERSION >= 0x040700
    // TODO: configurable format?
    if (msg->argument().startsWith("communi/")) {
        bool ok = false;
        qint64 timestamp = msg->argument().mid(8).toLongLong(&ok);
        if (ok) {
            --pendingPings;
            updateLag(QDateTime::currentMSecsSinceEpoch() - timestamp);
            return true;
        }
    }
#endif // QT_VERSION
    return false;
}

void IrcLagTimerPrivate::_irc_connected()
{
#if QT_VERSION >= 0x040700
    pendingPings = 0;
    if (interval > 0)
        timer.start();
#endif // QT_VERSION
}

void IrcLagTimerPrivate::_irc_pingServer()
{
#if QT_VERSION >= 0x040700
    // TODO: configurable format?
    QString cmd = QString("PING communi/%1").arg(QDateTime::currentMSecsSinceEpoch());
    connection->sendData(cmd.toUtf8());
    qint64 pingLag = pendingPings * interval * 1000;
    if (lag > -1 && pingLag > lag)
        updateLag(pingLag);
    ++pendingPings;
#endif // QT_VERSION
}

void IrcLagTimerPrivate::_irc_disconnected()
{
#if QT_VERSION >= 0x040700
    updateLag(-1);
    pendingPings = 0;
    if (timer.isActive())
        timer.stop();
#endif // QT_VERSION
}

void IrcLagTimerPrivate::updateTimer()
{
#if QT_VERSION >= 0x040700
    if (connection && interval > 0) {
        timer.setInterval(interval * 1000);
        if (!timer.isActive() && connection->isConnected())
            timer.start();
    } else {
        if (timer.isActive())
            timer.stop();
        updateLag(-1);
    }
#endif // QT_VERSION
}

void IrcLagTimerPrivate::updateLag(qint64 value)
{
    Q_Q(IrcLagTimer);
    value = qMax(-1ll, value);
    if (lag != value) {
        lag = value;
        emit q->lagChanged(lag);
    }
}
#endif // IRC_DOXYGEN

/*!
    Constructs a new lag timer with \a parent.

    \note If \a parent is an instance of IrcConnection, it will be
    automatically assigned to \ref IrcLagTimer::connection "connection".
 */
IrcLagTimer::IrcLagTimer(QObject* parent) : QObject(parent), d_ptr(new IrcLagTimerPrivate)
{
    Q_D(IrcLagTimer);
    d->q_ptr = this;
    connect(&d->timer, SIGNAL(timeout()), this, SLOT(_irc_pingServer()));
    setConnection(qobject_cast<IrcConnection*>(parent));
}

/*!
    Destructs the lag timer.
 */
IrcLagTimer::~IrcLagTimer()
{
}

/*!
    This property holds the associated connection.

    \par Access functions:
    \li IrcConnection* connection() const
    \li void setConnection(IrcConnection* connection)
 */
IrcConnection* IrcLagTimer::connection() const
{
    Q_D(const IrcLagTimer);
    return d->connection;
}

void IrcLagTimer::setConnection(IrcConnection* connection)
{
    Q_D(IrcLagTimer);
    if (d->connection != connection) {
        if (d->connection) {
            d->connection->removeMessageFilter(d);
            disconnect(d->connection, SIGNAL(connected()), this, SLOT(_irc_connected()));
            disconnect(d->connection, SIGNAL(disconnected()), this, SLOT(_irc_disconnected()));
        }
        d->connection = connection;
        if (connection) {
            connection->installMessageFilter(d);
            connect(connection, SIGNAL(connected()), this, SLOT(_irc_connected()));
            connect(connection, SIGNAL(disconnected()), this, SLOT(_irc_disconnected()));
        }
        d->updateLag(-1);
        d->updateTimer();
    }
}

/*!
    This property holds the current lag in milliseconds.

    The value is \c -1 when
    \li the connection is not connected,
    \li the lag has not yet been measured,
    \li the lag timer is disabled (interval <= 0s), or
    \li the Qt version is too old (4.7.0 or later is required).

    \par Access function:
    \li qint64 lag() const

    \par Notifier signal:
    \li void lagChanged(qint64 lag)
 */
qint64 IrcLagTimer::lag() const
{
    Q_D(const IrcLagTimer);
    return d->lag;
}

/*!
    This property holds the lag measurement interval in seconds.

    The default value is \c 60 seconds. A value equal to or
    less than \c 0 seconds disables the lag measurement.

    \par Access functions:
    \li int interval() const
    \li void setInterval(int seconds)
 */
int IrcLagTimer::interval() const
{
    Q_D(const IrcLagTimer);
    return d->interval;
}

void IrcLagTimer::setInterval(int seconds)
{
    Q_D(IrcLagTimer);
    if (d->interval != seconds) {
        d->interval = seconds;
        d->updateTimer();
    }
}

#include "moc_irclagtimer.cpp"
#include "moc_irclagtimer_p.cpp"

IRC_END_NAMESPACE
<|endoftext|>