<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2018 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "Metadata.h"

#include "database/SqliteTools.h"

#include <algorithm>

namespace medialibrary
{

const std::string Metadata::Table::Name = "Metadata";

Metadata::Record::Record( uint32_t t, std::string v )
    : m_type( t )
    , m_value( std::move( v ) )
    , m_isSet( true )
{
}

Metadata::Record::Record( uint32_t t )
    : m_type( t )
    , m_isSet( false )
{
}

bool Metadata::Record::isSet() const
{
    return m_isSet;
}

int64_t Metadata::Record::asInt() const
{
    return atoll( m_value.c_str() );
}

double Metadata::Record::asDouble() const
{
    return atof( m_value.c_str() );
}

const std::string& Metadata::Record::asStr() const
{
    return m_value;
}

void Metadata::Record::unset()
{
    m_isSet = false;
    m_value.clear();
}

Metadata::Metadata(MediaLibraryPtr ml , IMetadata::EntityType entityType)
    : m_ml( ml )
    , m_entityType( entityType )
    , m_nbMeta( 0 )
    , m_entityId( 0 )
{
}

void Metadata::init( int64_t entityId, uint32_t nbMeta )
{
    if ( isReady() == true )
        return;

    m_nbMeta = nbMeta;
    m_entityId = entityId;
    // Reserve the space for all meta to avoid a race condition where 2 threads
    // would cache different meta, invalidating the potential reference
    // to another IMediaMetadata held by another thread.
    // This guarantees the vector will not grow afterward.
    m_records.reserve( m_nbMeta );
    static const std::string req = "SELECT * FROM " + Metadata::Table::Name +
            " WHERE id_media = ? AND entity_type = ?";
    auto conn = m_ml->getConn();
    auto ctx = conn->acquireReadContext();
    sqlite::Statement stmt( conn->handle(), req );
    stmt.execute( m_entityId, m_entityType );
    for ( sqlite::Row row = stmt.row(); row != nullptr; row = stmt.row() )
    {
        assert( row.load<int64_t>( 0 ) == m_entityId );
        assert( row.load<IMetadata::EntityType>( 1 ) == m_entityType );
        m_records.emplace_back( row.load<decltype(Record::m_type)>( 2 ),
                          row.load<decltype(Record::m_value)>( 3 ) );
    }
}

void Metadata::clear()
{
    m_records.clear();
    m_records.reserve( m_nbMeta );
}

bool Metadata::isReady() const
{
    return m_nbMeta != 0;
}

IMetadata& Metadata::get( uint32_t type ) const
{
    assert( isReady() == true );

    auto it = std::find_if( begin( m_records ), end( m_records ), [type](const Record& r ) {
        return r.m_type == type;
    });
    if ( it == end( m_records ) )
    {
        // Create an unset meta for the given type˙No DB entity will be created until
        // the meta is actually set.
        m_records.emplace_back( type );
        return *( m_records.rbegin() );
    }
    return *it;
}

bool Metadata::set( uint32_t type, const std::string& value )
{
    assert( isReady() == true );

    auto it = std::find_if( begin( m_records ), end( m_records ), [type]( const Record& r ) {
        return r.m_type == type;
    });
    if ( it != end( m_records ) )
        (*it).set( value );
    else
        m_records.emplace_back( type, value );
    try
    {
        static const std::string req = "INSERT OR REPLACE INTO " + Metadata::Table::Name +
                "(id_media, entity_type, type, value) VALUES(?, ?, ?, ?)";
        return sqlite::Tools::executeInsert( m_ml->getConn(), req, m_entityId, m_entityType,
                                             type, value );
    }
    catch ( const sqlite::errors::Generic& ex )
    {
        LOG_ERROR( "Failed to update media metadata: ", ex.what() );
        return false;
    }
}

bool Metadata::set( uint32_t type, int64_t value )
{
    auto str = std::to_string( value );
    return set( type, str );
}

bool Metadata::unset( uint32_t type )
{
    assert( isReady() == true );
    auto it = std::find_if( begin( m_records ), end( m_records ), [type]( const Record& r ) {
        return r.m_type == type;
    });
    if ( it != end( m_records ) )
    {
        static const std::string req = "DELETE FROM " + Metadata::Table::Name +
                " WHERE id_media = ? AND entity_type = ? AND type = ?";
        (*it).unset();
        return sqlite::Tools::executeDelete( m_ml->getConn(), req, m_entityId,
                                             m_entityType, type );
    }
    return true;
}

const std::vector<Metadata::Record>& Metadata::all() const
{
    return m_records;
}

void Metadata::unset( sqlite::Connection* dbConn, IMetadata::EntityType entityType, uint32_t type )
{
    static const std::string req = "DELETE FROM " + Metadata::Table::Name +
            " WHERE entity_type = ? AND type = ? ";
    sqlite::Tools::executeDelete( dbConn, req, entityType, type );
}

void Metadata::createTable(sqlite::Connection* connection)
{
    const std::string reqs[] = {
        schema( Table::Name, Settings::DbModelVersion ),
    };
    for ( const auto& req : reqs )
        sqlite::Tools::executeRequest( connection, req );
}

std::string Metadata::schema( const std::string& tableName, uint32_t dbModel )
{
    assert( tableName == Table::Name );
    if ( dbModel < 14 )
    {
        return "CREATE TABLE IF NOT EXISTS " + Table::Name +
        "("
            "id_media INTEGER,"
            "type INTEGER,"
            "value TEXT"
        ")";
    }
    return "CREATE TABLE IF NOT EXISTS " + Table::Name +
    "("
        "id_media INTEGER,"
        "entity_type INTEGER,"
        "type INTEGER,"
        "value TEXT,"
        "PRIMARY KEY(id_media,entity_type,type)"
    ")";
}

void Metadata::Record::set( const std::string& value )
{
    m_value = value;
    m_isSet = true;
}

uint32_t Metadata::Record::type() const
{
    return m_type;
}

}
<commit_msg>Metadata: Remove IF NOT EXISTS from the table creation requests<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2018 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "Metadata.h"

#include "database/SqliteTools.h"

#include <algorithm>

namespace medialibrary
{

const std::string Metadata::Table::Name = "Metadata";

Metadata::Record::Record( uint32_t t, std::string v )
    : m_type( t )
    , m_value( std::move( v ) )
    , m_isSet( true )
{
}

Metadata::Record::Record( uint32_t t )
    : m_type( t )
    , m_isSet( false )
{
}

bool Metadata::Record::isSet() const
{
    return m_isSet;
}

int64_t Metadata::Record::asInt() const
{
    return atoll( m_value.c_str() );
}

double Metadata::Record::asDouble() const
{
    return atof( m_value.c_str() );
}

const std::string& Metadata::Record::asStr() const
{
    return m_value;
}

void Metadata::Record::unset()
{
    m_isSet = false;
    m_value.clear();
}

Metadata::Metadata(MediaLibraryPtr ml , IMetadata::EntityType entityType)
    : m_ml( ml )
    , m_entityType( entityType )
    , m_nbMeta( 0 )
    , m_entityId( 0 )
{
}

void Metadata::init( int64_t entityId, uint32_t nbMeta )
{
    if ( isReady() == true )
        return;

    m_nbMeta = nbMeta;
    m_entityId = entityId;
    // Reserve the space for all meta to avoid a race condition where 2 threads
    // would cache different meta, invalidating the potential reference
    // to another IMediaMetadata held by another thread.
    // This guarantees the vector will not grow afterward.
    m_records.reserve( m_nbMeta );
    static const std::string req = "SELECT * FROM " + Metadata::Table::Name +
            " WHERE id_media = ? AND entity_type = ?";
    auto conn = m_ml->getConn();
    auto ctx = conn->acquireReadContext();
    sqlite::Statement stmt( conn->handle(), req );
    stmt.execute( m_entityId, m_entityType );
    for ( sqlite::Row row = stmt.row(); row != nullptr; row = stmt.row() )
    {
        assert( row.load<int64_t>( 0 ) == m_entityId );
        assert( row.load<IMetadata::EntityType>( 1 ) == m_entityType );
        m_records.emplace_back( row.load<decltype(Record::m_type)>( 2 ),
                          row.load<decltype(Record::m_value)>( 3 ) );
    }
}

void Metadata::clear()
{
    m_records.clear();
    m_records.reserve( m_nbMeta );
}

bool Metadata::isReady() const
{
    return m_nbMeta != 0;
}

IMetadata& Metadata::get( uint32_t type ) const
{
    assert( isReady() == true );

    auto it = std::find_if( begin( m_records ), end( m_records ), [type](const Record& r ) {
        return r.m_type == type;
    });
    if ( it == end( m_records ) )
    {
        // Create an unset meta for the given type˙No DB entity will be created until
        // the meta is actually set.
        m_records.emplace_back( type );
        return *( m_records.rbegin() );
    }
    return *it;
}

bool Metadata::set( uint32_t type, const std::string& value )
{
    assert( isReady() == true );

    auto it = std::find_if( begin( m_records ), end( m_records ), [type]( const Record& r ) {
        return r.m_type == type;
    });
    if ( it != end( m_records ) )
        (*it).set( value );
    else
        m_records.emplace_back( type, value );
    try
    {
        static const std::string req = "INSERT OR REPLACE INTO " + Metadata::Table::Name +
                "(id_media, entity_type, type, value) VALUES(?, ?, ?, ?)";
        return sqlite::Tools::executeInsert( m_ml->getConn(), req, m_entityId, m_entityType,
                                             type, value );
    }
    catch ( const sqlite::errors::Generic& ex )
    {
        LOG_ERROR( "Failed to update media metadata: ", ex.what() );
        return false;
    }
}

bool Metadata::set( uint32_t type, int64_t value )
{
    auto str = std::to_string( value );
    return set( type, str );
}

bool Metadata::unset( uint32_t type )
{
    assert( isReady() == true );
    auto it = std::find_if( begin( m_records ), end( m_records ), [type]( const Record& r ) {
        return r.m_type == type;
    });
    if ( it != end( m_records ) )
    {
        static const std::string req = "DELETE FROM " + Metadata::Table::Name +
                " WHERE id_media = ? AND entity_type = ? AND type = ?";
        (*it).unset();
        return sqlite::Tools::executeDelete( m_ml->getConn(), req, m_entityId,
                                             m_entityType, type );
    }
    return true;
}

const std::vector<Metadata::Record>& Metadata::all() const
{
    return m_records;
}

void Metadata::unset( sqlite::Connection* dbConn, IMetadata::EntityType entityType, uint32_t type )
{
    static const std::string req = "DELETE FROM " + Metadata::Table::Name +
            " WHERE entity_type = ? AND type = ? ";
    sqlite::Tools::executeDelete( dbConn, req, entityType, type );
}

void Metadata::createTable(sqlite::Connection* connection)
{
    const std::string reqs[] = {
        schema( Table::Name, Settings::DbModelVersion ),
    };
    for ( const auto& req : reqs )
        sqlite::Tools::executeRequest( connection, req );
}

std::string Metadata::schema( const std::string& tableName, uint32_t dbModel )
{
    assert( tableName == Table::Name );
    if ( dbModel < 14 )
    {
        return "CREATE TABLE " + Table::Name +
        "("
            "id_media INTEGER,"
            "type INTEGER,"
            "value TEXT"
        ")";
    }
    return "CREATE TABLE " + Table::Name +
    "("
        "id_media INTEGER,"
        "entity_type INTEGER,"
        "type INTEGER,"
        "value TEXT,"
        "PRIMARY KEY(id_media,entity_type,type)"
    ")";
}

void Metadata::Record::set( const std::string& value )
{
    m_value = value;
    m_isSet = true;
}

uint32_t Metadata::Record::type() const
{
    return m_type;
}

}
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* 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.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

