<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2018.  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) {
                Execution::Throw (Execution::Platform::Windows::Exception (ERROR_INVALID_HANDLE), "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) {
                Execution::Throw (Execution::Platform::Windows::Exception (ERROR_INVALID_HANDLE), "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)
        {
            Debug::TraceContextBumper trcCtx{Stroika_Foundation_Debug_OptionalizeTraceArgs (L"OptionsFileHelper::OpenWithCreateAlongPath", L"parentKey=%p, path='%s'", parentKey, path.c_str ())};
            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
/*
 ********************************************************************************
 *************************** MimeTypes::Private::INIT ***************************
 ********************************************************************************
 */

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"));
#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>fixed serious bug in InternetMediaTypeRegistry::GetPreferredAssociatedFileSuffix () - noticed by MSVC level 4 warnings<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2018.  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) {
                Execution::Throw (Execution::Platform::Windows::Exception (ERROR_INVALID_HANDLE), "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) {
                Execution::Throw (Execution::Platform::Windows::Exception (ERROR_INVALID_HANDLE), "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)
        {
            Debug::TraceContextBumper trcCtx{Stroika_Foundation_Debug_OptionalizeTraceArgs (L"OptionsFileHelper::OpenWithCreateAlongPath", L"parentKey=%p, path='%s'", parentKey, path.c_str ())};
            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 {};
}<|endoftext|>


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

#include    "../Characters/Format.h"
#include    "../Containers/Tally.h"
#include    "../Time/Date.h"
#include    "../Time/DateTime.h"

#include    "ObjectVariantMapper.h"

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

using   Time::Date;
using   Time::DateTime;

/*
 ********************************************************************************
 ******* DataExchangeFormat::ObjectVariantMapper::TypeMappingDetails ************
 ********************************************************************************
 */
ObjectVariantMapper::TypeMappingDetails::TypeMappingDetails (
    const type_index& forTypeInfo,
    const std::function<VariantValue(ObjectVariantMapper* mapper, const Byte* objOfType)>& toVariantMapper,
    const std::function<void(ObjectVariantMapper* mapper, const VariantValue& d, Byte* into)>& fromVariantMapper
)
    : fForType (forTypeInfo)
    , fToVariantMapper (toVariantMapper)
    , fFromVariantMapper (fromVariantMapper)
{
}

ObjectVariantMapper::TypeMappingDetails::TypeMappingDetails (const type_index& forTypeInfo, size_t n, const Sequence<StructureFieldInfo>& fields)
    : fForType (forTypeInfo)
    , fToVariantMapper ()
    , fFromVariantMapper ()
{
#if     qDebug
    for (auto i : fields) {
        Require (i.fOffset < n);
    }
    {
        // assure each field unique
        Containers::Tally<size_t> t;
        for (auto i : fields) {
            t.Add (i.fOffset);
        }
        for (auto i : t) {
            Require (i.fCount == 1);
        }
    }
#if 0
    // GOOD TODO but cannot since no longer a member of the ObjectMapper class...
    {
        // Assure for each field type is registered
        for (auto i : fields) {
            Require (Lookup_ (i.fTypeInfo).fFromVariantMapper);
            Require (Lookup_ (i.fTypeInfo).fToVariantMapper);
        }
    }
#endif
#endif

    fToVariantMapper = [fields] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
        Mapping<String, VariantValue> m;
        for (auto i : fields) {
            const Byte* fieldObj = fromObjOfTypeT + i.fOffset;
            m.Add (i.fSerializedFieldName, mapper->FromObject (i.fTypeInfo, fromObjOfTypeT + i.fOffset));
        }
        return VariantValue (m);
    };
    fFromVariantMapper = [fields] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
        Mapping<String, VariantValue> m  =   d.As<Mapping<String, VariantValue>> ();
        for (auto i : fields) {
            Memory::Optional<VariantValue> o = m.Lookup (i.fSerializedFieldName);
            if (not o.empty ()) {
                mapper->ToObject (i.fTypeInfo, *o, intoObjOfTypeT + i.fOffset);
            }
        }
    };
}

/*
 ********************************************************************************
 ****************** DataExchangeFormat::ObjectVariantMapper *********************
 ********************************************************************************
 */
namespace {
    template    <typename T, typename UseVariantType>
    ObjectVariantMapper::TypeMappingDetails mkSerializerInfo_ ()
    {
        auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
            return VariantValue (static_cast<UseVariantType> (*reinterpret_cast<const T*> (fromObjOfTypeT)));
        };
        auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
            *reinterpret_cast<T*> (intoObjOfTypeT) = static_cast<T> (d.As<UseVariantType> ());
        };
        return ObjectVariantMapper::TypeMappingDetails (typeid (T), toVariantMapper, fromVariantMapper);
    }
    Set<ObjectVariantMapper::TypeMappingDetails>    mkCommonSerializers_ ()
    {
        Set<ObjectVariantMapper::TypeMappingDetails>    result;
        result.Add (mkSerializerInfo_<bool, bool> ());
        result.Add (mkSerializerInfo_<signed char, signed char> ());
        result.Add (mkSerializerInfo_<short int, short int> ());
        result.Add (mkSerializerInfo_<int, int> ());
        result.Add (mkSerializerInfo_<long int, long int> ());
        result.Add (mkSerializerInfo_<long long int, long long int> ());
        result.Add (mkSerializerInfo_<unsigned char, unsigned char> ());
        result.Add (mkSerializerInfo_<unsigned short, unsigned short> ());
        result.Add (mkSerializerInfo_<unsigned int, unsigned int> ());
        result.Add (mkSerializerInfo_<unsigned long int, unsigned long int> ());
        result.Add (mkSerializerInfo_<unsigned long long int, unsigned long long int> ());
        result.Add (mkSerializerInfo_<float, float> ());
        result.Add (mkSerializerInfo_<double, double> ());
        result.Add (mkSerializerInfo_<long double, long double> ());
        result.Add (mkSerializerInfo_<Date, Date> ());
        result.Add (mkSerializerInfo_<DateTime, DateTime> ());
        result.Add (mkSerializerInfo_<String, String> ());

        {
            typedef Mapping<String, String>  ACTUAL_ELEMENT_TYPE;
            auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                Mapping<String, VariantValue> m;
                const ACTUAL_ELEMENT_TYPE*  actualMember    =   reinterpret_cast<const ACTUAL_ELEMENT_TYPE*> (fromObjOfTypeT);
                for (auto i : *actualMember) {
                    // really could do either way - but second more efficient
                    //m.Add (i.first, mapper->Serialize (typeid (String), reinterpret_cast<const Byte*> (&i.second)));
                    m.Add (i.first, i.second);
                }
                return VariantValue (m);
            };
            auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                Mapping<String, VariantValue> m  =   d.As<Mapping<String, VariantValue>> ();
                ACTUAL_ELEMENT_TYPE*    actualInto  =   reinterpret_cast<ACTUAL_ELEMENT_TYPE*> (intoObjOfTypeT);
                actualInto->clear ();
                for (auto i : m) {
                    // really could do either way - but second more efficient
                    //actualInto->Add (i.first, mapper->ToObject<String> (i.second));
                    actualInto->Add (i.first, i.second.As<String> ());
                }
            };
            result.Add (ObjectVariantMapper::TypeMappingDetails (typeid(ACTUAL_ELEMENT_TYPE), toVariantMapper, fromVariantMapper));
        }

        {
            typedef Mapping<String, VariantValue>    ACTUAL_ELEMENT_TYPE;
            auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                const ACTUAL_ELEMENT_TYPE*  actualMember    =   reinterpret_cast<const ACTUAL_ELEMENT_TYPE*> (fromObjOfTypeT);
                return VariantValue (*actualMember);
            };
            auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                ACTUAL_ELEMENT_TYPE*    actualInto  =   reinterpret_cast<ACTUAL_ELEMENT_TYPE*> (intoObjOfTypeT);
                * actualInto = d.As<Mapping<String, VariantValue>> ();
            };
            result.Add (ObjectVariantMapper::TypeMappingDetails (typeid(ACTUAL_ELEMENT_TYPE), toVariantMapper, fromVariantMapper));
        }

        // TODO - ARRAY??? Maybe using Sequence???
        {
        }
        return result;
    }

    // Construct the default map once, so that it never needs be re-created (though it could easily get cloned when modified)
    Set<ObjectVariantMapper::TypeMappingDetails>    GetDefaultTypeMappers_ ()
    {
        static  Set<ObjectVariantMapper::TypeMappingDetails>    sDefaults_ = mkCommonSerializers_ ();
        return sDefaults_;
    }
}