//#include "stdafx.h"

#include "common/ExtManager.h"
#include "rubyext/WebView.h"
#include <common/RhodesApp.h>

//#include "MainWindow.h"
#include "common/app_build_capabilities.h"

//extern CMainWindow& getAppWindow();
//#define IDM_NAVIGATE                    40022
//#define IDM_EXECUTEJS                   40033
//#define IDM_STOPNAVIGATE                40034
//#define IDM_ZOOMPAGE                    40035
//#define IDM_ZOOMTEXT                    40036
extern "C" HWND getMainWnd();
extern "C" HINSTANCE rho_wmimpl_get_appinstance();
extern "C" void rho_sys_app_exit();
extern "C" WCHAR* rho_wmimpl_get_configfilepath();

namespace rho {
namespace common {

IMPLEMENT_LOGCLASS(CExtManager, "ExtManager");

void CExtManager::registerExtension(const String& strName, IRhoExtension* pExt)
{
    m_hashExtensions.put(strName, pExt);
}

IRhoExtension* CExtManager::getExtByName(const String& strName)
{
    return m_hashExtensions.get(strName);
}

CRhoExtData CExtManager::makeExtData()
{
    CRhoExtData oData;
    oData.m_hWnd = getMainWnd();
    oData.m_hInstance = rho_wmimpl_get_appinstance();
#if !defined(OS_WINDOWS_DESKTOP)
    //oData.m_hBrowserWnd = getAppWindow().getWebKitEngine()->GetHTMLWND();
#endif

    oData.m_iTabIndex = rho_webview_active_tab();
    return oData;
}

void CExtManager::onSetPropertiesData( const wchar_t* pPropID, const wchar_t* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onSetPropertiesData( pPropID, pData, makeExtData() );
    }
}

void CExtManager::onUnhandledProperty( const wchar_t* pModuleName, const wchar_t* pName, const wchar_t* pValue, const CRhoExtData& oExtData )
{
    rho::common::IRhoExtension* pExt = getExtByName( rho::common::convertToStringA(pModuleName) );
    if (pExt)
        pExt->onSetProperty( pName, pValue, oExtData );
}

void CExtManager::onBeforeNavigate(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onBeforeNavigate( szUrlBeingNavigatedTo, makeExtData() );
    }
}

void CExtManager::onNavigateComplete(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onNavigateComplete( szUrlBeingNavigatedTo, makeExtData() );
    }
}

void CExtManager::onDocumentComplete(const wchar_t* szUrlOfDocument)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onDocumentComplete( szUrlOfDocument, makeExtData() );
    }
}

void CExtManager::close()
{
   m_hashExtensions.clear();
}

void CExtManager::executeRubyCallback( const char* szCallback, const char* szCallbackBody, const char* szCallbackData, bool bWaitForResponse)
{
    //RHODESAPP().callCallbackWithData(szCallback, szCallbackBody, szCallbackData, bWaitForResponse );
}

void CExtManager::executeRubyCallbackWithJsonBody( const char* szCallback, const char* szCallbackBody, const char* szCallbackData, bool bWaitForResponse)
{
    //RHODESAPP().callCallbackWithJsonBody(szCallback, szCallbackBody, szCallbackData, bWaitForResponse );
}

//extern "C" VALUE rjson_tokener_parse(const char *str, char** pszError );
unsigned long CExtManager::parseJsonToRubyHash(const char* szJson)
{
    //char* szError = 0;
    //unsigned long valBody = rjson_tokener_parse(szJson, &szError);
    //if ( valBody != 0 )
    //    return valBody;

    //LOG(ERROR) + "Incorrect json body.Error:" + (szError ? szError : "");
    //if ( szError )
    //    free(szError);

    //return rho_ruby_get_NIL();
	return 0;
}

void CExtManager::navigate(const wchar_t* szUrl)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_NAVIGATE, (LPARAM)_wcsdup(szUrl) );
}

bool CExtManager::existsJavascript(const wchar_t* szJSFunction)
{
#if !defined(OS_WINDOWS_DESKTOP)
    return false; //getAppWindow().getWebKitEngine()->isExistJavascript(szJSFunction, rho_webview_active_tab());
#else
    return true;
#endif
}

void CExtManager::setBrowserGesturing(bool bEnableGesturing)
{
#if !defined(OS_WINDOWS_DESKTOP)
    //getAppWindow().getWebKitEngine()->setBrowserGesturing(bEnableGesturing);
#endif

}

void CExtManager::passSipPositionToEngine()
{
#if !defined(OS_WINDOWS_DESKTOP)
    //getAppWindow().getWebKitEngine()->NotifyEngineOfSipPosition();
#endif
}

void CExtManager::executeJavascript(const wchar_t* szJSFunction)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_EXECUTEJS, (LPARAM)_wcsdup(szJSFunction) );
}

StringW CExtManager::getCurrentUrl()
{
    return L"";//convertToStringW(RHODESAPP().getCurrentUrl(rho_webview_active_tab()));
}

void CExtManager::historyForward()
{
    //rho_webview_navigate_forward();
}

void CExtManager::historyBack()
{
    //rho_webview_navigate_back();
}

void CExtManager::refreshPage(bool bFromCache)
{
    //rho_webview_refresh(rho_webview_active_tab());
}

void CExtManager::stopNavigate()
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_STOPNAVIGATE, (LPARAM)rho_webview_active_tab() );
}

void CExtManager::quitApp()
{
    //rho_sys_app_exit();
}

static void __minimize_restoreApp(int nParam)
{
    //::ShowWindow(getMainWnd(), nParam );
}

void CExtManager::minimizeApp()
{
    //rho_callInUIThread(__minimize_restoreApp, SW_MINIMIZE);
}

void CExtManager::restoreApp()
{
   // rho_callInUIThread(__minimize_restoreApp, SW_RESTORE);
}

void CExtManager::resizeBrowserWindow(RECT rc)
{
    //::MoveWindow( getMainWnd(), rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE );
}

void CExtManager::zoomPage(float fZoom)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_ZOOMPAGE, (LPARAM)new CRhoFloatData(fZoom) );
}

void CExtManager::zoomText(int nZoom)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_ZOOMTEXT, (LPARAM)nZoom );
}

int CExtManager::getTextZoom() //Enum (0 to 4)
{
#if !defined(OS_WINDOWS_DESKTOP)
    return 0;//getAppWindow().getWebKitEngine()->GetTextZoomOnTab(rho_webview_active_tab());
#else
    return 2;
#endif
}

StringW CExtManager::getConfigPath()
{
#if defined(APP_BUILD_CAPABILITY_MOTOROLA)
    return L"";//rho_wmimpl_get_configfilepath();
#else
    return L"";
#endif
}

StringW CExtManager::getPageTitle(UINT iTab)
{
#if !defined(OS_WINDOWS_DESKTOP)
    wchar_t szBuf[1025];
    szBuf[0]=0;
    //getAppWindow().getWebKitEngine()->GetTitleOnTab( szBuf, 1024, iTab );
    return szBuf ? szBuf : L"";
#else
    return L"";
#endif
}

extern "C" int rho_wmimpl_is_loglevel_enabled(int nLogLevel);
extern "C" bool rho_wmimpl_get_is_version2();
void CExtManager::rhoLog(ELogExtLevels eLogLevel, const char* szModule, const char* szMsg, const char* szFile, int nLine)
{
#if defined(APP_BUILD_CAPABILITY_SHARED_RUNTIME)
    bool bRE1App = false;

    if (!rho_wmimpl_get_is_version2())
        bRE1App = true;

    if (bRE1App && !rho_wmimpl_is_loglevel_enabled(eLogLevel))
        return;
#endif

    int nSeverity = L_INFO;
    switch (eLogLevel)
    {
    case eLogError:
	    nSeverity = L_ERROR;
	    break;
    case eLogWarning:
        nSeverity = L_WARNING;
	    break;
    case eLogInfo:
        nSeverity = L_INFO;
	    break;
    case eLogUser:
        nSeverity = L_INFO;
	    break;
    case eLogDebug:
        nSeverity = L_TRACE;
	    break;
    }

    //rhoPlainLog(szFile, nLine, nSeverity, szModule, szMsg);

}

bool CExtManager::onWndMsg(MSG& oMsg)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        if ( (it->second)->onWndMsg( oMsg ) )
            return true;
    }

    return false;
}

bool CExtManager::onHTMLWndMsg(MSG& oMsg)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        if ( (it->second)->onHTMLWndMsg( oMsg ) )
            return true;
    }

    return false;
}

long CExtManager::OnNavigateTimeout(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnNavigateTimeout( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnSIPState(bool bSIPState)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnSIPState( bSIPState, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnAlertPopup(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnAlertPopup( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnAuthenticationRequest(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnAuthenticationRequest( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnGeolocationData(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnGeolocationData( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnNavigateError(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnNavigateError( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnLicenseError(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnLicenseError( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

void CExtManager::OnAppActivate(bool bActivate)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->OnAppActivate( bActivate, makeExtData() );
    }
}

void CExtManager::OnWindowChanged(LPVOID lparam)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->OnWindowChanged( lparam );
    }
}

//DWORD CExtManager::getProcessId()
//{
//#if !defined(OS_WINDOWS_DESKTOP)
//    return 0;//getAppWindow().getWebKitEngine()->GetProcessID();
//#else
//    return 0;
//#endif
//}
} //namespace common
} //namespace rho

<commit_msg>wp8: build fixed<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* 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.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

//#include "stdafx.h"

#include "common/ExtManager.h"
#include "rubyext/WebView.h"
#include <common/RhodesApp.h>

//#include "MainWindow.h"
#include "common/app_build_capabilities.h"

//extern CMainWindow& getAppWindow();
//#define IDM_NAVIGATE                    40022
//#define IDM_EXECUTEJS                   40033
//#define IDM_STOPNAVIGATE                40034
//#define IDM_ZOOMPAGE                    40035
//#define IDM_ZOOMTEXT                    40036
extern "C" HWND getMainWnd();
extern "C" HINSTANCE rho_wmimpl_get_appinstance();
extern "C" void rho_sys_app_exit();
extern "C" WCHAR* rho_wmimpl_get_configfilepath();

namespace rho {
namespace common {

IMPLEMENT_LOGCLASS(CExtManager, "ExtManager");

void CExtManager::registerExtension(const String& strName, IRhoExtension* pExt)
{
    m_hashExtensions.put(strName, pExt);
}

IRhoExtension* CExtManager::getExtByName(const String& strName)
{
    return m_hashExtensions.get(strName);
}

CRhoExtData CExtManager::makeExtData()
{
    CRhoExtData oData;
    oData.m_hWnd = getMainWnd();
    oData.m_hInstance = rho_wmimpl_get_appinstance();
#if !defined(OS_WINDOWS_DESKTOP)
    //oData.m_hBrowserWnd = getAppWindow().getWebKitEngine()->GetHTMLWND();
#endif

    oData.m_iTabIndex = rho_webview_active_tab();
    return oData;
}

void CExtManager::onSetPropertiesData( const wchar_t* pPropID, const wchar_t* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onSetPropertiesData( pPropID, pData, makeExtData() );
    }
}

void CExtManager::onUnhandledProperty( const wchar_t* pModuleName, const wchar_t* pName, const wchar_t* pValue, const CRhoExtData& oExtData )
{
    rho::common::IRhoExtension* pExt = getExtByName( rho::common::convertToStringA(pModuleName) );
    if (pExt)
        pExt->onSetProperty( pName, pValue, oExtData );
}

void CExtManager::onBeforeNavigate(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onBeforeNavigate( szUrlBeingNavigatedTo, makeExtData() );
    }
}

void CExtManager::onNavigateComplete(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onNavigateComplete( szUrlBeingNavigatedTo, makeExtData() );
    }
}

void CExtManager::onDocumentComplete(const wchar_t* szUrlOfDocument)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->onDocumentComplete( szUrlOfDocument, makeExtData() );
    }
}

void CExtManager::close()
{
   m_hashExtensions.clear();
}

void CExtManager::executeRubyCallback( const char* szCallback, const char* szCallbackBody, const char* szCallbackData, bool bWaitForResponse)
{
    //RHODESAPP().callCallbackWithData(szCallback, szCallbackBody, szCallbackData, bWaitForResponse );
}

void CExtManager::executeRubyCallbackWithJsonBody( const char* szCallback, const char* szCallbackBody, const char* szCallbackData, bool bWaitForResponse)
{
    //RHODESAPP().callCallbackWithJsonBody(szCallback, szCallbackBody, szCallbackData, bWaitForResponse );
}

//extern "C" VALUE rjson_tokener_parse(const char *str, char** pszError );
unsigned long CExtManager::parseJsonToRubyHash(const char* szJson)
{
    //char* szError = 0;
    //unsigned long valBody = rjson_tokener_parse(szJson, &szError);
    //if ( valBody != 0 )
    //    return valBody;

    //LOG(ERROR) + "Incorrect json body.Error:" + (szError ? szError : "");
    //if ( szError )
    //    free(szError);

    //return rho_ruby_get_NIL();
	return 0;
}

void CExtManager::navigate(const wchar_t* szUrl)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_NAVIGATE, (LPARAM)_wcsdup(szUrl) );
}

bool CExtManager::existsJavascript(const wchar_t* szJSFunction)
{
#if !defined(OS_WINDOWS_DESKTOP)
    return false; //getAppWindow().getWebKitEngine()->isExistJavascript(szJSFunction, rho_webview_active_tab());
#else
    return true;
#endif
}

void CExtManager::setBrowserGesturing(bool bEnableGesturing)
{
#if !defined(OS_WINDOWS_DESKTOP)
    //getAppWindow().getWebKitEngine()->setBrowserGesturing(bEnableGesturing);
#endif

}

void CExtManager::passSipPositionToEngine()
{
#if !defined(OS_WINDOWS_DESKTOP)
    //getAppWindow().getWebKitEngine()->NotifyEngineOfSipPosition();
#endif
}

void CExtManager::executeJavascript(const wchar_t* szJSFunction)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_EXECUTEJS, (LPARAM)_wcsdup(szJSFunction) );
}

StringW CExtManager::getCurrentUrl()
{
    return L"";//convertToStringW(RHODESAPP().getCurrentUrl(rho_webview_active_tab()));
}

void CExtManager::historyForward()
{
    //rho_webview_navigate_forward();
}

void CExtManager::historyBack()
{
    //rho_webview_navigate_back();
}

void CExtManager::refreshPage(bool bFromCache)
{
    //rho_webview_refresh(rho_webview_active_tab());
}

void CExtManager::stopNavigate()
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_STOPNAVIGATE, (LPARAM)rho_webview_active_tab() );
}

void CExtManager::quitApp()
{
    //rho_sys_app_exit();
}

static void __minimize_restoreApp(int nParam)
{
    //::ShowWindow(getMainWnd(), nParam );
}

void CExtManager::minimizeApp()
{
    //rho_callInUIThread(__minimize_restoreApp, SW_MINIMIZE);
}

void CExtManager::restoreApp()
{
   // rho_callInUIThread(__minimize_restoreApp, SW_RESTORE);
}

void CExtManager::resizeBrowserWindow(RECT rc)
{
    //::MoveWindow( getMainWnd(), rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE );
}

void CExtManager::zoomPage(float fZoom)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_ZOOMPAGE, (LPARAM)new CRhoFloatData(fZoom) );
}

void CExtManager::zoomText(int nZoom)
{
    //::PostMessage( getMainWnd(), WM_COMMAND, IDM_ZOOMTEXT, (LPARAM)nZoom );
}

int CExtManager::getTextZoom() //Enum (0 to 4)
{
#if !defined(OS_WINDOWS_DESKTOP)
    return 0;//getAppWindow().getWebKitEngine()->GetTextZoomOnTab(rho_webview_active_tab());
#else
    return 2;
#endif
}

StringW CExtManager::getConfigPath()
{
#if defined(APP_BUILD_CAPABILITY_MOTOROLA)
    return L"";//rho_wmimpl_get_configfilepath();
#else
    return L"";
#endif
}

StringW CExtManager::getPageTitle(UINT iTab)
{
#if !defined(OS_WINDOWS_DESKTOP)
    wchar_t szBuf[1025];
    szBuf[0]=0;
    //getAppWindow().getWebKitEngine()->GetTitleOnTab( szBuf, 1024, iTab );
    return szBuf ? szBuf : L"";
#else
    return L"";
#endif
}

extern "C" int rho_wmimpl_is_loglevel_enabled(int nLogLevel);
extern "C" bool rho_wmimpl_get_is_version2();
void CExtManager::rhoLog(ELogExtLevels eLogLevel, const char* szModule, const char* szMsg, const char* szFile, int nLine)
{
#if defined(APP_BUILD_CAPABILITY_SHARED_RUNTIME)
    bool bRE1App = false;

    if (!rho_wmimpl_get_is_version2())
        bRE1App = true;

    if (bRE1App && !rho_wmimpl_is_loglevel_enabled(eLogLevel))
        return;
#endif

    int nSeverity = L_INFO;
    switch (eLogLevel)
    {
    case eLogError:
	    nSeverity = L_ERROR;
	    break;
    case eLogWarning:
        nSeverity = L_WARNING;
	    break;
    case eLogInfo:
        nSeverity = L_INFO;
	    break;
    case eLogUser:
        nSeverity = L_INFO;
	    break;
    case eLogDebug:
        nSeverity = L_TRACE;
	    break;
    }

    //rhoPlainLog(szFile, nLine, nSeverity, szModule, szMsg);

}

bool CExtManager::onWndMsg(MSG& oMsg)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        if ( (it->second)->onWndMsg( oMsg ) )
            return true;
    }

    return false;
}

bool CExtManager::onHTMLWndMsg(MSG& oMsg)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        if ( (it->second)->onHTMLWndMsg( oMsg ) )
            return true;
    }

    return false;
}