ObjectVariantMapper::ObjectVariantMapper ()
    : fSerializers_ (GetDefaultTypeMappers_ ())
{
}

void    ObjectVariantMapper::RegisterTypeMapper (const TypeMappingDetails& serializerInfo)
{
    fSerializers_.Add (serializerInfo);
}

void    ObjectVariantMapper::ResetToDefaultTypeRegistry ()
{
    fSerializers_ = GetDefaultTypeMappers_ ();
}

VariantValue    ObjectVariantMapper::FromObject (const type_index& forTypeInfo, const Byte* objOfType)
{
    Require (Lookup_ (forTypeInfo).fToVariantMapper);
    return Lookup_ (forTypeInfo).fToVariantMapper (this, objOfType);
}

void    ObjectVariantMapper::ToObject (const type_index& forTypeInfo, const VariantValue& d, Byte* into)
{
    Require (Lookup_ (forTypeInfo).fFromVariantMapper);
    Lookup_ (forTypeInfo).fFromVariantMapper (this, d, into);
}

ObjectVariantMapper::TypeMappingDetails  ObjectVariantMapper::Lookup_ (const type_index& forTypeInfo) const
{
    TypeMappingDetails  foo (forTypeInfo, nullptr, nullptr);
    auto i  = fSerializers_.Lookup (foo);
    Require (i.IsPresent ());   // if not present, this is a usage error - only use types which are registered
    return *i;
}
<commit_msg>minor tweaks to DataExchangeFormat/ObjectVariantMapper for ease of use (debugmessages)<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "../Characters/Format.h"
#include    "../Containers/Tally.h"
#include    "../Debug/Trace.h"
#include    "../Time/Date.h"
#include    "../Time/DateTime.h"

#include    "ObjectVariantMapper.h"

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

using   Time::Date;
using   Time::DateTime;

/*
 ********************************************************************************
 ******* DataExchangeFormat::ObjectVariantMapper::TypeMappingDetails ************
 ********************************************************************************
 */
ObjectVariantMapper::TypeMappingDetails::TypeMappingDetails (
    const type_index& forTypeInfo,
    const std::function<VariantValue(ObjectVariantMapper* mapper, const Byte* objOfType)>& toVariantMapper,
    const std::function<void(ObjectVariantMapper* mapper, const VariantValue& d, Byte* into)>& fromVariantMapper
)
    : fForType (forTypeInfo)
    , fToVariantMapper (toVariantMapper)
    , fFromVariantMapper (fromVariantMapper)
{
}

ObjectVariantMapper::TypeMappingDetails::TypeMappingDetails (const type_index& forTypeInfo, size_t n, const Sequence<StructureFieldInfo>& fields)
    : fForType (forTypeInfo)
    , fToVariantMapper ()
    , fFromVariantMapper ()
{
#if     qDebug
    for (auto i : fields) {
        Require (i.fOffset < n);
    }
    {
        // assure each field unique
        Containers::Tally<size_t> t;
        for (auto i : fields) {
            t.Add (i.fOffset);
        }
        for (auto i : t) {
            Require (i.fCount == 1);
        }
    }
#if 0
    // GOOD TODO but cannot since no longer a member of the ObjectMapper class...
    {
        // Assure for each field type is registered
        for (auto i : fields) {
            Require (Lookup_ (i.fTypeInfo).fFromVariantMapper);
            Require (Lookup_ (i.fTypeInfo).fToVariantMapper);
        }
    }
#endif
#endif

    fToVariantMapper = [fields] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
        Mapping<String, VariantValue> m;
        for (auto i : fields) {
            const Byte* fieldObj = fromObjOfTypeT + i.fOffset;
            m.Add (i.fSerializedFieldName, mapper->FromObject (i.fTypeInfo, fromObjOfTypeT + i.fOffset));
        }
        return VariantValue (m);
    };
    fFromVariantMapper = [fields] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
        Mapping<String, VariantValue> m  =   d.As<Mapping<String, VariantValue>> ();
        for (auto i : fields) {
            Memory::Optional<VariantValue> o = m.Lookup (i.fSerializedFieldName);
            if (not o.empty ()) {
                mapper->ToObject (i.fTypeInfo, *o, intoObjOfTypeT + i.fOffset);
            }
        }
    };
}