long CExtManager::OnNavigateTimeout(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnNavigateTimeout( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnSIPState(bool bSIPState)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnSIPState( bSIPState, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnAlertPopup(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnAlertPopup( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnAuthenticationRequest(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnAuthenticationRequest( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnGeolocationData(int nEnum, void* pData)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnGeolocationData( nEnum, pData, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnNavigateError(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnNavigateError( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

long CExtManager::OnLicenseError(const wchar_t* szUrlBeingNavigatedTo)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        long lRes = (it->second)->OnLicenseError( szUrlBeingNavigatedTo, makeExtData() );
        if ( lRes )
            return lRes;
    }

    return 0;
}

void CExtManager::OnAppActivate(bool bActivate)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->OnAppActivate( bActivate, makeExtData() );
    }
}

void CExtManager::OnWindowChanged(LPVOID lparam)
{
    for ( HashtablePtr<String, IRhoExtension*>::iterator it = m_hashExtensions.begin(); it != m_hashExtensions.end(); ++it )
    {
        (it->second)->OnWindowChanged( lparam );
    }
}

bool CExtManager::RegisterForMessageCallback(unsigned int iMsgId)
{
    //return getAppWindow().getWebKitEngine()->RegisterForMessage(iMsgId);
	return true;
}

bool CExtManager::DeRegisterForMessageCallback(unsigned int iMsgId)
{
    //return getAppWindow().getWebKitEngine()->DeRegisterForMessage(iMsgId);
	return true;
}

//DWORD CExtManager::getProcessId()
//{
//#if !defined(OS_WINDOWS_DESKTOP)
//    return 0;//getAppWindow().getWebKitEngine()->GetProcessID();
//#else
//    return 0;
//#endif
//}
} //namespace common
} //namespace rho

<|endoftext|>


<commit_before>/* Copyright 2017 - 2021 R. Thomas
 * Copyright 2017 - 2021 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>
#include <fstream>
#include <iterator>
#include <exception>
#include <string>
#include <numeric>
#include <iomanip>
#include <sstream>
#include <string>

#include "logging.hpp"
#include "mbedtls/md5.h"

#include "LIEF/exception.hpp"

#include "LIEF/PE/utils.hpp"
#include "LIEF/PE/Structures.hpp"
#include "LIEF/PE/Binary.hpp"
#include "LIEF/PE/Import.hpp"
#include "LIEF/PE/ImportEntry.hpp"
#include "LIEF/BinaryStream/VectorStream.hpp"

#include "LIEF/utils.hpp"

#include "utils/ordinals_lookup_tables/libraries_table.hpp"
#include "utils/ordinals_lookup_tables_std/libraries_table.hpp"

#include "hash_stream.hpp"

namespace LIEF {
namespace PE {

inline std::string to_lower(std::string str) {
  std::string lower = str;
  std::transform(std::begin(str), std::end(str),
    std::begin(lower), ::tolower);
  return lower;
}

bool is_pe(const std::string& file) {
  std::ifstream binary(file, std::ios::in | std::ios::binary);
  if (not binary) {
    LIEF_ERR("Unable to open the file!");
    return false;
  }

  uint64_t file_size;
  binary.unsetf(std::ios::skipws);
  binary.seekg(0, std::ios::end);
  file_size = binary.tellg();
  binary.seekg(0, std::ios::beg);

  if (file_size < sizeof(pe_dos_header)) {
    LIEF_ERR("File too small");
    return false;
  }

  char magic[2];
  pe_dos_header dos_header;
  binary.read(magic, sizeof(magic));
  if (magic[0] != 'M' or magic[1] != 'Z') {
    return false;
  }

  binary.seekg(0, std::ios::beg);
  binary.read(reinterpret_cast<char*>(&dos_header), sizeof(pe_dos_header));
  if (dos_header.AddressOfNewExeHeader >= file_size) {
    return false;
  }
  char signature[sizeof(PE_Magic)];
  binary.seekg(dos_header.AddressOfNewExeHeader, std::ios::beg);
  binary.read(signature, sizeof(PE_Magic));
  return std::equal(std::begin(signature), std::end(signature), std::begin(PE_Magic));
}

bool is_pe(const std::vector<uint8_t>& raw) {

  if (raw.size() < sizeof(pe_dos_header)) {
    return false;
  }

  const pe_dos_header* dos_header = reinterpret_cast<const pe_dos_header*>(raw.data());
  if (raw[0] != 'M' or raw[1] != 'Z') {
    return false;
  }

  if ((dos_header->AddressOfNewExeHeader + sizeof(pe_header)) >= raw.size()) {
    return false;
  }

  VectorStream raw_stream(raw);
  raw_stream.setpos(dos_header->AddressOfNewExeHeader);
  auto signature = raw_stream.read_array<char>(sizeof(PE_Magic), /* check bounds */ true);

  return std::equal(signature, signature + sizeof(PE_Magic), std::begin(PE_Magic));
}

PE_TYPE get_type(const std::string& file) {
  if (not is_pe(file)) {
    throw LIEF::bad_format("This file is not a PE binary");
  }

  std::ifstream binary(file, std::ios::in | std::ios::binary);
  if (not binary) {
    throw LIEF::bad_file("Unable to open the file");
  }

  pe_dos_header          dos_header;
  pe32_optional_header   optional_header;
  binary.seekg(0, std::ios::beg);

  binary.read(reinterpret_cast<char*>(&dos_header), sizeof(pe_dos_header));

  binary.seekg(dos_header.AddressOfNewExeHeader + sizeof(pe_header), std::ios::beg);
  binary.read(reinterpret_cast<char*>(&optional_header), sizeof(pe32_optional_header));
  PE_TYPE type = static_cast<PE_TYPE>(optional_header.Magic);

  if (type == PE_TYPE::PE32 or type == PE_TYPE::PE32_PLUS) {
    return type;
  } else {
    throw LIEF::bad_format("This file is not PE32 or PE32+");
  }

}

PE_TYPE get_type(const std::vector<uint8_t>& raw) {
  if (not is_pe(raw)) {
    throw LIEF::bad_format("This file is not a PE binary");
  }

  VectorStream raw_stream = VectorStream(raw);

  const pe_dos_header* dos_header = &raw_stream.read<pe_dos_header>();
  raw_stream.setpos(dos_header->AddressOfNewExeHeader + sizeof(pe_header));
  const pe32_optional_header* optional_header = &raw_stream.read<pe32_optional_header>();

  PE_TYPE type = static_cast<PE_TYPE>(optional_header->Magic);

  if (type == PE_TYPE::PE32 or type == PE_TYPE::PE32_PLUS) {
    return type;
  } else {
    throw LIEF::bad_format("This file is not PE32 or PE32+");
  }

}

std::string get_imphash_std(const Binary& binary) {
  static const std::set<std::string> ALLOWED_EXT = {"dll", "ocx", "sys"};
  std::vector<uint8_t> md5_buffer(16);
  if (not binary.has_imports()) {
    return "";
  }
  std::string lstr;
  bool first_entry = true;
  hashstream hs(hashstream::HASH::MD5);
  for (const Import& imp : binary.imports()) {
    std::string libname = imp.name();

    Import resolved = resolve_ordinals(imp, /* strict */ false, /* use_std */ true);
    size_t ext_idx = resolved.name().find_last_of(".");
    std::string name = resolved.name();
    std::string ext;
    if (ext_idx != std::string::npos) {
      ext = to_lower(resolved.name().substr(ext_idx + 1));
    }
    if (ALLOWED_EXT.find(ext) != std::end(ALLOWED_EXT)) {
      name = name.substr(0, ext_idx);
    }

    std::string entries_string;
    for (const ImportEntry& e : resolved.entries()) {
      std::string funcname;
      if (e.is_ordinal()) {
        funcname = "ord" + std::to_string(e.ordinal());
      } else {
        funcname = e.name();
      }

      if (not entries_string.empty()) {
        entries_string += ",";
      }
      entries_string += name + "." + funcname;
    }
    if (not first_entry) {
      lstr += ",";
    } else {
      first_entry = false;
    }
    lstr += to_lower(entries_string);

    // use write(uint8_t*, size_t) instead of write(const std::string&) to avoid null char
    hs.write(reinterpret_cast<const uint8_t*>(lstr.data()), lstr.size());
    lstr.clear();
  }

  return hex_dump(hs.raw(), "");
}

std::string get_imphash_lief(const Binary& binary) {
  std::vector<uint8_t> md5_buffer(16);
  if (not binary.has_imports()) {
    return std::to_string(0);
  }

  it_const_imports imports = binary.imports();

  std::string import_list;
  for (const Import& imp : imports) {
    Import resolved = resolve_ordinals(imp);
    size_t ext_idx = resolved.name().find_last_of(".");
    std::string name_without_ext = resolved.name();

    if (ext_idx != std::string::npos) {
      name_without_ext = name_without_ext.substr(0, ext_idx);
    }

    std::string entries_string;
    for (const ImportEntry& e : resolved.entries()) {
      if (e.is_ordinal()) {
        entries_string += name_without_ext + ".#" + std::to_string(e.ordinal());
      } else {
        entries_string += name_without_ext + "." + e.name();
      }
    }
    import_list += to_lower(entries_string);
  }

  std::sort(
      std::begin(import_list),
      std::end(import_list),
      std::less<char>());

  mbedtls_md5(
      reinterpret_cast<const uint8_t*>(import_list.data()),
      import_list.size(),
      md5_buffer.data());
  return hex_dump(md5_buffer, "");
}

std::string get_imphash(const Binary& binary, IMPHASH_MODE mode) {
  switch (mode) {
    case IMPHASH_MODE::LIEF:
      {
        return get_imphash_lief(binary);
      }
    case IMPHASH_MODE::PEFILE:
      {
        return get_imphash_std(binary);
      }
  }
  return "";
}

Import resolve_ordinals(const Import& import, bool strict, bool use_std) {

  it_const_import_entries entries = import.entries();

  if (std::all_of(
        std::begin(entries),
        std::end(entries),
        [] (const ImportEntry& entry) {
          return not entry.is_ordinal();
        })) {
    LIEF_DEBUG("All imports use name. No ordinal!");
    return import;
  }

  std::string name = to_lower(import.name());

  std::function<const char*(uint32_t)> ordinal_resolver;
  if (use_std) {
    auto it = imphashstd::ordinals_library_tables.find(name);
    if (it != std::end(imphashstd::ordinals_library_tables)) {
      ordinal_resolver = it->second;
    }
  } else {
    auto it = ordinals_library_tables.find(name);
    if (it != std::end(ordinals_library_tables)) {
      ordinal_resolver = it->second;
    }
  }

  if (not ordinal_resolver) {
    std::string msg = "Ordinal lookup table for '" + name + "' not implemented";
    if (strict) {
      throw not_found(msg);
    }
    LIEF_DEBUG("{}", msg);
    return import;
  }

  Import resolved_import = import;
  for (ImportEntry& entry : resolved_import.entries()) {
    if (entry.is_ordinal()) {
      LIEF_DEBUG("Dealing with: {}", entry);
      const char* entry_name = ordinal_resolver(static_cast<uint32_t>(entry.ordinal()));
      if (entry_name == nullptr) {
        if (strict) {
          throw not_found("Unable to resolve ordinal: " + std::to_string(entry.ordinal()));
        }
        LIEF_DEBUG("Unable to resolve ordinal: #{:d}", entry.ordinal());
        continue;
      }
      entry.data(0);
      entry.name(entry_name);
    }
  }

  return resolved_import;
}
ALGORITHMS algo_from_oid(const std::string& oid) {
  static const std::unordered_map<std::string, ALGORITHMS> OID_MAP = {
    { "2.16.840.1.101.3.4.2.3", ALGORITHMS::SHA_512 },
    { "2.16.840.1.101.3.4.2.2", ALGORITHMS::SHA_384 },
    { "2.16.840.1.101.3.4.2.1", ALGORITHMS::SHA_256 },
    { "1.3.14.3.2.26",          ALGORITHMS::SHA_1   },

    { "1.2.840.113549.2.5",     ALGORITHMS::MD5 },
    { "1.2.840.113549.2.4",     ALGORITHMS::MD4 },
    { "1.2.840.113549.2.2",     ALGORITHMS::MD2 },

    { "1.2.840.113549.1.1.1",   ALGORITHMS::RSA },
    { "1.2.840.10045.2.1",      ALGORITHMS::EC  },

    { "1.2.840.113549.1.1.4",   ALGORITHMS::MD5_RSA        },
    { "1.2.840.10040.4.3",      ALGORITHMS::SHA1_DSA       },
    { "1.2.840.113549.1.1.5",   ALGORITHMS::SHA1_RSA       },
    { "1.2.840.113549.1.1.11",  ALGORITHMS::SHA_256_RSA    },
    { "1.2.840.113549.1.1.12",  ALGORITHMS::SHA_384_RSA    },
    { "1.2.840.113549.1.1.13",  ALGORITHMS::SHA_512_RSA    },
    { "1.2.840.10045.4.1",      ALGORITHMS::SHA1_ECDSA     },
    { "1.2.840.10045.4.3.2",    ALGORITHMS::SHA_256_ECDSA  },
    { "1.2.840.10045.4.3.3",    ALGORITHMS::SHA_384_ECDSA  },
    { "1.2.840.10045.4.3.4",    ALGORITHMS::SHA_512_ECDSA  },
  };

  const auto& it = OID_MAP.find(oid.c_str());
  if (it == std::end(OID_MAP)) {
    return ALGORITHMS::UNKNOWN;
  }
  return it->second;
}

}
}
<commit_msg>Use raw pointer instead of std::function<commit_after>/* Copyright 2017 - 2021 R. Thomas
 * Copyright 2017 - 2021 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>
#include <fstream>
#include <iterator>
#include <exception>
#include <string>
#include <numeric>
#include <iomanip>
#include <sstream>
#include <string>

#include "logging.hpp"
#include "mbedtls/md5.h"

#include "LIEF/exception.hpp"

#include "LIEF/PE/utils.hpp"
#include "LIEF/PE/Structures.hpp"
#include "LIEF/PE/Binary.hpp"
#include "LIEF/PE/Import.hpp"
#include "LIEF/PE/ImportEntry.hpp"
#include "LIEF/BinaryStream/VectorStream.hpp"

#include "LIEF/utils.hpp"

#include "utils/ordinals_lookup_tables/libraries_table.hpp"
#include "utils/ordinals_lookup_tables_std/libraries_table.hpp"

#include "hash_stream.hpp"

namespace LIEF {
namespace PE {

inline std::string to_lower(std::string str) {
  std::string lower = str;
  std::transform(std::begin(str), std::end(str),
    std::begin(lower), ::tolower);
  return lower;
}

bool is_pe(const std::string& file) {
  std::ifstream binary(file, std::ios::in | std::ios::binary);
  if (not binary) {
    LIEF_ERR("Unable to open the file!");
    return false;
  }

  uint64_t file_size;
  binary.unsetf(std::ios::skipws);
  binary.seekg(0, std::ios::end);
  file_size = binary.tellg();
  binary.seekg(0, std::ios::beg);

  if (file_size < sizeof(pe_dos_header)) {
    LIEF_ERR("File too small");
    return false;
  }

  char magic[2];
  pe_dos_header dos_header;
  binary.read(magic, sizeof(magic));
  if (magic[0] != 'M' or magic[1] != 'Z') {
    return false;
  }

  binary.seekg(0, std::ios::beg);
  binary.read(reinterpret_cast<char*>(&dos_header), sizeof(pe_dos_header));
  if (dos_header.AddressOfNewExeHeader >= file_size) {
    return false;
  }
  char signature[sizeof(PE_Magic)];
  binary.seekg(dos_header.AddressOfNewExeHeader, std::ios::beg);
  binary.read(signature, sizeof(PE_Magic));
  return std::equal(std::begin(signature), std::end(signature), std::begin(PE_Magic));
}

bool is_pe(const std::vector<uint8_t>& raw) {

  if (raw.size() < sizeof(pe_dos_header)) {
    return false;
  }

  const pe_dos_header* dos_header = reinterpret_cast<const pe_dos_header*>(raw.data());
  if (raw[0] != 'M' or raw[1] != 'Z') {
    return false;
  }

  if ((dos_header->AddressOfNewExeHeader + sizeof(pe_header)) >= raw.size()) {
    return false;
  }

  VectorStream raw_stream(raw);
  raw_stream.setpos(dos_header->AddressOfNewExeHeader);
  auto signature = raw_stream.read_array<char>(sizeof(PE_Magic), /* check bounds */ true);

  return std::equal(signature, signature + sizeof(PE_Magic), std::begin(PE_Magic));
}

PE_TYPE get_type(const std::string& file) {
  if (not is_pe(file)) {
    throw LIEF::bad_format("This file is not a PE binary");
  }

  std::ifstream binary(file, std::ios::in | std::ios::binary);
  if (not binary) {
    throw LIEF::bad_file("Unable to open the file");
  }

  pe_dos_header          dos_header;
  pe32_optional_header   optional_header;
  binary.seekg(0, std::ios::beg);

  binary.read(reinterpret_cast<char*>(&dos_header), sizeof(pe_dos_header));

  binary.seekg(dos_header.AddressOfNewExeHeader + sizeof(pe_header), std::ios::beg);
  binary.read(reinterpret_cast<char*>(&optional_header), sizeof(pe32_optional_header));
  PE_TYPE type = static_cast<PE_TYPE>(optional_header.Magic);

  if (type == PE_TYPE::PE32 or type == PE_TYPE::PE32_PLUS) {
    return type;
  } else {
    throw LIEF::bad_format("This file is not PE32 or PE32+");
  }

}

PE_TYPE get_type(const std::vector<uint8_t>& raw) {
  if (not is_pe(raw)) {
    throw LIEF::bad_format("This file is not a PE binary");
  }

  VectorStream raw_stream = VectorStream(raw);

  const pe_dos_header* dos_header = &raw_stream.read<pe_dos_header>();
  raw_stream.setpos(dos_header->AddressOfNewExeHeader + sizeof(pe_header));
  const pe32_optional_header* optional_header = &raw_stream.read<pe32_optional_header>();

  PE_TYPE type = static_cast<PE_TYPE>(optional_header->Magic);

  if (type == PE_TYPE::PE32 or type == PE_TYPE::PE32_PLUS) {
    return type;
  } else {
    throw LIEF::bad_format("This file is not PE32 or PE32+");
  }

}

std::string get_imphash_std(const Binary& binary) {
  static const std::set<std::string> ALLOWED_EXT = {"dll", "ocx", "sys"};
  std::vector<uint8_t> md5_buffer(16);
  if (not binary.has_imports()) {
    return "";
  }
  std::string lstr;
  bool first_entry = true;
  hashstream hs(hashstream::HASH::MD5);
  for (const Import& imp : binary.imports()) {
    std::string libname = imp.name();

    Import resolved = resolve_ordinals(imp, /* strict */ false, /* use_std */ true);
    size_t ext_idx = resolved.name().find_last_of(".");
    std::string name = resolved.name();
    std::string ext;
    if (ext_idx != std::string::npos) {
      ext = to_lower(resolved.name().substr(ext_idx + 1));
    }
    if (ALLOWED_EXT.find(ext) != std::end(ALLOWED_EXT)) {
      name = name.substr(0, ext_idx);
    }

    std::string entries_string;
    for (const ImportEntry& e : resolved.entries()) {
      std::string funcname;
      if (e.is_ordinal()) {
        funcname = "ord" + std::to_string(e.ordinal());
      } else {
        funcname = e.name();
      }

      if (not entries_string.empty()) {
        entries_string += ",";
      }
      entries_string += name + "." + funcname;
    }
    if (not first_entry) {
      lstr += ",";
    } else {
      first_entry = false;
    }
    lstr += to_lower(entries_string);

    // use write(uint8_t*, size_t) instead of write(const std::string&) to avoid null char
    hs.write(reinterpret_cast<const uint8_t*>(lstr.data()), lstr.size());
    lstr.clear();
  }

  return hex_dump(hs.raw(), "");
}