/*
 ********************************************************************************
 ****************** DataExchangeFormat::ObjectVariantMapper *********************
 ********************************************************************************
 */
namespace {
    template    <typename T, typename UseVariantType>
    ObjectVariantMapper::TypeMappingDetails mkSerializerInfo_ ()
    {
        auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
            return VariantValue (static_cast<UseVariantType> (*reinterpret_cast<const T*> (fromObjOfTypeT)));
        };
        auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
            *reinterpret_cast<T*> (intoObjOfTypeT) = static_cast<T> (d.As<UseVariantType> ());
        };
        return ObjectVariantMapper::TypeMappingDetails (typeid (T), toVariantMapper, fromVariantMapper);
    }
    Set<ObjectVariantMapper::TypeMappingDetails>    mkCommonSerializers_ ()
    {
        Set<ObjectVariantMapper::TypeMappingDetails>    result;
        result.Add (mkSerializerInfo_<bool, bool> ());
        result.Add (mkSerializerInfo_<signed char, signed char> ());
        result.Add (mkSerializerInfo_<short int, short int> ());
        result.Add (mkSerializerInfo_<int, int> ());
        result.Add (mkSerializerInfo_<long int, long int> ());
        result.Add (mkSerializerInfo_<long long int, long long int> ());
        result.Add (mkSerializerInfo_<unsigned char, unsigned char> ());
        result.Add (mkSerializerInfo_<unsigned short, unsigned short> ());
        result.Add (mkSerializerInfo_<unsigned int, unsigned int> ());
        result.Add (mkSerializerInfo_<unsigned long int, unsigned long int> ());
        result.Add (mkSerializerInfo_<unsigned long long int, unsigned long long int> ());
        result.Add (mkSerializerInfo_<float, float> ());
        result.Add (mkSerializerInfo_<double, double> ());
        result.Add (mkSerializerInfo_<long double, long double> ());
        result.Add (mkSerializerInfo_<Date, Date> ());
        result.Add (mkSerializerInfo_<DateTime, DateTime> ());
        result.Add (mkSerializerInfo_<String, String> ());

        {
            typedef Mapping<String, String>  ACTUAL_ELEMENT_TYPE;
            auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                Mapping<String, VariantValue> m;
                const ACTUAL_ELEMENT_TYPE*  actualMember    =   reinterpret_cast<const ACTUAL_ELEMENT_TYPE*> (fromObjOfTypeT);
                for (auto i : *actualMember) {
                    // really could do either way - but second more efficient
                    //m.Add (i.first, mapper->Serialize (typeid (String), reinterpret_cast<const Byte*> (&i.second)));
                    m.Add (i.first, i.second);
                }
                return VariantValue (m);
            };
            auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                Mapping<String, VariantValue> m  =   d.As<Mapping<String, VariantValue>> ();
                ACTUAL_ELEMENT_TYPE*    actualInto  =   reinterpret_cast<ACTUAL_ELEMENT_TYPE*> (intoObjOfTypeT);
                actualInto->clear ();
                for (auto i : m) {
                    // really could do either way - but second more efficient
                    //actualInto->Add (i.first, mapper->ToObject<String> (i.second));
                    actualInto->Add (i.first, i.second.As<String> ());
                }
            };
            result.Add (ObjectVariantMapper::TypeMappingDetails (typeid(ACTUAL_ELEMENT_TYPE), toVariantMapper, fromVariantMapper));
        }

        {
            typedef Mapping<String, VariantValue>    ACTUAL_ELEMENT_TYPE;
            auto toVariantMapper = [] (ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                const ACTUAL_ELEMENT_TYPE*  actualMember    =   reinterpret_cast<const ACTUAL_ELEMENT_TYPE*> (fromObjOfTypeT);
                return VariantValue (*actualMember);
            };
            auto fromVariantMapper = [] (ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                ACTUAL_ELEMENT_TYPE*    actualInto  =   reinterpret_cast<ACTUAL_ELEMENT_TYPE*> (intoObjOfTypeT);
                * actualInto = d.As<Mapping<String, VariantValue>> ();
            };
            result.Add (ObjectVariantMapper::TypeMappingDetails (typeid(ACTUAL_ELEMENT_TYPE), toVariantMapper, fromVariantMapper));
        }

        // TODO - ARRAY??? Maybe using Sequence???
        {
        }
        return result;
    }

    // Construct the default map once, so that it never needs be re-created (though it could easily get cloned when modified)
    Set<ObjectVariantMapper::TypeMappingDetails>    GetDefaultTypeMappers_ ()
    {
        static  Set<ObjectVariantMapper::TypeMappingDetails>    sDefaults_ = mkCommonSerializers_ ();
        return sDefaults_;
    }
}

ObjectVariantMapper::ObjectVariantMapper ()
    : fSerializers_ (GetDefaultTypeMappers_ ())
{
}

void    ObjectVariantMapper::RegisterTypeMapper (const TypeMappingDetails& serializerInfo)
{
    fSerializers_.Add (serializerInfo);
}

void    ObjectVariantMapper::ResetToDefaultTypeRegistry ()
{
    fSerializers_ = GetDefaultTypeMappers_ ();
}

VariantValue    ObjectVariantMapper::FromObject (const type_index& forTypeInfo, const Byte* objOfType)
{
    Require (Lookup_ (forTypeInfo).fToVariantMapper);
    return Lookup_ (forTypeInfo).fToVariantMapper (this, objOfType);
}

void    ObjectVariantMapper::ToObject (const type_index& forTypeInfo, const VariantValue& d, Byte* into)
{
    Require (Lookup_ (forTypeInfo).fFromVariantMapper);
    Lookup_ (forTypeInfo).fFromVariantMapper (this, d, into);
}