std::string get_imphash_lief(const Binary& binary) {
  std::vector<uint8_t> md5_buffer(16);
  if (not binary.has_imports()) {
    return std::to_string(0);
  }

  it_const_imports imports = binary.imports();

  std::string import_list;
  for (const Import& imp : imports) {
    Import resolved = resolve_ordinals(imp);
    size_t ext_idx = resolved.name().find_last_of(".");
    std::string name_without_ext = resolved.name();

    if (ext_idx != std::string::npos) {
      name_without_ext = name_without_ext.substr(0, ext_idx);
    }

    std::string entries_string;
    for (const ImportEntry& e : resolved.entries()) {
      if (e.is_ordinal()) {
        entries_string += name_without_ext + ".#" + std::to_string(e.ordinal());
      } else {
        entries_string += name_without_ext + "." + e.name();
      }
    }
    import_list += to_lower(entries_string);
  }

  std::sort(
      std::begin(import_list),
      std::end(import_list),
      std::less<char>());

  mbedtls_md5(
      reinterpret_cast<const uint8_t*>(import_list.data()),
      import_list.size(),
      md5_buffer.data());
  return hex_dump(md5_buffer, "");
}

std::string get_imphash(const Binary& binary, IMPHASH_MODE mode) {
  switch (mode) {
    case IMPHASH_MODE::LIEF:
      {
        return get_imphash_lief(binary);
      }
    case IMPHASH_MODE::PEFILE:
      {
        return get_imphash_std(binary);
      }
  }
  return "";
}

Import resolve_ordinals(const Import& import, bool strict, bool use_std) {
  using ordinal_resolver_t = const char*(*)(uint32_t);

  it_const_import_entries entries = import.entries();

  if (std::all_of(
        std::begin(entries),
        std::end(entries),
        [] (const ImportEntry& entry) {
          return not entry.is_ordinal();
        })) {
    LIEF_DEBUG("All imports use name. No ordinal!");
    return import;
  }

  std::string name = to_lower(import.name());

  ordinal_resolver_t ordinal_resolver = nullptr;
  if (use_std) {
    auto it = imphashstd::ordinals_library_tables.find(name);
    if (it != std::end(imphashstd::ordinals_library_tables)) {
      ordinal_resolver = it->second;
    }
  } else {
    auto it = ordinals_library_tables.find(name);
    if (it != std::end(ordinals_library_tables)) {
      ordinal_resolver = it->second;
    }
  }

  if (ordinal_resolver == nullptr) {
    std::string msg = "Ordinal lookup table for '" + name + "' not implemented";
    if (strict) {
      throw not_found(msg);
    }
    LIEF_DEBUG("{}", msg);
    return import;
  }

  Import resolved_import = import;
  for (ImportEntry& entry : resolved_import.entries()) {
    if (entry.is_ordinal()) {
      LIEF_DEBUG("Dealing with: {}", entry);
      const char* entry_name = ordinal_resolver(static_cast<uint32_t>(entry.ordinal()));
      if (entry_name == nullptr) {
        if (strict) {
          throw not_found("Unable to resolve ordinal: " + std::to_string(entry.ordinal()));
        }
        LIEF_DEBUG("Unable to resolve ordinal: #{:d}", entry.ordinal());
        continue;
      }
      entry.data(0);
      entry.name(entry_name);
    }
  }

  return resolved_import;
}
ALGORITHMS algo_from_oid(const std::string& oid) {
  static const std::unordered_map<std::string, ALGORITHMS> OID_MAP = {
    { "2.16.840.1.101.3.4.2.3", ALGORITHMS::SHA_512 },
    { "2.16.840.1.101.3.4.2.2", ALGORITHMS::SHA_384 },
    { "2.16.840.1.101.3.4.2.1", ALGORITHMS::SHA_256 },
    { "1.3.14.3.2.26",          ALGORITHMS::SHA_1   },

    { "1.2.840.113549.2.5",     ALGORITHMS::MD5 },
    { "1.2.840.113549.2.4",     ALGORITHMS::MD4 },
    { "1.2.840.113549.2.2",     ALGORITHMS::MD2 },

    { "1.2.840.113549.1.1.1",   ALGORITHMS::RSA },
    { "1.2.840.10045.2.1",      ALGORITHMS::EC  },

    { "1.2.840.113549.1.1.4",   ALGORITHMS::MD5_RSA        },
    { "1.2.840.10040.4.3",      ALGORITHMS::SHA1_DSA       },
    { "1.2.840.113549.1.1.5",   ALGORITHMS::SHA1_RSA       },
    { "1.2.840.113549.1.1.11",  ALGORITHMS::SHA_256_RSA    },
    { "1.2.840.113549.1.1.12",  ALGORITHMS::SHA_384_RSA    },
    { "1.2.840.113549.1.1.13",  ALGORITHMS::SHA_512_RSA    },
    { "1.2.840.10045.4.1",      ALGORITHMS::SHA1_ECDSA     },
    { "1.2.840.10045.4.3.2",    ALGORITHMS::SHA_256_ECDSA  },
    { "1.2.840.10045.4.3.3",    ALGORITHMS::SHA_384_ECDSA  },
    { "1.2.840.10045.4.3.4",    ALGORITHMS::SHA_512_ECDSA  },
  };

  const auto& it = OID_MAP.find(oid.c_str());
  if (it == std::end(OID_MAP)) {
    return ALGORITHMS::UNKNOWN;
  }
  return it->second;
}

}
}
<|endoftext|>


<commit_before>#include "Rainback.hpp"

#include <iostream>

#include <functional>
#include <QTextStream>
#include <QApplication>
#include <QPushButton>
#include <QLineEdit>
#include <QTextEdit>
#include <QRegExp>
#include <QFileSystemWatcher>

#include <lua-cxx/LuaValue.hpp>
#include <lua-cxx/loaders.hpp>
#include <lua-cxx/userdata.hpp>
#include <lua-cxx/QObjectObserver.hpp>

#include "LuaPainter.hpp"
#include "LuaFont.hpp"

namespace lua {

template<>
struct UserdataType<QWidget>
{
    constexpr static const char* name = "QWidget";

    static void initialize(LuaStack& stack, QWidget& widget)
    {
        auto userdata = stack.save();
        lua::push(stack, userdata);
        lua::qobject(stack, widget);

        lua::push(stack, lua::value::table);
        auto methods = stack.save();

        methods["resize"] = std::function<void(QWidget&, const int, const int)>(
            [](QWidget& widget, const int w, const int h) {
                widget.resize(w, h);
            }
        );

        methods["setGeometry"] = std::function<void(QWidget&, const int, const int, const int, const int)>(
            [](QWidget& widget, const int x, const int y, const int w, const int h) {
                widget.setGeometry(x, y, w, h);
            }
        );

        methods["__methods"] = methods;

        auto worker = stack.lua()(""
            "return function(userdata, methods)\n"
            "    local mt = getmetatable(userdata);\n"
            ""
            "    local defaultIndex = mt.__index;\n"
            "    function mt.__index(self, key)\n"
            "        return methods[key] or defaultIndex(self, key);\n"
            "    end;\n"
            "end;\n"
        );
        worker(userdata, methods);

        auto observer = new lua::QObjectObserver(&widget, userdata.as<LuaUserdata*>());
        observer->setDestroyOnGC(true);
    }
};

} // namespace lua

std::shared_ptr<LuaFont> newFont(LuaStack& stack)
{
    switch (stack.size()) {
    case 0:
        return std::make_shared<LuaFont>();
    case 1:
        return std::make_shared<LuaFont>(stack.as<QString>(1));
    default:
        return std::make_shared<LuaFont>(
            stack.as<QString>(1),
            stack.as<int>(2)
        );
    }
}

namespace rainback {

void Rainback::assertWidget()
{
    if (!_widget) {
        throw LuaException("This function must not be used when no widget is available");
    }
}

Rainback::Rainback(Lua& lua) :
    _widget(nullptr),
    _lua(lua)
{
    _lua["Rainback"] = lua::value::table;

    _lua["Rainback"]["AddModuleDirectory"] =
    std::function<void(const std::string&, const std::string&)>(
        [this](const std::string& root, const std::string& prefix) {
            auto loader = std::make_shared<DirectoryModuleLoader>();
            loaders.push_back(loader);
            loader->setRoot(QDir(root.c_str()));
            loader->setPrefix(prefix);
            _lua.addModuleLoader(loader.get());
        }
    );

    _lua["Rainback"]["LoadDirectory"] = std::function<void(const std::string&, const bool)>(
        [this](const std::string& path, const bool recurse) {
            lua::load_dir(_lua, QDir(path.c_str()), recurse);
        }
    );

    _lua["Rainback"]["Font"] = newFont;

    _lua["Rainback"]["Button"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QPushButton(_widget), true);
        }
    );

    _lua["Rainback"]["LineEdit"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QLineEdit(_widget), true);
        }
    );

    _lua["Rainback"]["TextEdit"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QTextEdit(_widget), true);
        }
    );

    _lua["Rainback" ]["ScreenWidth"] = std::function<int()>([this]() {
        assertWidget();
        return _widget->width();
    });

    _lua["Rainback" ]["ScreenHeight"] = std::function<int()>([this]() {
        assertWidget();
        return _widget->height();
    });

    _lua["Rainback"]["GetTime"] = std::function<long()>([this]() {
        return elapsed.elapsed();
    });

    _lua["Rainback"]["StartTick"] =
    std::function<std::function<void()>(const int)>([this](const int framerate) {
        timer.start(1000 / framerate);
        return [this]() {
            timer.stop();
        };
    });

    _lua["Rainback"]["GetCursorPosition"] =
    std::function<void(LuaStack&)>([this](LuaStack& stack) {
        assertWidget();
        QPoint pos(_widget->mapFromGlobal(QCursor::pos()));
        stack.clear();
        lua::push(stack, pos.x());
        lua::push(stack, pos.y());
    });

    _lua["Rainback"]["Update"] = std::function<void()>([this]() {
        assertWidget();
        _widget->update();
    });

    _lua["Rainback"]["Close"] = std::function<void()>([this]() {
        assertWidget();
        qApp->closeAllWindows();
    });

    _lua["Rainback"]["SetBackgroundColor"] = std::function<void(const int, const int, const int)>(
        [this](const int r, const int g, const int b) {
            assertWidget();
            _widget->setAutoFillBackground(true);
            QPalette p(_widget->palette());
            p.setColor(QPalette::Background, QColor(r, g, b));
            _widget->setPalette(p);
        }
    );

    _lua["Rainback"]["FileExists"] = std::function<bool(const QString&)>(
        [this](const QString& fileName) {
            return QFile(fileName).exists();
        }
    );

    _lua["Rainback"]["ReadFile"] = std::function<QString(const QString&)>(
        [this](const QString& fileName) {
            QFile file(fileName);
            openFile(file, QIODevice::ReadOnly, true);
            // Using QTextStream here breaks for Unicode strings
            return QString(file.readAll());
        }
    );

    _lua["Rainback"]["ReadCompressedFile"] = std::function<QString(const QString&)>(
        [this](const QString& fileName) {
            QFile file(fileName);
            openFile(file, QIODevice::ReadOnly, true);
            return QString(qUncompress(file.readAll()));
        }
    );

    _lua["Rainback"]["WriteFile"] = std::function<void(const QString&, const QString&)>(
        [this](const QString& fileName, const QString& data) {
            QFile file(fileName);
            openFile(file, QIODevice::WriteOnly | QIODevice::Truncate, false);
            QTextStream(&file) << data;
        }
    );

    _lua["Rainback"]["WriteCompressedFile"] = std::function<void(const QString&, const QString&)>(
        [this](const QString& fileName, const QString& data) {
            QFile file(fileName);
            openFile(file, QIODevice::WriteOnly | QIODevice::Truncate, false);
            file.write(qCompress(data.toUtf8()));
        }
    );

    _lua["Rainback"]["WatchFile"] = std::function<void(LuaStack&)>(
        [this](LuaStack& stack) {
            auto watcher = new QFileSystemWatcher(this);

            for (int i=1; i <= stack.size(); ++i) {
                watcher->addPath(stack.as<QString>(i));
            }
            stack.clear();

            lua::push<QObject*>(stack, watcher, true);
            auto observer = new lua::QObjectObserver(watcher, stack.as<LuaUserdata*>(-1));
            observer->setDestroyOnGC(true);
        }
    );

    _lua["string"]["grep"] = lua::LuaCallable([](LuaStack& stack) {
        auto str = stack.as<QString>(1);
        QRegExp re(stack.as<QString>(2));
        stack.clear();

        if (re.indexIn(str) == -1) {
            return;
        }

        for (int i = 0; i <= re.captureCount(); ++i) {
            lua::push(stack, re.cap(i));
        }
    });

    lua::qvariantPusher(QVariant::Size, [](LuaStack& stack, const QVariant& source) {
        lua::push(stack, lua::value::table);

        auto size = source.toSize();
        stack.set("width", size.width());
        stack.set("height", size.height());
    });

    elapsed.start();

    connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
    connect(qApp, SIGNAL(lastWindowClosed()), this, SLOT(close()));
}

void Rainback::openFile(QFile& file, const QIODevice::OpenMode& flags, const bool checkExists)
{
    if (checkExists && !file.exists()) {
        throw LuaException(
            (QString("The specified file '") + file.fileName() + "' does not exist").toStdString()
        );
    }
    if (!file.open(flags)) {
        throw LuaException(
            (QString("The specified file '") + file.fileName() + "' failed to open: " + file.error()).toStdString()
        );
    }
}

void Rainback::timeout()
{
    rainback::dispatch(_lua, "UPDATE");
}

void Rainback::close()
{
    rainback::dispatch(_lua, "CLOSE");
}

} // namespace rainback

// vim: set ts=4 sw=4 :
<commit_msg>Add unpack if it's not defined already<commit_after>#include "Rainback.hpp"

#include <iostream>

#include <functional>
#include <QTextStream>
#include <QApplication>
#include <QPushButton>
#include <QLineEdit>
#include <QTextEdit>
#include <QRegExp>
#include <QFileSystemWatcher>

#include <lua-cxx/LuaValue.hpp>
#include <lua-cxx/loaders.hpp>
#include <lua-cxx/userdata.hpp>
#include <lua-cxx/QObjectObserver.hpp>

#include "LuaPainter.hpp"
#include "LuaFont.hpp"

namespace lua {

template<>
struct UserdataType<QWidget>
{
    constexpr static const char* name = "QWidget";

    static void initialize(LuaStack& stack, QWidget& widget)
    {
        auto userdata = stack.save();
        lua::push(stack, userdata);
        lua::qobject(stack, widget);

        lua::push(stack, lua::value::table);
        auto methods = stack.save();

        methods["resize"] = std::function<void(QWidget&, const int, const int)>(
            [](QWidget& widget, const int w, const int h) {
                widget.resize(w, h);
            }
        );

        methods["setGeometry"] = std::function<void(QWidget&, const int, const int, const int, const int)>(
            [](QWidget& widget, const int x, const int y, const int w, const int h) {
                widget.setGeometry(x, y, w, h);
            }
        );

        methods["__methods"] = methods;

        auto worker = stack.lua()(""
            "return function(userdata, methods)\n"
            "    local mt = getmetatable(userdata);\n"
            ""
            "    local defaultIndex = mt.__index;\n"
            "    function mt.__index(self, key)\n"
            "        return methods[key] or defaultIndex(self, key);\n"
            "    end;\n"
            "end;\n"
        );
        worker(userdata, methods);

        auto observer = new lua::QObjectObserver(&widget, userdata.as<LuaUserdata*>());
        observer->setDestroyOnGC(true);
    }
};

} // namespace lua

std::shared_ptr<LuaFont> newFont(LuaStack& stack)
{
    switch (stack.size()) {
    case 0:
        return std::make_shared<LuaFont>();
    case 1:
        return std::make_shared<LuaFont>(stack.as<QString>(1));
    default:
        return std::make_shared<LuaFont>(
            stack.as<QString>(1),
            stack.as<int>(2)
        );
    }
}

namespace rainback {

void Rainback::assertWidget()
{
    if (!_widget) {
        throw LuaException("This function must not be used when no widget is available");
    }
}

Rainback::Rainback(Lua& lua) :
    _widget(nullptr),
    _lua(lua)
{
	if (_lua["unpack"].isNil()) {
		_lua["unpack"] = _lua["table"]["unpack"];
	}

    _lua["Rainback"] = lua::value::table;

    _lua["Rainback"]["AddModuleDirectory"] =
    std::function<void(const std::string&, const std::string&)>(
        [this](const std::string& root, const std::string& prefix) {
            auto loader = std::make_shared<DirectoryModuleLoader>();
            loaders.push_back(loader);
            loader->setRoot(QDir(root.c_str()));
            loader->setPrefix(prefix);
            _lua.addModuleLoader(loader.get());
        }
    );

    _lua["Rainback"]["LoadDirectory"] = std::function<void(const std::string&, const bool)>(
        [this](const std::string& path, const bool recurse) {
            lua::load_dir(_lua, QDir(path.c_str()), recurse);
        }
    );

    _lua["Rainback"]["Font"] = newFont;

    _lua["Rainback"]["Button"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QPushButton(_widget), true);
        }
    );

    _lua["Rainback"]["LineEdit"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QLineEdit(_widget), true);
        }
    );

    _lua["Rainback"]["TextEdit"] = lua::LuaCallable([this](LuaStack& stack) {
            assertWidget();
            stack.clear();
            lua::push<QWidget*>(stack, new QTextEdit(_widget), true);
        }
    );

    _lua["Rainback" ]["ScreenWidth"] = std::function<int()>([this]() {
        assertWidget();
        return _widget->width();
    });

    _lua["Rainback" ]["ScreenHeight"] = std::function<int()>([this]() {
        assertWidget();
        return _widget->height();
    });

    _lua["Rainback"]["GetTime"] = std::function<long()>([this]() {
        return elapsed.elapsed();
    });

    _lua["Rainback"]["StartTick"] =
    std::function<std::function<void()>(const int)>([this](const int framerate) {
        timer.start(1000 / framerate);
        return [this]() {
            timer.stop();
        };
    });

    _lua["Rainback"]["GetCursorPosition"] =
    std::function<void(LuaStack&)>([this](LuaStack& stack) {
        assertWidget();
        QPoint pos(_widget->mapFromGlobal(QCursor::pos()));
        stack.clear();
        lua::push(stack, pos.x());
        lua::push(stack, pos.y());
    });

    _lua["Rainback"]["Update"] = std::function<void()>([this]() {
        assertWidget();
        _widget->update();
    });

    _lua["Rainback"]["Close"] = std::function<void()>([this]() {
        assertWidget();
        qApp->closeAllWindows();
    });

    _lua["Rainback"]["SetBackgroundColor"] = std::function<void(const int, const int, const int)>(
        [this](const int r, const int g, const int b) {
            assertWidget();
            _widget->setAutoFillBackground(true);
            QPalette p(_widget->palette());
            p.setColor(QPalette::Background, QColor(r, g, b));
            _widget->setPalette(p);
        }
    );

    _lua["Rainback"]["FileExists"] = std::function<bool(const QString&)>(
        [this](const QString& fileName) {
            return QFile(fileName).exists();
        }
    );

    _lua["Rainback"]["ReadFile"] = std::function<QString(const QString&)>(
        [this](const QString& fileName) {
            QFile file(fileName);
            openFile(file, QIODevice::ReadOnly, true);
            // Using QTextStream here breaks for Unicode strings
            return QString(file.readAll());
        }
    );

    _lua["Rainback"]["ReadCompressedFile"] = std::function<QString(const QString&)>(
        [this](const QString& fileName) {
            QFile file(fileName);
            openFile(file, QIODevice::ReadOnly, true);
            return QString(qUncompress(file.readAll()));
        }
    );

    _lua["Rainback"]["WriteFile"] = std::function<void(const QString&, const QString&)>(
        [this](const QString& fileName, const QString& data) {
            QFile file(fileName);
            openFile(file, QIODevice::WriteOnly | QIODevice::Truncate, false);
            QTextStream(&file) << data;
        }
    );

    _lua["Rainback"]["WriteCompressedFile"] = std::function<void(const QString&, const QString&)>(
        [this](const QString& fileName, const QString& data) {
            QFile file(fileName);
            openFile(file, QIODevice::WriteOnly | QIODevice::Truncate, false);
            file.write(qCompress(data.toUtf8()));
        }
    );

    _lua["Rainback"]["WatchFile"] = std::function<void(LuaStack&)>(
        [this](LuaStack& stack) {
            auto watcher = new QFileSystemWatcher(this);

            for (int i=1; i <= stack.size(); ++i) {
                watcher->addPath(stack.as<QString>(i));
            }
            stack.clear();

            lua::push<QObject*>(stack, watcher, true);
            auto observer = new lua::QObjectObserver(watcher, stack.as<LuaUserdata*>(-1));
            observer->setDestroyOnGC(true);
        }
    );

    _lua["string"]["grep"] = lua::LuaCallable([](LuaStack& stack) {
        auto str = stack.as<QString>(1);
        QRegExp re(stack.as<QString>(2));
        stack.clear();

        if (re.indexIn(str) == -1) {
            return;
        }

        for (int i = 0; i <= re.captureCount(); ++i) {
            lua::push(stack, re.cap(i));
        }
    });

    lua::qvariantPusher(QVariant::Size, [](LuaStack& stack, const QVariant& source) {
        lua::push(stack, lua::value::table);

        auto size = source.toSize();
        stack.set("width", size.width());
        stack.set("height", size.height());
    });

    elapsed.start();

    connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
    connect(qApp, SIGNAL(lastWindowClosed()), this, SLOT(close()));
}