ObjectVariantMapper::TypeMappingDetails  ObjectVariantMapper::Lookup_ (const type_index& forTypeInfo) const
{
    Debug::TraceContextBumper   ctx (TSTR ("ObjectVariantMapper::Lookup_"));
    DbgTrace ("(forTypeInfo = %s)", forTypeInfo.name ());
    TypeMappingDetails  foo (forTypeInfo, nullptr, nullptr);
    auto i  = fSerializers_.Lookup (foo);
    Require (i.IsPresent ());   // if not present, this is a usage error - only use types which are registered
    return *i;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "otbImage.h"
#include "otbWrapperInputImageParameter.h"

// Test image case, expect the same pointer for two calls with the same type
int otbWrapperInputImageParameterTest1(int, char* argv[])
{
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  /*
  Originally reported on gitlab as bug #1899:
  https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/issues/1899
  */
  using ImageType       = otb::Image<float, 2>;
  using ImageTypeOutput = otb::Image<unsigned char, 2>;

  auto image = ImageType::New();
  param->SetImage(image.GetPointer());

  auto output1 = param->GetImage<ImageTypeOutput>();
  auto output2 = param->GetImage<ImageTypeOutput>();

  if (output1 != output2)
  {
    std::cerr << "InputImageParameter calls to ->GetImage<> are not consistent.\n";
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

// Test image case, expect an exception for two calls with different types
int otbWrapperInputImageParameterTest2(int, char* argv[])
{
  using ImageType  = otb::Image<float, 2>;
  using ImageTypeA = otb::Image<unsigned char, 2>;
  using ImageTypeB = otb::Image<double, 2>;

  auto image = ImageType::New();
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetImage(image.GetPointer());

  try
  {
    param->GetImage<ImageTypeA>();
    param->GetImage<ImageTypeB>();
    param->GetImage<ImageTypeA>();
  }
  catch (itk::ExceptionObject&)
  {
    std::cerr << "Expected exception when calling GetImage() with different types.\n";
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

// Filename case, expect the same pointer for two calls with the same type
int otbWrapperInputImageParameterTest3(int, char* argv[])
{
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetFromFileName(argv[1]);
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  using ImageTypeOutput = otb::Image<unsigned char, 2>;

  auto output1 = param->GetImage<ImageTypeOutput>();
  auto output2 = param->GetImage<ImageTypeOutput>();

  if (output1 != output2)
  {
    std::cerr << "InputImageParameter calls to ->GetImage<> are not consistent.\n";
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

// Filename case, expect an exception for two calls with different types
int otbWrapperInputImageParameterTest4(int, char* argv[])
{
  using ImageTypeA = otb::Image<unsigned char, 2>;
  using ImageTypeB = otb::Image<double, 2>;

  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetFromFileName(argv[1]);
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  try
  {
    param->GetImage<ImageTypeA>();
    param->GetImage<ImageTypeB>();
    param->GetImage<ImageTypeA>();
  }
  catch (itk::ExceptionObject&)
  {
    std::cerr << "Expected exception when calling GetImage() with different types.\n";
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

int otbWrapperInputImageParameterTest(int argc, char* argv[])
{
  return otbWrapperInputImageParameterTest1(argc, argv) && otbWrapperInputImageParameterTest2(argc, argv) && otbWrapperInputImageParameterTest3(argc, argv) &&
         otbWrapperInputImageParameterTest4(argc, argv);
}
<commit_msg>WRG: remove unused parameter name<commit_after>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "otbImage.h"
#include "otbWrapperInputImageParameter.h"

// Test image case, expect the same pointer for two calls with the same type
int otbWrapperInputImageParameterTest1(int, char* argv[])
{
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  /*
  Originally reported on gitlab as bug #1899:
  https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/issues/1899
  */
  using ImageType       = otb::Image<float, 2>;
  using ImageTypeOutput = otb::Image<unsigned char, 2>;

  auto image = ImageType::New();
  param->SetImage(image.GetPointer());

  auto output1 = param->GetImage<ImageTypeOutput>();
  auto output2 = param->GetImage<ImageTypeOutput>();

  if (output1 != output2)
  {
    std::cerr << "InputImageParameter calls to ->GetImage<> are not consistent.\n";
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

// Test image case, expect an exception for two calls with different types
int otbWrapperInputImageParameterTest2(int, char* [])
{
  using ImageType  = otb::Image<float, 2>;
  using ImageTypeA = otb::Image<unsigned char, 2>;
  using ImageTypeB = otb::Image<double, 2>;

  auto image = ImageType::New();
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetImage(image.GetPointer());

  try
  {
    param->GetImage<ImageTypeA>();
    param->GetImage<ImageTypeB>();
    param->GetImage<ImageTypeA>();
  }
  catch (itk::ExceptionObject&)
  {
    std::cerr << "Expected exception when calling GetImage() with different types.\n";
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

// Filename case, expect the same pointer for two calls with the same type
int otbWrapperInputImageParameterTest3(int, char* argv[])
{
  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetFromFileName(argv[1]);
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  using ImageTypeOutput = otb::Image<unsigned char, 2>;

  auto output1 = param->GetImage<ImageTypeOutput>();
  auto output2 = param->GetImage<ImageTypeOutput>();

  if (output1 != output2)
  {
    std::cerr << "InputImageParameter calls to ->GetImage<> are not consistent.\n";
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

// Filename case, expect an exception for two calls with different types
int otbWrapperInputImageParameterTest4(int, char* argv[])
{
  using ImageTypeA = otb::Image<unsigned char, 2>;
  using ImageTypeB = otb::Image<double, 2>;

  auto param = otb::Wrapper::InputImageParameter::New();
  param->SetFromFileName(argv[1]);
  param->SetKey(argv[2]);
  param->SetDescription(argv[3]);

  try
  {
    param->GetImage<ImageTypeA>();
    param->GetImage<ImageTypeB>();
    param->GetImage<ImageTypeA>();
  }
  catch (itk::ExceptionObject&)
  {
    std::cerr << "Expected exception when calling GetImage() with different types.\n";
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

int otbWrapperInputImageParameterTest(int argc, char* argv[])
{
  return otbWrapperInputImageParameterTest1(argc, argv) && otbWrapperInputImageParameterTest2(argc, argv) && otbWrapperInputImageParameterTest3(argc, argv) &&
         otbWrapperInputImageParameterTest4(argc, argv);
}
<|endoftext|>


<commit_before>
#include "GameLogger.h"

using namespace std;

GameLogger::GameLogger()
  :
  logfileManager(true),
  lastCompleteFrameNumber(0),
  oldState(PlayerInfo::initial),
  firstRecording(true),
  lastAudioDataTimestamp(0),
  lastRecordedPlainImageID(CameraInfo::Bottom)
{
  logfileManager.openFile("/tmp/game.log");

  imageOutFile.open("/tmp/images.log", ios::out | ios::binary);
  lastTimeImageRecorded = getFrameInfo();

  getDebugParameterList().add(&params);
}

GameLogger::~GameLogger()
{
  logfileManager.closeFile();
  imageOutFile.close();
  getDebugParameterList().remove(&params);
}

#define LOGSTUFF(name) \
  { std::stringstream& dataStream = logfileManager.log(getFrameInfo().getFrameNumber(), #name); \
  Serializer<name>::serialize(get##name(), dataStream); } ((void)0)

void GameLogger::execute()
{
  // HACK: wait a bit before starting recording
  if(!logfileManager.is_ready()) {
    return;
  }

  if( getBehaviorStateComplete().state.IsInitialized() &&
      getBehaviorStateSparse().state.IsInitialized())
  {
    bool something_recorded = false;

    // write out the complete behavior state when it was just created in this frame
    if(getBehaviorStateComplete().state.framenumber() >= lastCompleteFrameNumber)
    {
      LOGSTUFF(BehaviorStateComplete);
      LOGSTUFF(RobotInfo);

      lastCompleteFrameNumber = getFrameInfo().getFrameNumber();
      something_recorded = true;
    }

    // condition wheather the current frame should be logged:
    bool log_this_frame = (getBehaviorStateSparse().state.framenumber() == getFrameInfo().getFrameNumber());

    // NOTE: record only the first frame if the state changed to initial or finished
    if(!firstRecording && oldState == getPlayerInfo().robotState) {
      log_this_frame = log_this_frame && getPlayerInfo().robotState != PlayerInfo::initial;
      log_this_frame = log_this_frame && getPlayerInfo().robotState != PlayerInfo::finished;
      log_this_frame = log_this_frame && getMotionStatus().currentMotion != motion::init;
    }

    if(log_this_frame)
    {
      LOGSTUFF(BehaviorStateSparse);

      // proprioception
      LOGSTUFF(OdometryData);
      LOGSTUFF(CameraMatrix);
      LOGSTUFF(CameraMatrixTop);

      if(params.logBodyStatus) {
        LOGSTUFF(BodyStatus);
      }

      // perception
      LOGSTUFF(GoalPercept);
      LOGSTUFF(GoalPerceptTop);

      LOGSTUFF(MultiBallPercept);
      LOGSTUFF(BallModel);

      if(params.logUltraSound) {
        LOGSTUFF(UltraSoundReceiveData);
      }

      //LOGSTUFF(BallPercept);
      //LOGSTUFF(BallPerceptTop);

      LOGSTUFF(FieldPercept);
      LOGSTUFF(FieldPerceptTop);

      LOGSTUFF(ScanLineEdgelPercept);
      LOGSTUFF(ScanLineEdgelPerceptTop);
      LOGSTUFF(ShortLinePercept);
      LOGSTUFF(RansacLinePercept);
      LOGSTUFF(RansacCirclePercept2018);

      if(params.logBallCandidates) {
        LOGSTUFF(BallCandidates);
        LOGSTUFF(BallCandidatesTop);
      }

      LOGSTUFF(TeamMessage);

      // keep the audio device open for some time

      if(params.logAudioData)
      {
        // remember when the capture was on and keep recording for some time after it's off
        if(getAudioControl().capture) {
          timeOfLastCapture = getFrameInfo();
        } else if(getFrameInfo().getTimeSince(timeOfLastCapture.getTime()) < 3000) {
          getAudioControl().capture = true;
        }

        // new data avaliable and capture is still on
        if(lastAudioDataTimestamp < getAudioData().timestamp) {
          LOGSTUFF(AudioData);
          lastAudioDataTimestamp = getAudioData().timestamp;
        }
      }

      if (getWhistlePercept().whistleDetected) {
        LOGSTUFF(WhistlePercept);
      }

      // record images every 1s
      if(params.logPlainImages && getFrameInfo().getTimeSince(lastTimeImageRecorded) > params.logPlainImagesDelay && imageOutFile.is_open() && !imageOutFile.fail()) {
        unsigned int frameNumber = getFrameInfo().getFrameNumber();
        imageOutFile.write((const char*)(&frameNumber), sizeof(unsigned int));

        // switch camera each frame
        if(lastRecordedPlainImageID == CameraInfo::Top) {
          imageOutFile.write((const char*)getImage().data(), getImage().data_size());
          lastRecordedPlainImageID = CameraInfo::Bottom;
        } else {
          imageOutFile.write((const char*)getImageTop().data(), getImageTop().data_size());
          lastRecordedPlainImageID = CameraInfo::Top;
        }

        lastTimeImageRecorded = getFrameInfo();
      }

      something_recorded = true;
    }

    if(something_recorded) {
      LOGSTUFF(FrameInfo);
      firstRecording = false;
    }

    // remember the old state
    oldState = getPlayerInfo().robotState;
  }
}

<commit_msg>added comment about who stops the recording eventually<commit_after>
#include "GameLogger.h"

using namespace std;

GameLogger::GameLogger()
  :
  logfileManager(true),
  lastCompleteFrameNumber(0),
  oldState(PlayerInfo::initial),
  firstRecording(true),
  lastAudioDataTimestamp(0),
  lastRecordedPlainImageID(CameraInfo::Bottom)
{
  logfileManager.openFile("/tmp/game.log");

  imageOutFile.open("/tmp/images.log", ios::out | ios::binary);
  lastTimeImageRecorded = getFrameInfo();

  getDebugParameterList().add(&params);
}

GameLogger::~GameLogger()
{
  logfileManager.closeFile();
  imageOutFile.close();
  getDebugParameterList().remove(&params);
}

#define LOGSTUFF(name) \
  { std::stringstream& dataStream = logfileManager.log(getFrameInfo().getFrameNumber(), #name); \
  Serializer<name>::serialize(get##name(), dataStream); } ((void)0)

void GameLogger::execute()
{
  // HACK: wait a bit before starting recording
  if(!logfileManager.is_ready()) {
    return;
  }

  if( getBehaviorStateComplete().state.IsInitialized() &&
      getBehaviorStateSparse().state.IsInitialized())
  {
    bool something_recorded = false;

    // write out the complete behavior state when it was just created in this frame
    if(getBehaviorStateComplete().state.framenumber() >= lastCompleteFrameNumber)
    {
      LOGSTUFF(BehaviorStateComplete);
      LOGSTUFF(RobotInfo);

      lastCompleteFrameNumber = getFrameInfo().getFrameNumber();
      something_recorded = true;
    }

    // condition wheather the current frame should be logged:
    bool log_this_frame = (getBehaviorStateSparse().state.framenumber() == getFrameInfo().getFrameNumber());

    // NOTE: record only the first frame if the state changed to initial or finished
    if(!firstRecording && oldState == getPlayerInfo().robotState) {
      log_this_frame = log_this_frame && getPlayerInfo().robotState != PlayerInfo::initial;
      log_this_frame = log_this_frame && getPlayerInfo().robotState != PlayerInfo::finished;
      log_this_frame = log_this_frame && getMotionStatus().currentMotion != motion::init;
    }

    if(log_this_frame)
    {
      LOGSTUFF(BehaviorStateSparse);

      // proprioception
      LOGSTUFF(OdometryData);
      LOGSTUFF(CameraMatrix);
      LOGSTUFF(CameraMatrixTop);

      if(params.logBodyStatus) {
        LOGSTUFF(BodyStatus);
      }

      // perception
      LOGSTUFF(GoalPercept);
      LOGSTUFF(GoalPerceptTop);

      LOGSTUFF(MultiBallPercept);
      LOGSTUFF(BallModel);

      if(params.logUltraSound) {
        LOGSTUFF(UltraSoundReceiveData);
      }

      //LOGSTUFF(BallPercept);
      //LOGSTUFF(BallPerceptTop);

      LOGSTUFF(FieldPercept);
      LOGSTUFF(FieldPerceptTop);

      LOGSTUFF(ScanLineEdgelPercept);
      LOGSTUFF(ScanLineEdgelPerceptTop);
      LOGSTUFF(ShortLinePercept);
      LOGSTUFF(RansacLinePercept);
      LOGSTUFF(RansacCirclePercept2018);

      if(params.logBallCandidates) {
        LOGSTUFF(BallCandidates);
        LOGSTUFF(BallCandidatesTop);
      }

      LOGSTUFF(TeamMessage);

      // keep the audio device open for some time

      if(params.logAudioData)
      {
        // remember when the capture was on and keep recording for some time after the behavior says stop recording
        if(getAudioControl().capture) {
          timeOfLastCapture = getFrameInfo();
        } else if(getFrameInfo().getTimeSince(timeOfLastCapture.getTime()) < 3000) {
          getAudioControl().capture = true;
        }

        // new data avaliable and capture is still on
        if(lastAudioDataTimestamp < getAudioData().timestamp) {
          LOGSTUFF(AudioData);
          lastAudioDataTimestamp = getAudioData().timestamp;
        }
      }

      if (getWhistlePercept().whistleDetected) {
        LOGSTUFF(WhistlePercept);
      }

      // record images every 1s
      if(params.logPlainImages && getFrameInfo().getTimeSince(lastTimeImageRecorded) > params.logPlainImagesDelay && imageOutFile.is_open() && !imageOutFile.fail()) {
        unsigned int frameNumber = getFrameInfo().getFrameNumber();
        imageOutFile.write((const char*)(&frameNumber), sizeof(unsigned int));

        // switch camera each frame
        if(lastRecordedPlainImageID == CameraInfo::Top) {
          imageOutFile.write((const char*)getImage().data(), getImage().data_size());
          lastRecordedPlainImageID = CameraInfo::Bottom;
        } else {
          imageOutFile.write((const char*)getImageTop().data(), getImageTop().data_size());
          lastRecordedPlainImageID = CameraInfo::Top;
        }

        lastTimeImageRecorded = getFrameInfo();
      }

      something_recorded = true;
    }

    if(something_recorded) {
      LOGSTUFF(FrameInfo);
      firstRecording = false;
    }

    // remember the old state
    oldState = getPlayerInfo().robotState;
  }
}

<|endoftext|>


<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "BufferedResourceLoader.hxx"
#include "HttpResponseHandler.hxx"
#include "strmap.hxx"
#include "istream/BufferedIstream.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "util/Cancellable.hxx"
#include "stopwatch.hxx"

class BufferedResourceLoader::Request final
    : Cancellable, BufferedIstreamHandler
{
    struct pool &pool;
    ResourceLoader &next;
    const StopwatchPtr parent_stopwatch;
    const sticky_hash_t session_sticky;
    const char *const cache_tag;
    const char *const site_name;
    const http_method_t method;
    const ResourceAddress &address;
    const http_status_t status;
    StringMap headers;
    const char *const body_etag;
    HttpResponseHandler &handler;

    CancellablePointer cancel_ptr;

public:
    Request(struct pool &_pool, ResourceLoader &_next,
            const StopwatchPtr &_parent_stopwatch,
            sticky_hash_t _session_sticky,
            const char *_cache_tag,
            const char *_site_name,
            http_method_t _method, const ResourceAddress &_address,
            http_status_t _status, StringMap &&_headers,
            const char *_body_etag,
            HttpResponseHandler &_handler,
            CancellablePointer &_cancel_ptr) noexcept
        :pool(_pool), next(_next), parent_stopwatch(_parent_stopwatch),
         session_sticky(_session_sticky),
         cache_tag(_cache_tag),
         site_name(_site_name),
         method(_method), address(_address),
         status(_status),
         /* copy the headers, because they may come from a
            FilterCacheRequest pool which may be freed before
            BufferedIstream becomes ready */
         headers(pool, _headers),
         body_etag(_body_etag),
         handler(_handler)
    {
        _cancel_ptr = *this;
    }

    void Start(EventLoop &_event_loop, PipeStock *_pipe_stock,
               UnusedIstreamPtr &&body) noexcept {
        NewBufferedIstream(pool, _event_loop, _pipe_stock,
                           *this, std::move(body),
                           cancel_ptr);
    }

private:
    void Destroy() noexcept {
        this->~Request();
    }

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override {
        cancel_ptr.Cancel();
        Destroy();
    }

    /* virtual methods from class BufferedIstreamHandler */
    void OnBufferedIstreamReady(UnusedIstreamPtr i) noexcept override {
        next.SendRequest(pool, parent_stopwatch,
                         session_sticky, cache_tag, site_name,
                         method, address, status, std::move(headers),
                         std::move(i), body_etag,
                         handler, cancel_ptr);
    }

    void OnBufferedIstreamError(std::exception_ptr e) noexcept override {
        handler.InvokeError(std::move(e));
    }
};

void
BufferedResourceLoader::SendRequest(struct pool &pool,
                                    const StopwatchPtr &parent_stopwatch,
                                    sticky_hash_t session_sticky,
                                    const char *cache_tag,
                                    const char *site_name,
                                    http_method_t method,
                                    const ResourceAddress &address,
                                    http_status_t status, StringMap &&headers,
                                    UnusedIstreamPtr body, const char *body_etag,
                                    HttpResponseHandler &handler,
                                    CancellablePointer &cancel_ptr) noexcept
{
    if (body) {
        auto *request = NewFromPool<Request>(pool, pool, next, parent_stopwatch,
                                             session_sticky,
                                             cache_tag, site_name,
                                             method, address,
                                             status, std::move(headers),
                                             body_etag, handler, cancel_ptr);
        request->Start(event_loop, pipe_stock, std::move(body));
    } else {
        next.SendRequest(pool, parent_stopwatch,
                         session_sticky, cache_tag, site_name,
                         method, address, status, std::move(headers),
                         std::move(body), body_etag,
                         handler, cancel_ptr);
    }
}
<commit_msg>BufferedResourceLoader: use class PoolLeakDetector<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "BufferedResourceLoader.hxx"
#include "HttpResponseHandler.hxx"
#include "strmap.hxx"
#include "istream/BufferedIstream.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "pool/LeakDetector.hxx"
#include "util/Cancellable.hxx"
#include "stopwatch.hxx"

class BufferedResourceLoader::Request final
    : PoolLeakDetector, Cancellable, BufferedIstreamHandler
{
    struct pool &pool;
    ResourceLoader &next;
    const StopwatchPtr parent_stopwatch;
    const sticky_hash_t session_sticky;
    const char *const cache_tag;
    const char *const site_name;
    const http_method_t method;
    const ResourceAddress &address;
    const http_status_t status;
    StringMap headers;
    const char *const body_etag;
    HttpResponseHandler &handler;

    CancellablePointer cancel_ptr;

public:
    Request(struct pool &_pool, ResourceLoader &_next,
            const StopwatchPtr &_parent_stopwatch,
            sticky_hash_t _session_sticky,
            const char *_cache_tag,
            const char *_site_name,
            http_method_t _method, const ResourceAddress &_address,
            http_status_t _status, StringMap &&_headers,
            const char *_body_etag,
            HttpResponseHandler &_handler,
            CancellablePointer &_cancel_ptr) noexcept
        :PoolLeakDetector(_pool), pool(_pool),
         next(_next), parent_stopwatch(_parent_stopwatch),
         session_sticky(_session_sticky),
         cache_tag(_cache_tag),
         site_name(_site_name),
         method(_method), address(_address),
         status(_status),
         /* copy the headers, because they may come from a
            FilterCacheRequest pool which may be freed before
            BufferedIstream becomes ready */
         headers(pool, _headers),
         body_etag(_body_etag),
         handler(_handler)
    {
        _cancel_ptr = *this;
    }

    void Start(EventLoop &_event_loop, PipeStock *_pipe_stock,
               UnusedIstreamPtr &&body) noexcept {
        NewBufferedIstream(pool, _event_loop, _pipe_stock,
                           *this, std::move(body),
                           cancel_ptr);
    }

private:
    void Destroy() noexcept {
        this->~Request();
    }

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override {
        cancel_ptr.Cancel();
        Destroy();
    }

    /* virtual methods from class BufferedIstreamHandler */
    void OnBufferedIstreamReady(UnusedIstreamPtr i) noexcept override {
        next.SendRequest(pool, parent_stopwatch,
                         session_sticky, cache_tag, site_name,
                         method, address, status, std::move(headers),
                         std::move(i), body_etag,
                         handler, cancel_ptr);
    }

    void OnBufferedIstreamError(std::exception_ptr e) noexcept override {
        handler.InvokeError(std::move(e));
    }
};

void
BufferedResourceLoader::SendRequest(struct pool &pool,
                                    const StopwatchPtr &parent_stopwatch,
                                    sticky_hash_t session_sticky,
                                    const char *cache_tag,
                                    const char *site_name,
                                    http_method_t method,
                                    const ResourceAddress &address,
                                    http_status_t status, StringMap &&headers,
                                    UnusedIstreamPtr body, const char *body_etag,
                                    HttpResponseHandler &handler,
                                    CancellablePointer &cancel_ptr) noexcept
{
    if (body) {
        auto *request = NewFromPool<Request>(pool, pool, next, parent_stopwatch,
                                             session_sticky,
                                             cache_tag, site_name,
                                             method, address,
                                             status, std::move(headers),
                                             body_etag, handler, cancel_ptr);
        request->Start(event_loop, pipe_stock, std::move(body));
    } else {
        next.SendRequest(pool, parent_stopwatch,
                         session_sticky, cache_tag, site_name,
                         method, address, status, std::move(headers),
                         std::move(body), body_etag,
                         handler, cancel_ptr);
    }
}
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef torrent_info::file_iterator iter;

        for (iter i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(ti.files().at(i));

        return result;
    }

    std::string hash_for_piece(torrent_info const& ti, int i)
    {
        return ti.hash_for_piece(i).to_string();
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(path);
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

    bool get_tier(announce_entry const& ae) { return ae.tier; }
    void set_tier(announce_entry& ae, bool v) { ae.tier = v; }
    bool get_fail_limit(announce_entry const& ae) { return ae.fail_limit; }
    void set_fail_limit(announce_entry& ae, int l) { ae.fail_limit = l; }
    bool get_fails(announce_entry const& ae) { return ae.fails; }
    bool get_source(announce_entry const& ae) { return ae.source; }
    bool get_verified(announce_entry const& ae) { return ae.verified; }
    bool get_updating(announce_entry const& ae) { return ae.updating; }
    bool get_start_sent(announce_entry const& ae) { return ae.start_sent; }
    bool get_complete_sent(announce_entry const& ae) { return ae.complete_sent; }
    bool get_send_stats(announce_entry const& ae) { return ae.send_stats; }

    size_type get_size(file_entry const& fe) { return fe.size; }
    size_type get_offset(file_entry const& fe) { return fe.offset; }
    bool get_pad_file(file_entry const& fe) { return fe.pad_file; }
    bool get_executable_attribute(file_entry const& fe) { return fe.executable_attribute; }
    bool get_hidden_attribute(file_entry const& fe) { return fe.hidden_attribute; }
    bool get_symlink_attribute(file_entry const& fe) { return fe.symlink_attribute; }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    void (torrent_info::*rename_file0)(int, std::string const&) = &torrent_info::rename_file;
#if TORRENT_USE_WSTRING
    void (torrent_info::*rename_file1)(int, std::wstring const&) = &torrent_info::rename_file;
#endif

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>(arg("e")))
#endif
        .def(init<sha1_hash const&, int>((arg("info_hash"), arg("flags") = 0)))
        .def(init<char const*, int, int>((arg("buffer"), arg("length"), arg("flags") = 0)))
        .def(init<std::string, int>((arg("file"), arg("flags") = 0)))
        .def(init<torrent_info const&, int>((arg("ti"), arg("flags") = 0)))
#if TORRENT_USE_WSTRING
        .def(init<std::wstring, int>((arg("file"), arg("flags") = 0)))
#endif

        .def("add_tracker", &torrent_info::add_tracker, arg("url"))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at)
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))
        .def("rename_file", rename_file0)
#if TORRENT_USE_WSTRING
        .def("rename_file", rename_file1)
#endif

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
        .def_readwrite("path", &file_entry::path)
        .def_readwrite("symlink_path", &file_entry::symlink_path)
        .def_readwrite("filehash", &file_entry::filehash)
        .def_readwrite("mtime", &file_entry::mtime)
        .add_property("pad_file", &get_pad_file)
        .add_property("executable_attribute", &get_executable_attribute)
        .add_property("hidden_attribute", &get_hidden_attribute)
        .add_property("symlink_attribute", &get_symlink_attribute)
        .add_property("offset", &get_offset)
        .add_property("size", &get_size)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .add_property("tier", &get_tier, &set_tier)
        .add_property("fail_limit", &get_fail_limit, &set_fail_limit)
        .add_property("fails", &get_fails)
        .add_property("source", &get_source)
        .add_property("verified", &get_verified)
        .add_property("updating", &get_updating)
        .add_property("start_sent", &get_start_sent)
        .add_property("complete_sent", &get_complete_sent)
        .add_property("send_stats", &get_send_stats)

        .def("reset", &announce_entry::reset)
        .def("failed", &announce_entry::failed, arg("retry_interval") = 0)
        .def("can_announce", &announce_entry::can_announce)
        .def("is_working", &announce_entry::is_working)
        .def("trim", &announce_entry::trim)
        ;

    enum_<announce_entry::tracker_source>("tracker_source")
        .value("source_torrent", announce_entry::source_torrent)
        .value("source_client", announce_entry::source_client)
        .value("source_magnet_link", announce_entry::source_magnet_link)
        .value("source_tex", announce_entry::source_tex)
    ;
}

<commit_msg>fix python binding build<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/session_settings.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef torrent_info::file_iterator iter;

        for (iter i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(ti.files().at(i));

        return result;
    }

    std::string hash_for_piece(torrent_info const& ti, int i)
    {
        return ti.hash_for_piece(i).to_string();
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(path);
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

    bool get_tier(announce_entry const& ae) { return ae.tier; }
    void set_tier(announce_entry& ae, bool v) { ae.tier = v; }
    bool get_fail_limit(announce_entry const& ae) { return ae.fail_limit; }
    void set_fail_limit(announce_entry& ae, int l) { ae.fail_limit = l; }
    bool get_fails(announce_entry const& ae) { return ae.fails; }
    bool get_source(announce_entry const& ae) { return ae.source; }
    bool get_verified(announce_entry const& ae) { return ae.verified; }
    bool get_updating(announce_entry const& ae) { return ae.updating; }
    bool get_start_sent(announce_entry const& ae) { return ae.start_sent; }
    bool get_complete_sent(announce_entry const& ae) { return ae.complete_sent; }
    bool get_send_stats(announce_entry const& ae) { return ae.send_stats; }

    size_type get_size(file_entry const& fe) { return fe.size; }
    size_type get_offset(file_entry const& fe) { return fe.offset; }
    bool get_pad_file(file_entry const& fe) { return fe.pad_file; }
    bool get_executable_attribute(file_entry const& fe) { return fe.executable_attribute; }
    bool get_hidden_attribute(file_entry const& fe) { return fe.hidden_attribute; }
    bool get_symlink_attribute(file_entry const& fe) { return fe.symlink_attribute; }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    void (torrent_info::*rename_file0)(int, std::string const&) = &torrent_info::rename_file;
#if TORRENT_USE_WSTRING
    void (torrent_info::*rename_file1)(int, std::wstring const&) = &torrent_info::rename_file;
#endif

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>(arg("e")))
#endif
        .def(init<sha1_hash const&, int>((arg("info_hash"), arg("flags") = 0)))
        .def(init<char const*, int, int>((arg("buffer"), arg("length"), arg("flags") = 0)))
        .def(init<std::string, int>((arg("file"), arg("flags") = 0)))
        .def(init<torrent_info const&, int>((arg("ti"), arg("flags") = 0)))
#if TORRENT_USE_WSTRING
        .def(init<std::wstring, int>((arg("file"), arg("flags") = 0)))
#endif

        .def("add_tracker", &torrent_info::add_tracker, arg("url"))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at)
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))
        .def("rename_file", rename_file0)
#if TORRENT_USE_WSTRING
        .def("rename_file", rename_file1)
#endif

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
        .def_readwrite("path", &file_entry::path)
        .def_readwrite("symlink_path", &file_entry::symlink_path)
        .def_readwrite("filehash", &file_entry::filehash)
        .def_readwrite("mtime", &file_entry::mtime)
        .add_property("pad_file", &get_pad_file)
        .add_property("executable_attribute", &get_executable_attribute)
        .add_property("hidden_attribute", &get_hidden_attribute)
        .add_property("symlink_attribute", &get_symlink_attribute)
        .add_property("offset", &get_offset)
        .add_property("size", &get_size)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .add_property("tier", &get_tier, &set_tier)
        .add_property("fail_limit", &get_fail_limit, &set_fail_limit)
        .add_property("fails", &get_fails)
        .add_property("source", &get_source)
        .add_property("verified", &get_verified)
        .add_property("updating", &get_updating)
        .add_property("start_sent", &get_start_sent)
        .add_property("complete_sent", &get_complete_sent)
        .add_property("send_stats", &get_send_stats)

        .def("reset", &announce_entry::reset)
        .def("failed", &announce_entry::failed, arg("retry_interval") = 0)
        .def("can_announce", &announce_entry::can_announce)
        .def("is_working", &announce_entry::is_working)
        .def("trim", &announce_entry::trim)
        ;

    enum_<announce_entry::tracker_source>("tracker_source")
        .value("source_torrent", announce_entry::source_torrent)
        .value("source_client", announce_entry::source_client)
        .value("source_magnet_link", announce_entry::source_magnet_link)
        .value("source_tex", announce_entry::source_tex)
    ;
}

<|endoftext|>