void Rainback::openFile(QFile& file, const QIODevice::OpenMode& flags, const bool checkExists)
{
    if (checkExists && !file.exists()) {
        throw LuaException(
            (QString("The specified file '") + file.fileName() + "' does not exist").toStdString()
        );
    }
    if (!file.open(flags)) {
        throw LuaException(
            (QString("The specified file '") + file.fileName() + "' failed to open: " + file.error()).toStdString()
        );
    }
}

void Rainback::timeout()
{
    rainback::dispatch(_lua, "UPDATE");
}

void Rainback::close()
{
    rainback::dispatch(_lua, "CLOSE");
}

} // namespace rainback

// vim: set ts=4 sw=4 :
<|endoftext|>


<commit_before>///
/// @file  S2Status.cpp
/// @brief Print the status of S2(x, y) in percent.
///        Requires use of --status[=N] command-line flag.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2Status.hpp>
#include <primecount-internal.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;

namespace primecount {

S2Status::S2Status(maxint_t x) :
  old_percent_(-1),
  old_time_(0),
  print_threshold_(0.04),
  precision_(get_status_precision(x))
{
  precision_factor_ = ipow(10, precision_);
}

double S2Status::skewed_percent(maxint_t n, maxint_t limit) const
{
  double exp = 0.96;
  double percent = get_percent((double) n, (double) limit);
  double base = exp + percent / (101 / (1 - exp));
  double min = pow(base, 100.0);
  percent = 100 - in_between(0, 100 * (pow(base, percent) - min) / (1 - min), 100);

  return max(old_percent_, percent);
}

bool S2Status::is_print(double percent, double new_time) const
{
  if (new_time - old_time_ >= print_threshold_)
  {
    int new_percent = (int) (precision_factor_ * percent);
    int old_percent = (int) (precision_factor_ * percent);

    return new_percent > old_percent_;
  }

  return false;
}

void S2Status::print(maxint_t n, maxint_t limit)
{
  double percent = skewed_percent(n, limit);
  double time = get_wtime();

  if (is_print(percent, time))
  {
    ostringstream status;
    ostringstream out;

    status << "\rStatus: " << fixed << setprecision(precision_) << percent << "%";
    string reset_line = string(status.str().length(),' ');
    out << "\r" << reset_line << status.str();
    cout << out.str() << flush;

    #pragma omp critical (s2_status)
    {
      old_percent_ = percent;
      old_time_ = time;
    }
  }
}

void S2Status::print(maxint_t n, maxint_t limit, double rsd)
{
  double percent = skewed_percent(n, limit);
  double time = get_wtime();

  if (is_print(percent, time))
  {
    ostringstream oss;
    ostringstream out;

    int load_balance = (int) in_between(0, 100 - rsd + 0.5, 100);

    oss << "\rStatus: " << fixed << setprecision(precision_) << percent << "%, ";
    oss << "Load balance: " << load_balance << "%";
    string reset_line = string(oss.str().length() + 2,' ');
    out << "\r" << reset_line << oss.str();
    cout << out.str() << flush;

    old_percent_ = percent;
    old_time_ = time;
  }
}

} //namespace
<commit_msg>Fix typo<commit_after>///
/// @file  S2Status.cpp
/// @brief Print the status of S2(x, y) in percent.
///        Requires use of --status[=N] command-line flag.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2Status.hpp>
#include <primecount-internal.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;

namespace primecount {

S2Status::S2Status(maxint_t x) :
  old_percent_(-1),
  old_time_(0),
  print_threshold_(0.04),
  precision_(get_status_precision(x))
{
  precision_factor_ = ipow(10, precision_);
}

double S2Status::skewed_percent(maxint_t n, maxint_t limit) const
{
  double exp = 0.96;
  double percent = get_percent((double) n, (double) limit);
  double base = exp + percent / (101 / (1 - exp));
  double min = pow(base, 100.0);
  percent = 100 - in_between(0, 100 * (pow(base, percent) - min) / (1 - min), 100);

  return max(old_percent_, percent);
}

bool S2Status::is_print(double percent, double new_time) const
{
  if (new_time - old_time_ >= print_threshold_)
  {
    int new_val = (int) (precision_factor_ * percent);
    int old_val = (int) (precision_factor_ * old_percent_);

    return new_val > old_val;
  }

  return false;
}

void S2Status::print(maxint_t n, maxint_t limit)
{
  double percent = skewed_percent(n, limit);
  double time = get_wtime();

  if (is_print(percent, time))
  {
    ostringstream status;
    ostringstream out;

    status << "\rStatus: " << fixed << setprecision(precision_) << percent << "%";
    string reset_line = string(status.str().length(),' ');
    out << "\r" << reset_line << status.str();
    cout << out.str() << flush;

    #pragma omp critical (s2_status)
    {
      old_percent_ = percent;
      old_time_ = time;
    }
  }
}

void S2Status::print(maxint_t n, maxint_t limit, double rsd)
{
  double percent = skewed_percent(n, limit);
  double time = get_wtime();

  if (is_print(percent, time))
  {
    ostringstream oss;
    ostringstream out;

    int load_balance = (int) in_between(0, 100 - rsd + 0.5, 100);

    oss << "\rStatus: " << fixed << setprecision(precision_) << percent << "%, ";
    oss << "Load balance: " << load_balance << "%";
    string reset_line = string(oss.str().length() + 2,' ');
    out << "\r" << reset_line << oss.str();
    cout << out.str() << flush;

    old_percent_ = percent;
    old_time_ = time;
  }
}

} //namespace
<|endoftext|>


<commit_before>/*
 * Triangle.hpp
 *
 *  Created on: 12 Jun 2014
 *      Author: rick
 */

#ifndef TRIANGLE_H
#define TRIANGLE_H

/* fixed recursive includes */
class Triangle;

#include "Vec3D.hpp"
#include "Vertex.hpp"
#include "Texture.hpp"
#include <array>

class Triangle{
public:
	const std::array<Vertex, 3> vertices;
	const std::array<Texture, 3> textures;
	Vec3Df normal;
	inline Triangle() : vertices({ Vertex(0), Vertex(0), Vertex(0) }) {}
   // textures{Texture(0), Texture(0), Texture(0)}, normal(0){};
    inline Triangle(const Triangle & triangle) :
        vertices({triangle.vertices[0], triangle.vertices[1], triangle.vertices[2]}),
        textures({triangle.textures[0], triangle.textures[1], triangle.textures[2]}),
        normal(triangle.normal)
        {};
    inline Triangle(const Vertex & v0, const Vertex & v1, const Vertex & v2,
            const Texture & t0, const Texture & t1, const Texture & t2):
        vertices({v0, v1, v2}),
        textures({t0, t1, t2}),
        normal(calculateNormal(v0, v1, v2))
        {};
    inline Triangle(const Vertex & v0, const Vertex & v1, const Vertex & v2,
		const Texture & t0, const Texture & t1, const Texture & t2, const Vec3Df n) :
		vertices({ v0, v1, v2 }),
		textures({ t0, t1, t2 }),
        normal(n)
        {};
	inline Triangle(const Vertex & v0, const Vertex & v1, const Vertex & v2) :
		vertices({ v0, v1, v2 })
    {};
    inline virtual ~Triangle(){}
//    inline Triangle & operator=(const Triangle & t){
//        return Triangle(
//            t.vertices[0],
//            t.vertices[1],
//            t.vertices[2],
//            t.textures[0],
//            t.textures[1],
//            t.textures[2],
//            t.normal
//        );
//    }
    static inline const Vec3Df calculateNormal(const Vertex& v0, const Vertex& v1, const Vertex& v2){
        Vec3Df normal = Vec3Df::crossProduct(v1.p - v0.p, v2.p - v1.p);
        float length = normal.getLength();
        if(length > 0)
            normal /= normal.getLength();

        return normal;
    }
};

#endif /* TRIANGLE_H */
<commit_msg>reverted triangle fixes<commit_after>/*
 * Triangle.hpp
 *
 *  Created on: 12 Jun 2014
 *      Author: rick
 */

#ifndef TRIANGLE_H
#define TRIANGLE_H

/* fixed recursive includes */
class Triangle;

#include "Vec3D.hpp"
#include "Vertex.hpp"
#include "Texture.hpp"

class Triangle{
public:
    Vertex vertices[3];
    Texture textures[3];
    Vec3Df normal;
    Triangle();
    Triangle(const Triangle & triangle);
    Triangle(const Vertex & v0, const Vertex & v1, const Vertex & v2,
                const Texture & t0, const Texture & t1, const Texture & t2);
    Triangle(const Vertex & v0, const Vertex & v1, const Vertex & v2);
        virtual ~Triangle();
    Triangle & operator=(const Triangle & t2);
    void calculateNormal();
};

#endif /* TRIANGLE_H */
<|endoftext|>