<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: plmodel.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 13:08:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"
#include <plugin/model.hxx>
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif

using namespace com::sun::star::uno;

//==================================================================================================
Reference< XInterface > SAL_CALL PluginModel_CreateInstance( const Reference< ::com::sun::star::lang::XMultiServiceFactory >  & ) throw( Exception )
{
    Reference< XInterface >  xService = *new PluginModel();
    return xService;
}

Any PluginModel::queryAggregation( const Type& type ) throw( RuntimeException )
{
    Any aRet( ::cppu::queryInterface( type,
                                      static_cast< ::com::sun::star::lang::XComponent* >(this),
                                      static_cast< ::com::sun::star::io::XPersistObject* >(this ),
                                      static_cast< ::com::sun::star::awt::XControlModel* >(this),
                                      static_cast< ::com::sun::star::beans::XPropertySet* >(this),
                                      static_cast< ::com::sun::star::beans::XMultiPropertySet* >(this),
                                      static_cast< ::com::sun::star::beans::XFastPropertySet* >(this)
        ) );
    return aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( type );
}

// ::com::sun::star::lang::XServiceInfo
::rtl::OUString PluginModel::getImplementationName() throw()

{
    return getImplementationName_Static();
}

// ::com::sun::star::lang::XServiceInfo
sal_Bool PluginModel::supportsService(const ::rtl::OUString& ServiceName) throw()
{
    Sequence< ::rtl::OUString > aSNL = getSupportedServiceNames();
    const ::rtl::OUString * pArray = aSNL.getConstArray();
    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
        if( pArray[i] == ServiceName )
            return sal_True;
    return sal_False;
}

// ::com::sun::star::lang::XServiceInfo
Sequence< ::rtl::OUString > PluginModel::getSupportedServiceNames(void) throw()
{
    return getSupportedServiceNames_Static();
}

// XPluginManager_Impl
Sequence< ::rtl::OUString > PluginModel::getSupportedServiceNames_Static(void) throw()
{
    Sequence< ::rtl::OUString > aSNS( 1 );
    aSNS.getArray()[0] = ::rtl::OUString::createFromAscii( "com.sun.star.plugin.PluginModel" );
    return aSNS;
}

static const char* aCreationURL = "URL";
static const char* aMime = "TYPE";

static ::osl::Mutex aPropertyMutex;

static ::com::sun::star::beans::Property aProps[] =
{
    ::com::sun::star::beans::Property(
        ::rtl::OUString::createFromAscii( aMime ),
        1,
        ::getCppuType((const ::rtl::OUString*)0),
        ::com::sun::star::beans::PropertyAttribute::BOUND ),
    ::com::sun::star::beans::Property(
        ::rtl::OUString::createFromAscii( aCreationURL ),
        2,
        ::getCppuType((const ::rtl::OUString*)0),
        ::com::sun::star::beans::PropertyAttribute::BOUND )
};

PluginModel::PluginModel() :
        BroadcasterHelperHolder( aPropertyMutex ),
        OPropertySetHelper( m_aHelper ),
        OPropertyArrayHelper( aProps, 2 )
{
}

PluginModel::PluginModel(const ::rtl::OUString& rURL, const rtl::OUString& rMimeType ) :
        BroadcasterHelperHolder( aPropertyMutex ),
        OPropertySetHelper( m_aHelper ),
        OPropertyArrayHelper( aProps, 2 ),
        m_aCreationURL( rURL ),
        m_aMimeType( rMimeType )
{
}

PluginModel::~PluginModel()
{
}

Reference< ::com::sun::star::beans::XPropertySetInfo >  PluginModel::getPropertySetInfo() throw()
{
    static Reference< ::com::sun::star::beans::XPropertySetInfo > aInfo =
        createPropertySetInfo( *this );
    return aInfo;
}

::cppu::IPropertyArrayHelper& PluginModel::getInfoHelper()
{
    return *this;
}

sal_Bool PluginModel::convertFastPropertyValue( Any & rConvertedValue,
                                                Any & rOldValue,
                                                sal_Int32 nHandle,
                                                const Any& rValue ) throw()
{
    if( nHandle == 1 || nHandle == 2 )
    {
        if( rValue.getValueTypeClass() == typelib_TypeClass_STRING )
        {
            rConvertedValue = rValue;
            if( nHandle = 2 )
                rOldValue <<= m_aCreationURL;
            else if( nHandle == 1 )
                rOldValue <<= m_aMimeType;
            return sal_True;
        }
    }
    return sal_False;
}

void PluginModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
                                                    const Any& rValue )
    throw()
{
    if( rValue.getValueTypeClass() == typelib_TypeClass_STRING ) // FIXME wrong type!

    {
        if( nHandle == 2 )
            rValue >>= m_aCreationURL;
        else if( nHandle == 1 )
            rValue >>= m_aMimeType;
    }
    else
        throw ::com::sun::star::lang::IllegalArgumentException();
}

void PluginModel::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const throw()
{
    if( nHandle == 2 )
        rValue <<= m_aCreationURL;
    else if( nHandle == 1 )
        rValue <<= m_aMimeType;
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::addEventListener( const Reference< ::com::sun::star::lang::XEventListener > & l ) throw()
{
    m_aDisposeListeners.push_back( l );
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::removeEventListener( const Reference< ::com::sun::star::lang::XEventListener > & l ) throw()
{
    m_aDisposeListeners.remove( l );
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::dispose(void) throw()
{
    // send disposing events
    ::com::sun::star::lang::EventObject aEvt;
    aEvt.Source = (::cppu::OWeakObject*)this;
    ::std::list< Reference< ::com::sun::star::lang::XEventListener > > aLocalListeners = m_aDisposeListeners;
    for( ::std::list< Reference< ::com::sun::star::lang::XEventListener > >::iterator it = aLocalListeners.begin();
         it != aLocalListeners.end(); ++it )
        (*it)->disposing( aEvt );

    m_aDisposeListeners.clear();

    disposing();
}

// ::com::sun::star::io::XPersistObject
::rtl::OUString PluginModel::getServiceName() throw()
{
    return ::rtl::OUString::createFromAscii( "com.sun.star.plugin.PluginModel" );
}

void PluginModel::write(const Reference< ::com::sun::star::io::XObjectOutputStream > & OutStream) throw()
{
    OutStream->writeUTF( m_aCreationURL );
}

void PluginModel::read(const Reference< ::com::sun::star::io::XObjectInputStream > & InStream) throw()
{
    m_aCreationURL = InStream->readUTF();
}
<commit_msg>INTEGRATION: CWS wae4extensions (1.7.192); FILE MERGED 2007/10/01 10:26:56 fs 1.7.192.2: #i81612# warning-free code (unxlngi6) 2007/09/27 10:20:01 fs 1.7.192.1: #i81612# warning-free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: plmodel.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 14:51:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"
#include <plugin/model.hxx>
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif

using namespace com::sun::star::uno;

//==================================================================================================
Reference< XInterface > SAL_CALL PluginModel_CreateInstance( const Reference< ::com::sun::star::lang::XMultiServiceFactory >  & ) throw( Exception )
{
    Reference< XInterface >  xService = *new PluginModel();
    return xService;
}

Any PluginModel::queryAggregation( const Type& type ) throw( RuntimeException )
{
    Any aRet( ::cppu::queryInterface( type,
                                      static_cast< ::com::sun::star::lang::XComponent* >(this),
                                      static_cast< ::com::sun::star::io::XPersistObject* >(this ),
                                      static_cast< ::com::sun::star::awt::XControlModel* >(this),
                                      static_cast< ::com::sun::star::beans::XPropertySet* >(this),
                                      static_cast< ::com::sun::star::beans::XMultiPropertySet* >(this),
                                      static_cast< ::com::sun::star::beans::XFastPropertySet* >(this)
        ) );
    return aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( type );
}

// ::com::sun::star::lang::XServiceInfo
::rtl::OUString PluginModel::getImplementationName() throw()

{
    return getImplementationName_Static();
}

// ::com::sun::star::lang::XServiceInfo
sal_Bool PluginModel::supportsService(const ::rtl::OUString& ServiceName) throw()
{
    Sequence< ::rtl::OUString > aSNL = getSupportedServiceNames();
    const ::rtl::OUString * pArray = aSNL.getConstArray();
    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
        if( pArray[i] == ServiceName )
            return sal_True;
    return sal_False;
}

// ::com::sun::star::lang::XServiceInfo
Sequence< ::rtl::OUString > PluginModel::getSupportedServiceNames(void) throw()
{
    return getSupportedServiceNames_Static();
}

// XPluginManager_Impl
Sequence< ::rtl::OUString > PluginModel::getSupportedServiceNames_Static(void) throw()
{
    Sequence< ::rtl::OUString > aSNS( 1 );
    aSNS.getArray()[0] = ::rtl::OUString::createFromAscii( "com.sun.star.plugin.PluginModel" );
    return aSNS;
}

static const char* aCreationURL = "URL";
static const char* aMime = "TYPE";

static ::osl::Mutex aPropertyMutex;

static ::com::sun::star::beans::Property aProps[] =
{
    ::com::sun::star::beans::Property(
        ::rtl::OUString::createFromAscii( aMime ),
        1,
        ::getCppuType((const ::rtl::OUString*)0),
        ::com::sun::star::beans::PropertyAttribute::BOUND ),
    ::com::sun::star::beans::Property(
        ::rtl::OUString::createFromAscii( aCreationURL ),
        2,
        ::getCppuType((const ::rtl::OUString*)0),
        ::com::sun::star::beans::PropertyAttribute::BOUND )
};

PluginModel::PluginModel() :
        BroadcasterHelperHolder( aPropertyMutex ),
        OPropertySetHelper( m_aHelper ),
        OPropertyArrayHelper( aProps, 2 )
{
}

PluginModel::PluginModel(const ::rtl::OUString& rURL, const rtl::OUString& rMimeType ) :
        BroadcasterHelperHolder( aPropertyMutex ),
        OPropertySetHelper( m_aHelper ),
        OPropertyArrayHelper( aProps, 2 ),
        m_aCreationURL( rURL ),
        m_aMimeType( rMimeType )
{
}

PluginModel::~PluginModel()
{
}

Reference< ::com::sun::star::beans::XPropertySetInfo >  PluginModel::getPropertySetInfo() throw()
{
    static Reference< ::com::sun::star::beans::XPropertySetInfo > aInfo =
        createPropertySetInfo( *this );
    return aInfo;
}

::cppu::IPropertyArrayHelper& PluginModel::getInfoHelper()
{
    return *this;
}

sal_Bool PluginModel::convertFastPropertyValue( Any & rConvertedValue,
                                                Any & rOldValue,
                                                sal_Int32 nHandle,
                                                const Any& rValue ) throw()
{
    if( nHandle == 1 || nHandle == 2 )
    {
        if( rValue.getValueTypeClass() == TypeClass_STRING )
        {
            rConvertedValue = rValue;
            if( nHandle == 2 )
                rOldValue <<= m_aCreationURL;
            else if( nHandle == 1 )
                rOldValue <<= m_aMimeType;
            return sal_True;
        }
    }
    return sal_False;
}

void PluginModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
                                                    const Any& rValue )
    throw(::com::sun::star::uno::Exception)
{
    if( rValue.getValueTypeClass() == TypeClass_STRING ) // FIXME wrong type!

    {
        if( nHandle == 2 )
            rValue >>= m_aCreationURL;
        else if( nHandle == 1 )
            rValue >>= m_aMimeType;
    }
    else
        throw ::com::sun::star::lang::IllegalArgumentException();
}

void PluginModel::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const throw()
{
    if( nHandle == 2 )
        rValue <<= m_aCreationURL;
    else if( nHandle == 1 )
        rValue <<= m_aMimeType;
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::addEventListener( const Reference< ::com::sun::star::lang::XEventListener > & l ) throw()
{
    m_aDisposeListeners.push_back( l );
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::removeEventListener( const Reference< ::com::sun::star::lang::XEventListener > & l ) throw()
{
    m_aDisposeListeners.remove( l );
}

//---- ::com::sun::star::lang::XComponent ----------------------------------------------------------------------------------
void PluginModel::dispose(void) throw()
{
    // send disposing events
    ::com::sun::star::lang::EventObject aEvt;
    aEvt.Source = (::cppu::OWeakObject*)this;
    ::std::list< Reference< ::com::sun::star::lang::XEventListener > > aLocalListeners = m_aDisposeListeners;
    for( ::std::list< Reference< ::com::sun::star::lang::XEventListener > >::iterator it = aLocalListeners.begin();
         it != aLocalListeners.end(); ++it )
        (*it)->disposing( aEvt );

    m_aDisposeListeners.clear();

    disposing();
}

// ::com::sun::star::io::XPersistObject
::rtl::OUString PluginModel::getServiceName() throw()
{
    return ::rtl::OUString::createFromAscii( "com.sun.star.plugin.PluginModel" );
}

void PluginModel::write(const Reference< ::com::sun::star::io::XObjectOutputStream > & OutStream) throw()
{
    OutStream->writeUTF( m_aCreationURL );
}

void PluginModel::read(const Reference< ::com::sun::star::io::XObjectInputStream > & InStream) throw()
{
    m_aCreationURL = InStream->readUTF();
}
<|endoftext|>


<commit_before>#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <shlwapi.h>
#include <fcntl.h>
#include <ctype.h>
#include <userenv.h>

#include <QMutexLocker>
#include <QScopedPointer>
#include <QList>
#include <QVector>
#include <QDir>
#include <string>

#include "filebrowser/file-browser-requests.h"
#include "filebrowser/sharedlink-dialog.h"
#include "rpc/rpc-client.h"
#include "seafile-applet.h"
#include "account-mgr.h"
#include "ext-handler.h"

namespace {

const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe";
const int kPipeBufSize = 1024;
const char *kRepoRelayAddrProperty = "relay-address";

bool
extPipeReadN (HANDLE pipe, void *buf, size_t len)
{
    DWORD bytes_read;
    bool success = ReadFile(
        pipe,                  // handle to pipe
        buf,                   // buffer to receive data
        (DWORD)len,            // size of buffer
        &bytes_read,           // number of bytes read
        NULL);                 // not overlapped I/O

    if (!success || bytes_read != (DWORD)len) {
        DWORD error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            qDebug("[ext] connection closed by extension\n");
        } else {
            qWarning("[ext] Failed to read command from extension(), "
                     "error code %lu\n", error);
        }
        return false;
    }

    return true;
}

bool
extPipeWriteN(HANDLE pipe, void *buf, size_t len)
{
    DWORD bytes_written;
    bool success = WriteFile(
        pipe,                  // handle to pipe
        buf,                   // buffer to receive data
        (DWORD)len,            // size of buffer
        &bytes_written,        // number of bytes written
        NULL);                 // not overlapped I/O

    if (!success || bytes_written != (DWORD)len) {
        DWORD error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            qDebug("[ext] connection closed by extension\n");
        } else {
            qWarning("[ext] Failed to read command from extension(), "
                     "error code %lu\n", error);
        }
        return false;
    }

    FlushFileBuffers(pipe);
    return true;
}

/**
 * Replace "\" with "/", and remove the trailing slash
 */
QString normalizedPath(const QString& path)
{
    QString p = QDir::fromNativeSeparators(path);
    if (p.endsWith("/")) {
        p = p.left(p.size() - 1);
    }
    return p;
}

std::string formatErrorMessage()
{
    DWORD error_code = ::GetLastError();
    if (error_code == 0) {
        return "no error";
    }
    char buf[256] = {0};
    ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL,
                    error_code,
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                    buf,
                    sizeof(buf) - 1,
                    NULL);
    return buf;
}

} // namespace

SINGLETON_IMPL(SeafileExtensionHandler)

SeafileExtensionHandler::SeafileExtensionHandler()
{
    listener_thread_ = new ExtConnectionListenerThread;

    connect(listener_thread_, SIGNAL(generateShareLink(const QString&, const QString&, bool)),
            this, SLOT(generateShareLink(const QString&, const QString&, bool)));
}

void SeafileExtensionHandler::start()
{
    listener_thread_->start();
}

Account SeafileExtensionHandler::findAccountByRepo(const QString& repo_id)
{
    SeafileRpcClient *rpc = seafApplet->rpcClient();
    if (!accounts_cache_.contains(repo_id)) {
        QString relay_addr;
        if (rpc->getRepoProperty(repo_id, kRepoRelayAddrProperty, &relay_addr) < 0) {
            return Account();
        }
        const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
        for (int i = 0; i < accounts.size(); i++) {
            const Account& account = accounts[i];
            if (account.serverUrl.host() == relay_addr) {
                accounts_cache_[repo_id] = account;
                break;
            }
        }
    }
    return accounts_cache_.value(repo_id, Account());
}

void SeafileExtensionHandler::generateShareLink(const QString& repo_id,
                                                const QString& path_in_repo,
                                                bool is_file)
{
    qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
    const Account account = findAccountByRepo(repo_id);
    if (!account.isValid()) {
        return;
    }

    GetSharedLinkRequest *req = new GetSharedLinkRequest(
        account, repo_id, path_in_repo, is_file);

    connect(req, SIGNAL(success(const QString&)),
            this, SLOT(onShareLinkGenerated(const QString&)));

    req->send();
}

void SeafileExtensionHandler::onShareLinkGenerated(const QString& link)
{
    SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
    dialog->raise();
    dialog->activateWindow();
}

void ExtConnectionListenerThread::run()
{
    while (1) {
        HANDLE pipe = INVALID_HANDLE_VALUE;
        bool connected = false;

        pipe = CreateNamedPipe(
            kSeafExtPipeName,         // pipe name
            PIPE_ACCESS_DUPLEX,       // read/write access
            PIPE_TYPE_MESSAGE |       // message type pipe
            PIPE_READMODE_MESSAGE |   // message-read mode
            PIPE_WAIT,                // blocking mode
            PIPE_UNLIMITED_INSTANCES, // max. instances
            kPipeBufSize,             // output buffer size
            kPipeBufSize,             // input buffer size
            0,                        // client time-out
            NULL);                    // default security attribute

        if (pipe == INVALID_HANDLE_VALUE) {
            qWarning ("Failed to create named pipe, GLE=%lu\n",
                      GetLastError());
            return;
        }

        /* listening on this pipe */
        connected = ConnectNamedPipe(pipe, NULL) ?
            true : (GetLastError() == ERROR_PIPE_CONNECTED);

        if (!connected) {
            qWarning ("Failed on ConnectNamedPipe(), GLE=%lu\n",
                      GetLastError());
            CloseHandle(pipe);
            return;
        }

        qDebug ("[ext pipe] Accepted an extension pipe client\n");
        servePipeInNewThread(pipe);
    }
}

void ExtConnectionListenerThread::servePipeInNewThread(HANDLE pipe)
{
    ExtCommandsHandler *t = new ExtCommandsHandler(pipe);

    connect(t, SIGNAL(generateShareLink(const QString&, const QString&, bool)),
            this, SIGNAL(generateShareLink(const QString&, const QString&, bool)));
    t->start();
}

QMutex ExtCommandsHandler::rpc_mutex_;

ExtCommandsHandler::ExtCommandsHandler(HANDLE pipe)
{
    pipe_ = pipe;
}

void ExtCommandsHandler::run()
{
    rpc_ = new SeafileRpcClient;
    rpc_->connectDaemon();
    while (1) {
        QStringList args;
        if (!readRequest(&args)) {
            qWarning ("failed to read request from shell extension: %s",
                      formatErrorMessage().c_str());
            break;
        }

        QString cmd = args.takeAt(0);
        QString resp;
        if (cmd == "list-repos") {
            resp = handleListRepos(args);
        } else if (cmd == "get-share-link") {
            handleGenShareLink(args);
        } else {
            qWarning ("[ext] unknown request command: %s", cmd.toUtf8().data());
        }

        if (!sendResponse(resp)) {
            qWarning ("failed to write response to shell extension: %s",
                      formatErrorMessage().c_str());
            break;
        }
    }

    qWarning ("An extension client is disconnected: GLE=%lu\n",
              GetLastError());
    DisconnectNamedPipe(pipe_);
    CloseHandle(pipe_);
}

bool ExtCommandsHandler::readRequest(QStringList *args)
{
    uint32_t len;
    if (!extPipeReadN(pipe_, &len, sizeof(len)) || len == 0)
        return false;

    QScopedPointer<char> buf(new char[len + 1]);
    buf.data()[len] = 0;
    if (!extPipeReadN(pipe_, buf.data(), len))
        return false;

    QStringList list = QString::fromUtf8(buf.data()).split('\t', QString::SkipEmptyParts);
    if (list.empty()) {
        qWarning("[ext] got an empty request");
        return false;
    }
    *args = list;
    return true;
}

bool ExtCommandsHandler::sendResponse(const QString& resp)
{
    QByteArray raw_resp = resp.toUtf8();
    uint32_t len = raw_resp.length();

    if (!extPipeWriteN(pipe_, &len, sizeof(len))) {
        return false;
    }
    if (len > 0) {
        if (!extPipeWriteN(pipe_, raw_resp.data(), len)) {
            return false;
        }
    }
    return true;
}

QList<LocalRepo> ExtCommandsHandler::listLocalRepos()
{
    QMutexLocker lock(&rpc_mutex_);

    std::vector<LocalRepo> repos;
    rpc_->listLocalRepos(&repos);
    return QVector<LocalRepo>::fromStdVector(repos).toList();
}

void ExtCommandsHandler::handleGenShareLink(const QStringList& args)
{
    if (args.size() != 1) {
        return;
    }
    QString path = normalizedPath(args[0]);
    foreach (const LocalRepo& repo, listLocalRepos()) {
        QString wt = normalizedPath(repo.worktree);
        qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
        if (path.startsWith(wt)) {
            QString path_in_repo = path.mid(wt.size());
            bool is_file = QFileInfo(path).isFile();
            emit generateShareLink(repo.id, path_in_repo, is_file);
        }
    }
}

QString ExtCommandsHandler::handleListRepos(const QStringList& args)
{
    if (args.size() != 0) {
        return "";
    }
    QStringList infos;
    foreach (const LocalRepo& repo, listLocalRepos()) {
        infos << QString("%1\t%2").arg(repo.id).arg(normalizedPath(repo.worktree));
    }

    return infos.join("\n");
}
<commit_msg>[ext] fixed generating shared link for repos with the same name prefix<commit_after>#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <shlwapi.h>
#include <fcntl.h>
#include <ctype.h>
#include <userenv.h>

#include <QMutexLocker>
#include <QScopedPointer>
#include <QList>
#include <QVector>
#include <QDir>
#include <string>

#include "filebrowser/file-browser-requests.h"
#include "filebrowser/sharedlink-dialog.h"
#include "rpc/rpc-client.h"
#include "seafile-applet.h"
#include "account-mgr.h"
#include "ext-handler.h"

namespace {

const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe";
const int kPipeBufSize = 1024;
const char *kRepoRelayAddrProperty = "relay-address";

bool
extPipeReadN (HANDLE pipe, void *buf, size_t len)
{
    DWORD bytes_read;
    bool success = ReadFile(
        pipe,                  // handle to pipe
        buf,                   // buffer to receive data
        (DWORD)len,            // size of buffer
        &bytes_read,           // number of bytes read
        NULL);                 // not overlapped I/O

    if (!success || bytes_read != (DWORD)len) {
        DWORD error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            qDebug("[ext] connection closed by extension\n");
        } else {
            qWarning("[ext] Failed to read command from extension(), "
                     "error code %lu\n", error);
        }
        return false;
    }

    return true;
}

bool
extPipeWriteN(HANDLE pipe, void *buf, size_t len)
{
    DWORD bytes_written;
    bool success = WriteFile(
        pipe,                  // handle to pipe
        buf,                   // buffer to receive data
        (DWORD)len,            // size of buffer
        &bytes_written,        // number of bytes written
        NULL);                 // not overlapped I/O

    if (!success || bytes_written != (DWORD)len) {
        DWORD error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            qDebug("[ext] connection closed by extension\n");
        } else {
            qWarning("[ext] Failed to read command from extension(), "
                     "error code %lu\n", error);
        }
        return false;
    }

    FlushFileBuffers(pipe);
    return true;
}

/**
 * Replace "\" with "/", and remove the trailing slash
 */
QString normalizedPath(const QString& path)
{
    QString p = QDir::fromNativeSeparators(path);
    if (p.endsWith("/")) {
        p = p.left(p.size() - 1);
    }
    return p;
}

std::string formatErrorMessage()
{
    DWORD error_code = ::GetLastError();
    if (error_code == 0) {
        return "no error";
    }
    char buf[256] = {0};
    ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL,
                    error_code,
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                    buf,
                    sizeof(buf) - 1,
                    NULL);
    return buf;
}

} // namespace

SINGLETON_IMPL(SeafileExtensionHandler)

SeafileExtensionHandler::SeafileExtensionHandler()
{
    listener_thread_ = new ExtConnectionListenerThread;

    connect(listener_thread_, SIGNAL(generateShareLink(const QString&, const QString&, bool)),
            this, SLOT(generateShareLink(const QString&, const QString&, bool)));
}

void SeafileExtensionHandler::start()
{
    listener_thread_->start();
}

Account SeafileExtensionHandler::findAccountByRepo(const QString& repo_id)
{
    SeafileRpcClient *rpc = seafApplet->rpcClient();
    if (!accounts_cache_.contains(repo_id)) {
        QString relay_addr;
        if (rpc->getRepoProperty(repo_id, kRepoRelayAddrProperty, &relay_addr) < 0) {
            return Account();
        }
        const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
        for (int i = 0; i < accounts.size(); i++) {
            const Account& account = accounts[i];
            if (account.serverUrl.host() == relay_addr) {
                accounts_cache_[repo_id] = account;
                break;
            }
        }
    }
    return accounts_cache_.value(repo_id, Account());
}

void SeafileExtensionHandler::generateShareLink(const QString& repo_id,
                                                const QString& path_in_repo,
                                                bool is_file)
{
    qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
    const Account account = findAccountByRepo(repo_id);
    if (!account.isValid()) {
        return;
    }

    GetSharedLinkRequest *req = new GetSharedLinkRequest(
        account, repo_id, path_in_repo, is_file);

    connect(req, SIGNAL(success(const QString&)),
            this, SLOT(onShareLinkGenerated(const QString&)));

    req->send();
}

void SeafileExtensionHandler::onShareLinkGenerated(const QString& link)
{
    SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->show();
    dialog->raise();
    dialog->activateWindow();
}

void ExtConnectionListenerThread::run()
{
    while (1) {
        HANDLE pipe = INVALID_HANDLE_VALUE;
        bool connected = false;

        pipe = CreateNamedPipe(
            kSeafExtPipeName,         // pipe name
            PIPE_ACCESS_DUPLEX,       // read/write access
            PIPE_TYPE_MESSAGE |       // message type pipe
            PIPE_READMODE_MESSAGE |   // message-read mode
            PIPE_WAIT,                // blocking mode
            PIPE_UNLIMITED_INSTANCES, // max. instances
            kPipeBufSize,             // output buffer size
            kPipeBufSize,             // input buffer size
            0,                        // client time-out
            NULL);                    // default security attribute

        if (pipe == INVALID_HANDLE_VALUE) {
            qWarning ("Failed to create named pipe, GLE=%lu\n",
                      GetLastError());
            return;
        }

        /* listening on this pipe */
        connected = ConnectNamedPipe(pipe, NULL) ?
            true : (GetLastError() == ERROR_PIPE_CONNECTED);

        if (!connected) {
            qWarning ("Failed on ConnectNamedPipe(), GLE=%lu\n",
                      GetLastError());
            CloseHandle(pipe);
            return;
        }

        qDebug ("[ext pipe] Accepted an extension pipe client\n");
        servePipeInNewThread(pipe);
    }
}

void ExtConnectionListenerThread::servePipeInNewThread(HANDLE pipe)
{
    ExtCommandsHandler *t = new ExtCommandsHandler(pipe);

    connect(t, SIGNAL(generateShareLink(const QString&, const QString&, bool)),
            this, SIGNAL(generateShareLink(const QString&, const QString&, bool)));
    t->start();
}

QMutex ExtCommandsHandler::rpc_mutex_;

ExtCommandsHandler::ExtCommandsHandler(HANDLE pipe)
{
    pipe_ = pipe;
}

void ExtCommandsHandler::run()
{
    rpc_ = new SeafileRpcClient;
    rpc_->connectDaemon();
    while (1) {
        QStringList args;
        if (!readRequest(&args)) {
            qWarning ("failed to read request from shell extension: %s",
                      formatErrorMessage().c_str());
            break;
        }

        QString cmd = args.takeAt(0);
        QString resp;
        if (cmd == "list-repos") {
            resp = handleListRepos(args);
        } else if (cmd == "get-share-link") {
            handleGenShareLink(args);
        } else {
            qWarning ("[ext] unknown request command: %s", cmd.toUtf8().data());
        }

        if (!sendResponse(resp)) {
            qWarning ("failed to write response to shell extension: %s",
                      formatErrorMessage().c_str());
            break;
        }
    }

    qWarning ("An extension client is disconnected: GLE=%lu\n",
              GetLastError());
    DisconnectNamedPipe(pipe_);
    CloseHandle(pipe_);
}

bool ExtCommandsHandler::readRequest(QStringList *args)
{
    uint32_t len;
    if (!extPipeReadN(pipe_, &len, sizeof(len)) || len == 0)
        return false;

    QScopedPointer<char> buf(new char[len + 1]);
    buf.data()[len] = 0;
    if (!extPipeReadN(pipe_, buf.data(), len))
        return false;

    QStringList list = QString::fromUtf8(buf.data()).split('\t', QString::SkipEmptyParts);
    if (list.empty()) {
        qWarning("[ext] got an empty request");
        return false;
    }
    *args = list;
    return true;
}

bool ExtCommandsHandler::sendResponse(const QString& resp)
{
    QByteArray raw_resp = resp.toUtf8();
    uint32_t len = raw_resp.length();

    if (!extPipeWriteN(pipe_, &len, sizeof(len))) {
        return false;
    }
    if (len > 0) {
        if (!extPipeWriteN(pipe_, raw_resp.data(), len)) {
            return false;
        }
    }
    return true;
}

QList<LocalRepo> ExtCommandsHandler::listLocalRepos()
{
    QMutexLocker lock(&rpc_mutex_);

    std::vector<LocalRepo> repos;
    rpc_->listLocalRepos(&repos);
    return QVector<LocalRepo>::fromStdVector(repos).toList();
}

void ExtCommandsHandler::handleGenShareLink(const QStringList& args)
{
    if (args.size() != 1) {
        return;
    }
    QString path = normalizedPath(args[0]);
    foreach (const LocalRepo& repo, listLocalRepos()) {
        QString wt = normalizedPath(repo.worktree);
        qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
        if (path.length() > wt.length() && path.startsWith(wt) and path.at(wt.length()) == '/') {
            QString path_in_repo = path.mid(wt.size());
            bool is_file = QFileInfo(path).isFile();
            emit generateShareLink(repo.id, path_in_repo, is_file);
            break;
        }
    }
}

QString ExtCommandsHandler::handleListRepos(const QStringList& args)
{
    if (args.size() != 0) {
        return "";
    }
    QStringList infos;
    foreach (const LocalRepo& repo, listLocalRepos()) {
        infos << QString("%1\t%2").arg(repo.id).arg(normalizedPath(repo.worktree));
    }

    return infos.join("\n");
}
<|endoftext|>


<commit_before>#ifndef X_XFT_HPP
#define X_XFT_HPP

#include <iostream>
#include <unordered_map>

#include <X11/Xft/Xft.h>

#include "data_types.hpp"

namespace x {

class xft {
  public:
    xft(Display * dpy, const Drawable & drawable);
    xft(Display * dpy, const Pixmap & pixmap, int depth);
    ~xft(void);

    void
    draw_string_utf8(const std::string & text,
                     const unsigned int & x, const unsigned int & y,
                     const x::type::fontname & fontname,
                     const x::type::colorname & colorname,
                     double alpha = 1.0);

    XGlyphInfo
    text_extents_utf8(const x::type::fontname &, const std::string & text);

    XftColor * const operator[](const x::type::colorname & colorname);

    XftFont * const operator[](const x::type::fontname & fontname);

  private:
    xft(const xft & other);
    xft & operator=(const xft & other);

    XftDraw * m_xftdraw;
    Display * m_dpy;
    Drawable m_drawable;
    Colormap m_colormap;
    XVisualInfo m_visual_info;

    std::unordered_map<std::string, XftColor> m_colors;
    std::unordered_map<std::string, XftFont *> m_fonts;
}; // class xft

}; // namespace x

#endif // X_XFT_HPP
<commit_msg>Delete copy c'tor & assignment operator explicitely<commit_after>#ifndef X_XFT_HPP
#define X_XFT_HPP

#include <iostream>
#include <unordered_map>

#include <X11/Xft/Xft.h>

#include "data_types.hpp"

namespace x {

class xft {
  public:
    xft(Display * dpy, const Drawable & drawable);
    xft(Display * dpy, const Pixmap & pixmap, int depth);
    ~xft(void);

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

    void
    draw_string_utf8(const std::string & text,
                     const unsigned int & x, const unsigned int & y,
                     const x::type::fontname & fontname,
                     const x::type::colorname & colorname,
                     double alpha = 1.0);

    XGlyphInfo
    text_extents_utf8(const x::type::fontname &, const std::string & text);

    XftColor * const operator[](const x::type::colorname & colorname);

    XftFont * const operator[](const x::type::fontname & fontname);

  private:
    xft(const xft & other);
    xft & operator=(const xft & other);

    XftDraw * m_xftdraw;
    Display * m_dpy;
    Drawable m_drawable;
    Colormap m_colormap;
    XVisualInfo m_visual_info;

    std::unordered_map<std::string, XftColor> m_colors;
    std::unordered_map<std::string, XftFont *> m_fonts;
}; // class xft

}; // namespace x

#endif // X_XFT_HPP
<|endoftext|>


<commit_before>#ifndef UTILS_STATE_PTR_HPP
#define UTILS_STATE_PTR_HPP

#include <cassert>
#include <type_traits>
#include <memory>

// Users can change the namespace of `state_ptr`.
// The default namespace is `putl` which stands for "Pointer Utils".
#ifndef UTILS_STATE_PTR_HPP_NAMESPACE
#define UTILS_STATE_PTR_HPP_NAMESPACE putl
#endif

namespace UTILS_STATE_PTR_HPP_NAMESPACE {
	namespace detail {
		/// \brief Returns the logarithm to the power of `2` for the given `number`.
		///
		/// Note: Returns `0` for the special case when `number` is `0`.
		constexpr auto log2(uint64_t number) -> uint64_t {
			uint64_t acc{0};
			while (number > 1) {
				number /= 2;
				acc += 1;
			}
			return acc;
		}

		/// ===================================================================
		///  Tests for the constexpr log2 implementation.
		/// ===================================================================

		static_assert(log2(70) == 6, "");
		static_assert(log2(64) == 6, "");
		static_assert(log2(35) == 5, "");
		static_assert(log2(32) == 5, "");
		static_assert(log2(17) == 4, "");
		static_assert(log2(10) == 3, "");
		static_assert(log2( 4) == 2, "");
		static_assert(log2( 2) == 1, "");
		static_assert(log2( 1) == 0, "");
		static_assert(log2( 0) == 0, ""); // edge case
	}

	template<typename T, class Deleter = std::default_delete<T>>
	class state_ptr {
	public:
		using element_type   = T;
		using pointer_type   = T*;
		using reference_type = typename std::add_lvalue_reference<T>::type;
		using state_type     = uintptr_t;

		static_assert(sizeof(pointer_type) == sizeof(uintptr_t), "");

		constexpr static size_t state_bits = detail::log2(sizeof(T));
		constexpr static size_t ptr_bits   = 8 * sizeof(pointer_type) - state_bits;
		constexpr static size_t threshold  = (1 << state_bits) - 1;

		state_ptr(
			pointer_type ptr,
			state_type   state = 0u
		):
			m_ptr{reinterpret_cast<uintptr_t>(ptr) >> state_bits},
			m_state{state}
		{
			check_invariant();
		}

		void check_invariant() {
			assert(m_state <= threshold);
		}

		void set_state(uintptr_t new_state) {
			assert(new_state <= threshold);
			m_state = new_state;
			check_invariant();
		}

		auto get_state() -> uintptr_t {
			return m_state;
		}

		auto get_ptr() -> pointer_type {
			uintptr_t c = m_ptr;
			return reinterpret_cast<pointer_type>(c << state_bits);
		}

		auto get_ptr() const -> const pointer_type {
			uintptr_t c = m_ptr;
			return reinterpret_cast<pointer_type>(c << state_bits);
		}

		void operator++() {
			++m_ptr;
		}

		void operator++(int) {
			++m_ptr;
		}

		void operator--() {
			--m_ptr;
		}

		void operator--(int) {
			--m_ptr;
		}

		auto operator*() const -> reference_type {
			return *reinterpret_cast<pointer_type>(get_ptr());
		}

		auto operator->() const -> pointer_type {
			return reinterpret_cast<pointer_type>(get_ptr());
		}

		template<typename X> friend bool operator==(state_ptr<X> const& lhs, state_ptr<X> const& rhs);
		template<typename X> friend bool operator!=(state_ptr<X> const& lhs, state_ptr<X> const& rhs);

		template<typename X> friend bool operator<(state_ptr<X> const& lhs, state_ptr<X> const& rhs);

	private:
		uintptr_t m_ptr   : ptr_bits;
		uintptr_t m_state : state_bits;
	};

	template<typename T>
	auto operator==(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return lhs.m_ptr == rhs.m_ptr;
	}

	template<typename T>
	auto operator!=(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return !(lhs == rhs);
	}

	template<typename T>
	auto operator<(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return !(lhs.m_ptr < rhs.m_ptr);
	}

	static_assert(sizeof(state_ptr<uint32_t>) == sizeof(uint32_t*), "");
	static_assert(state_ptr<uint32_t>::state_bits == 2, "");
	static_assert(state_ptr<uint32_t>::ptr_bits == 8 * sizeof(uint32_t*) - state_ptr<uint32_t>::state_bits, "");

	static_assert(sizeof(state_ptr<uint64_t>) == sizeof(uint64_t*), "");
	static_assert(state_ptr<uint64_t>::state_bits == 3, "");
	static_assert(state_ptr<uint64_t>::ptr_bits == 8 * sizeof(uint64_t*) - state_ptr<uint64_t>::state_bits, "");
}

#endif // UTILS_STATE_PTR_HPP
<commit_msg>removed operator++ and operator-- for state_ptr<commit_after>#ifndef UTILS_STATE_PTR_HPP
#define UTILS_STATE_PTR_HPP

#include <cassert>
#include <type_traits>
#include <memory>

// Users can change the namespace of `state_ptr`.
// The default namespace is `putl` which stands for "Pointer Utils".
#ifndef UTILS_STATE_PTR_HPP_NAMESPACE
#define UTILS_STATE_PTR_HPP_NAMESPACE putl
#endif

namespace UTILS_STATE_PTR_HPP_NAMESPACE {
	namespace detail {
		/// \brief Returns the logarithm to the power of `2` for the given `number`.
		///
		/// Note: Returns `0` for the special case when `number` is `0`.
		constexpr auto log2(uint64_t number) -> uint64_t {
			uint64_t acc{0};
			while (number > 1) {
				number /= 2;
				acc += 1;
			}
			return acc;
		}

		/// ===================================================================
		///  Tests for the constexpr log2 implementation.
		/// ===================================================================

		static_assert(log2(70) == 6, "");
		static_assert(log2(64) == 6, "");
		static_assert(log2(35) == 5, "");
		static_assert(log2(32) == 5, "");
		static_assert(log2(17) == 4, "");
		static_assert(log2(10) == 3, "");
		static_assert(log2( 4) == 2, "");
		static_assert(log2( 2) == 1, "");
		static_assert(log2( 1) == 0, "");
		static_assert(log2( 0) == 0, ""); // edge case
	}

	template<typename T, class Deleter = std::default_delete<T>>
	class state_ptr {
	public:
		using element_type   = T;
		using pointer_type   = T*;
		using reference_type = typename std::add_lvalue_reference<T>::type;
		using state_type     = uintptr_t;

		static_assert(sizeof(pointer_type) == sizeof(uintptr_t), "");

		constexpr static size_t state_bits = detail::log2(sizeof(T));
		constexpr static size_t ptr_bits   = 8 * sizeof(pointer_type) - state_bits;
		constexpr static size_t threshold  = (1 << state_bits) - 1;

		state_ptr(
			pointer_type ptr,
			state_type   state = 0u
		):
			m_ptr{reinterpret_cast<uintptr_t>(ptr) >> state_bits},
			m_state{state}
		{
			check_invariant();
		}

		void check_invariant() {
			assert(m_state <= threshold);
		}

		void set_state(uintptr_t new_state) {
			assert(new_state <= threshold);
			m_state = new_state;
			check_invariant();
		}

		auto get_state() -> uintptr_t {
			return m_state;
		}

		auto get_ptr() -> pointer_type {
			uintptr_t c = m_ptr;
			return reinterpret_cast<pointer_type>(c << state_bits);
		}

		auto get_ptr() const -> const pointer_type {
			uintptr_t c = m_ptr;
			return reinterpret_cast<pointer_type>(c << state_bits);
		}

		auto operator*() const -> reference_type {
			return *reinterpret_cast<pointer_type>(get_ptr());
		}

		auto operator->() const -> pointer_type {
			return reinterpret_cast<pointer_type>(get_ptr());
		}

		template<typename X> friend bool operator==(state_ptr<X> const& lhs, state_ptr<X> const& rhs);
		template<typename X> friend bool operator!=(state_ptr<X> const& lhs, state_ptr<X> const& rhs);

		template<typename X> friend bool operator<(state_ptr<X> const& lhs, state_ptr<X> const& rhs);

	private:
		uintptr_t m_ptr   : ptr_bits;
		uintptr_t m_state : state_bits;
	};

	template<typename T>
	auto operator==(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return lhs.m_ptr == rhs.m_ptr;
	}

	template<typename T>
	auto operator!=(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return !(lhs == rhs);
	}

	template<typename T>
	auto operator<(state_ptr<T> const& rhs, state_ptr<T> const& lhs) -> bool {
		return !(lhs.m_ptr < rhs.m_ptr);
	}

	static_assert(sizeof(state_ptr<uint32_t>) == sizeof(uint32_t*), "");
	static_assert(state_ptr<uint32_t>::state_bits == 2, "");
	static_assert(state_ptr<uint32_t>::ptr_bits == 8 * sizeof(uint32_t*) - state_ptr<uint32_t>::state_bits, "");

	static_assert(sizeof(state_ptr<uint64_t>) == sizeof(uint64_t*), "");
	static_assert(state_ptr<uint64_t>::state_bits == 3, "");
	static_assert(state_ptr<uint64_t>::ptr_bits == 8 * sizeof(uint64_t*) - state_ptr<uint64_t>::state_bits, "");
}

#endif // UTILS_STATE_PTR_HPP
<|endoftext|>


<commit_before>#include "app_timbo.hpp"
#include <cossb.hpp>
#include <string>
#include <algorithm>
#include <ext/json.hpp>
#include <base/log.hpp>
#include <base/broker.hpp>
#include <fstream>
#include <vector>
#include <base/task.hpp>
#include <file/collector.hpp>

using namespace std;

#define HEAD		0x55
#define END		0xaa
#define SET		0xf0
#define TRAJ		0x0d
#define RECORD	0x02
#define PLAY		0x03
#define STOP		0x04
#define PING		0x24
#define TRAJECTORY_DUMP	0x37
#define TRAJECTORY_PLAY	0x2e

void app_timbo::key_id_setting(int value){
	unsigned char frame[] = {HEAD, 0x07, SET, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, END};
	memcpy(frame+3, _group_id, sizeof(_group_id));
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	cossb_broker->publish("app_timbo_command", _msg);

}

void app_timbo::key_id_select(int value){

}

void app_timbo::key_send_trajectory(int value){
	unsigned char frame[] = {HEAD, 0x07, 0x0f, TRAJ, 0x00, 0x00, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_record(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, RECORD, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'RECORD' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_play(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, PLAY, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'PLAY' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_stop(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, STOP, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'STOP' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_ping(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, PING, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'PING' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg); //one more
}

void app_timbo::timbo_trajectory_play(int page, int guidebook_id){

	map<int, vector<unsigned char>> trj_map; //[id, trajectory]
	file::collector* trj_files = new file::collector(fmt::format("./contents/{}/", guidebook_id).c_str(), ".trj");

	if(trj_files->getList().empty()){
		cossb_log->log(log::loglevel::ERROR, "There is no trajectory files.");
		return;
	}

	//1. load trajectory data
	for(auto& file : trj_files->getList()){
		size_t pos = file.filename.find(fmt::format("page{}_", page));
		if(pos!=string::npos){
			string str_id = file.filename.substr(pos+6);
			int id = ::stoi(str_id.c_str());
			cossb_log->log(log::loglevel::INFO, fmt::format("[Device ID : {}] Found Trajectory file : {}", id, file.relative));

			ifstream f;
			f.open(file.absolute, ios::in|ios::binary);
			if(f.is_open()){
				f.seekg(0, ios::end);	//set the pointer to the end of file
				int size = f.tellg();
				f.seekg(0, ios::beg);
				unsigned char* data = new unsigned char[size];
				f.read((char*)data, size);
				vector<unsigned char> trjtmp;
				trjtmp.insert(trjtmp.end(), &data[0], &data[size]);
				trj_map[id] = trjtmp;	//insert to map
				delete []data;
				cossb_log->log(log::loglevel::INFO, fmt::format("Loaded Trajectory file : {} ({}) ",file.filename, trjtmp.size()));
			}
			else
				cossb_log->log(log::loglevel::ERROR, fmt::format("Cannot be loaded Trajectory file : {}",file.relative));
			f.close();
		}
	}
	delete trj_files;

	//2. multiple trajectory download..
	for(auto& trj:trj_map){
		unsigned char start[] = {HEAD, 0x06, (unsigned char)trj.first, 0x0c, 0x0, 0x55, 0x7f, 0x01, END}; //start
		string logdata;
		for(auto& c:start)
			logdata += fmt::format("{}\t",(int)c);
		cossb_log->log(log::loglevel::INFO, fmt::format("[{}]{}",trj.first, logdata));
		vector<unsigned char> sdata(start, start+sizeof(start)/sizeof(start[0]));
		cossb::message smsg(this, base::msg_type::DATA);
		smsg.pack(sdata);
		cossb_broker->publish("timbo_write", smsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}

	//send start
	for(auto& trj:trj_map){
		unsigned char header[] = {HEAD, 0x03, (unsigned char)trj.first, 0x2e, 0x00, END};
		vector<unsigned char> hdata(header, header+sizeof(header)/sizeof(header[0]));
		cossb::message hmsg(this, base::msg_type::DATA);
		hmsg.pack(hdata);
		cossb_broker->publish("timbo_write", hmsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}
	cossb_log->log(log::loglevel::INFO, "Now Trajectories downloading..");

	//data downloading...
	const int offset = 20;
	int pos = 0;

	while(1){
		cossb_log->log(log::loglevel::INFO, fmt::format("pos : {}", pos));
		for(auto& trj:trj_map){
			if(pos<(int)trj.second.size()){
				unsigned char trj_pack[] = {HEAD, 0x05, (unsigned char)trj.first, TRAJ, trj.second[pos+2], trj.second[pos+3], 0x00, END};
				string logdata;
				for(auto& c:trj_pack)
					logdata += fmt::format("{}\t",(int)c);
				cossb_log->log(log::loglevel::INFO, fmt::format("[{}]{}",trj.first, logdata));
				cossb::message vmsg(this, base::msg_type::DATA);
				vector<unsigned char> data2(trj_pack, trj_pack+sizeof(trj_pack));
				vmsg.pack(data2);
				cossb_log->log(log::loglevel::INFO, fmt::format("[Device ID : {}] Send Trajectory : {}, {}", trj.first, trj.second[pos+2], trj.second[pos+3]));
				cossb_broker->publish("timbo_write", vmsg);
				//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
				boost::this_thread::sleep(boost::posix_time::milliseconds(100));
			}
			else
				break;

			}
			pos+=offset;
		}

	for(auto& trj:trj_map){
		cossb::message tmsg(this, base::msg_type::DATA);
		unsigned char tail[] = {HEAD, 0x03, (unsigned char)trj.first, 0x04, 0x00, END};
		vector<unsigned char> data3(tail, tail+sizeof(tail));
		tmsg.pack(data3);
		cossb_broker->publish("timbo_write", tmsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}

	cossb_log->log(log::loglevel::INFO, "Trajectory Downloading...Done.");
}

void app_timbo::timbo_trajectory_dump(int page, int guidebook_id) {
	unsigned char frame[] = {HEAD, 0x03, TRAJECTORY_DUMP, 0x00, END};
	vector<unsigned char> packet(frame, frame+sizeof(frame)/sizeof(frame[0]));
	std::tuple<int, int, vector<unsigned char>> data = std::make_tuple(page, guidebook_id, packet);
	cossb::message _msg(this, base::msg_type::REQUEST);
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'TRAJECTORY DUMP' command");
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::ebook_sound_play()
{
	cossb::message msg(this, cossb::base::msg_type::REQUEST);
	nlohmann::json _json_msg;
	_json_msg["command"] = "sound_play";
	msg.pack(_json_msg.dump());
	cossb_broker->publish("websocket_write_msg",msg);
	cossb_log->log(log::loglevel::INFO, "Sound Play on Ebook");
}
<commit_msg>fix trajectory download bug<commit_after>#include "app_timbo.hpp"
#include <cossb.hpp>
#include <string>
#include <algorithm>
#include <ext/json.hpp>
#include <base/log.hpp>
#include <base/broker.hpp>
#include <fstream>
#include <vector>
#include <base/task.hpp>
#include <file/collector.hpp>

using namespace std;

#define HEAD		0x55
#define END		0xaa
#define SET		0xf0
#define TRAJ		0x0d
#define RECORD	0x02
#define PLAY		0x03
#define STOP		0x04
#define PING		0x24
#define TRAJECTORY_DUMP	0x37
#define TRAJECTORY_PLAY	0x2e

void app_timbo::key_id_setting(int value){
	unsigned char frame[] = {HEAD, 0x07, SET, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, END};
	memcpy(frame+3, _group_id, sizeof(_group_id));
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	cossb_broker->publish("app_timbo_command", _msg);

}

void app_timbo::key_id_select(int value){

}

void app_timbo::key_send_trajectory(int value){
	unsigned char frame[] = {HEAD, 0x07, 0x0f, TRAJ, 0x00, 0x00, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_record(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, RECORD, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'RECORD' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_play(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, PLAY, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'PLAY' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_stop(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, STOP, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'STOP' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::timbo_ping(){
	unsigned char frame[] = {HEAD, 0x03, 0x0f, PING, 0x00, END};
	cossb::message _msg(this, base::msg_type::DATA);
	vector<unsigned char> data(frame, frame+sizeof(frame));
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'PING' command");
	cossb_broker->publish("timbo_write", _msg);
	boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	cossb_broker->publish("timbo_write", _msg); //one more
}

void app_timbo::timbo_trajectory_play(int page, int guidebook_id){

	map<int, vector<unsigned char>> trj_map; //[id, trajectory]
	file::collector* trj_files = new file::collector(fmt::format("./contents/{}/", guidebook_id).c_str(), ".trj");

	if(trj_files->getList().empty()){
		cossb_log->log(log::loglevel::ERROR, "There is no trajectory files.");
		return;
	}

	//1. load trajectory data
	for(auto& file : trj_files->getList()){
		size_t pos = file.filename.find(fmt::format("page{}_", page));
		if(pos!=string::npos){
			string str_id = file.filename.substr(pos+6);
			int id = ::stoi(str_id.c_str());
			cossb_log->log(log::loglevel::INFO, fmt::format("[Device ID : {}] Found Trajectory file : {}", id, file.relative));

			ifstream f;
			f.open(file.absolute, ios::in|ios::binary);
			if(f.is_open()){
				f.seekg(0, ios::end);	//set the pointer to the end of file
				int size = f.tellg();
				f.seekg(0, ios::beg);
				unsigned char* data = new unsigned char[size];
				f.read((char*)data, size);
				vector<unsigned char> trjtmp;
				trjtmp.insert(trjtmp.end(), &data[0], &data[size]);
				trj_map[id] = trjtmp;	//insert to map
				delete []data;
				cossb_log->log(log::loglevel::INFO, fmt::format("Loaded Trajectory file : {} ({}) ",file.filename, trjtmp.size()));
			}
			else
				cossb_log->log(log::loglevel::ERROR, fmt::format("Cannot be loaded Trajectory file : {}",file.relative));
			f.close();
		}
	}
	delete trj_files;

	//2. multiple trajectory download..
	for(auto& trj:trj_map){
		unsigned char start[] = {HEAD, 0x06, (unsigned char)trj.first, 0x0c, 0x0, 0x55, 0x7f, 0x01, END}; //start
		string logdata;
		for(auto& c:start)
			logdata += fmt::format("{}\t",(int)c);
		cossb_log->log(log::loglevel::INFO, fmt::format("[{}]{}",trj.first, logdata));
		vector<unsigned char> sdata(start, start+sizeof(start)/sizeof(start[0]));
		cossb::message smsg(this, base::msg_type::DATA);
		smsg.pack(sdata);
		cossb_broker->publish("timbo_write", smsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}

	//send start
	for(auto& trj:trj_map){
		unsigned char header[] = {HEAD, 0x03, (unsigned char)trj.first, 0x2e, 0x00, END};
		vector<unsigned char> hdata(header, header+sizeof(header)/sizeof(header[0]));
		cossb::message hmsg(this, base::msg_type::DATA);
		hmsg.pack(hdata);
		cossb_broker->publish("timbo_write", hmsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}
	cossb_log->log(log::loglevel::INFO, "Now Trajectories downloading..");

	//data downloading...
	const int offset = 20;
	int pos = 0;

	bool done = false;
	while(1){
		//cossb_log->log(log::loglevel::INFO, fmt::format("pos : {}", pos));
		for(auto& trj:trj_map){
			if(pos<(int)trj.second.size()){
				unsigned char trj_pack[] = {HEAD, 0x05, (unsigned char)trj.first, TRAJ, trj.second[pos+2], trj.second[pos+3], 0x00, END};
				string logdata;
				for(auto& c:trj_pack)
					logdata += fmt::format("{}\t",(int)c);
				cossb_log->log(log::loglevel::INFO, fmt::format("[{}]{}",trj.first, logdata));
				cossb::message vmsg(this, base::msg_type::DATA);
				vector<unsigned char> data2(trj_pack, trj_pack+sizeof(trj_pack));
				vmsg.pack(data2);
				cossb_log->log(log::loglevel::INFO, fmt::format("({}) [Device ID : {}] Send Trajectory : {}, {}", pos, trj.first, trj.second[pos+2], trj.second[pos+3]));
				cossb_broker->publish("timbo_write", vmsg);
				//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
				boost::this_thread::sleep(boost::posix_time::milliseconds(100));
			}
			else{
				done = true;
				break;
			}

		}
		if(done)
			break;

		pos+=offset;

	}

	for(auto& trj:trj_map){
		cossb::message tmsg(this, base::msg_type::DATA);
		unsigned char tail[] = {HEAD, 0x03, (unsigned char)trj.first, 0x04, 0x00, END};
		vector<unsigned char> data3(tail, tail+sizeof(tail));
		tmsg.pack(data3);
		cossb_broker->publish("timbo_write", tmsg);
		//boost::this_thread::sleep(boost::posix_time::milliseconds(100/trj_map.size()));
		boost::this_thread::sleep(boost::posix_time::milliseconds(100));
	}

	cossb_log->log(log::loglevel::INFO, "Trajectory Downloading...Done.");
}

void app_timbo::timbo_trajectory_dump(int page, int guidebook_id) {
	unsigned char frame[] = {HEAD, 0x03, TRAJECTORY_DUMP, 0x00, END};
	vector<unsigned char> packet(frame, frame+sizeof(frame)/sizeof(frame[0]));
	std::tuple<int, int, vector<unsigned char>> data = std::make_tuple(page, guidebook_id, packet);
	cossb::message _msg(this, base::msg_type::REQUEST);
	_msg.pack(data);
	cossb_log->log(log::loglevel::INFO, "> Publish 'TRAJECTORY DUMP' command");
	cossb_broker->publish("timbo_write", _msg);
}

void app_timbo::ebook_sound_play()
{
	cossb::message msg(this, cossb::base::msg_type::REQUEST);
	nlohmann::json _json_msg;
	_json_msg["command"] = "sound_play";
	msg.pack(_json_msg.dump());
	cossb_broker->publish("websocket_write_msg",msg);
	cossb_log->log(log::loglevel::INFO, "Sound Play on Ebook");
}
<|endoftext|>


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

#include <cstddef>
#include <memory>
#include <realm/util/features.h>
#include <cstdint>
#include <vector>
#include <realm/util/file.hpp>

#if REALM_ENABLE_ENCRYPTION

#if REALM_PLATFORM_APPLE
#include <CommonCrypto/CommonCrypto.h>
#elif defined(_WIN32)
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#include <openssl/sha.h>
#include <openssl/evp.h>
#pragma GCC diagnostic pop
#endif

namespace realm {
namespace util {

struct iv_table;
class EncryptedFileMapping;

class AESCryptor {
public:
    AESCryptor(const uint8_t* key);
    ~AESCryptor() noexcept;

    void set_file_size(off_t new_size);

    bool read(FileDesc fd, off_t pos, char* dst, size_t size);
    void write(FileDesc fd, off_t pos, const char* src, size_t size) noexcept;

private:
    enum EncryptionMode {
#if REALM_PLATFORM_APPLE
        mode_Encrypt = kCCEncrypt,
        mode_Decrypt = kCCDecrypt
#elif defined(_WIN32)
        mode_Encrypt = 0,
        mode_Decrypt = 1
#else
        mode_Encrypt = 1,
        mode_Decrypt = 0
#endif
    };

#if REALM_PLATFORM_APPLE
    CCCryptorRef m_encr;
    CCCryptorRef m_decr;
#elif defined(_WIN32)
    BCRYPT_KEY_HANDLE m_aes_key_handle;
#else
    uint8_t m_aesKey[32];
    EVP_CIPHER_CTX* m_ctx;
#endif

    uint8_t m_hmacKey[32];
    std::vector<iv_table> m_iv_buffer;
    std::unique_ptr<char[]> m_rw_buffer;
    std::unique_ptr<char[]> m_dst_buffer;

    void calc_hmac(const void* src, size_t len, uint8_t* dst, const uint8_t* key) const;
    bool check_hmac(const void* data, size_t len, const uint8_t* hmac) const;
    void crypt(EncryptionMode mode, off_t pos, char* dst, const char* src, const char* stored_iv) noexcept;
    iv_table& get_iv_table(FileDesc fd, off_t data_pos) noexcept;
    void handle_error();
};

struct ReaderInfo {
    const void* reader_ID;
    uint64_t version;
};

struct SharedFileInfo {
    FileDesc fd;
    AESCryptor cryptor;
    std::vector<EncryptedFileMapping*> mappings;
    uint64_t last_scanned_version = 0;
    uint64_t current_version = 0;
    size_t num_decrypted_pages = 0;
    size_t num_reclaimed_pages = 0;
    size_t progress_index = 0;
    std::vector<ReaderInfo> readers;

    SharedFileInfo(const uint8_t* key, FileDesc file_descriptor);
};
}
}

#endif // REALM_ENABLE_ENCRYPTION
<commit_msg>Revert change to aes_cryptor.hpp<commit_after>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************/

#include <cstddef>
#include <memory>
#include <realm/util/features.h>
#include <cstdint>
#include <vector>
#include <realm/util/file.hpp>

#if REALM_ENABLE_ENCRYPTION

#if REALM_PLATFORM_APPLE
#include <CommonCrypto/CommonCrypto.h>
#elif defined(_WIN32)
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#else
#include <openssl/sha.h>
#include <openssl/evp.h>
#endif

namespace realm {
namespace util {

struct iv_table;
class EncryptedFileMapping;

class AESCryptor {
public:
    AESCryptor(const uint8_t* key);
    ~AESCryptor() noexcept;

    void set_file_size(off_t new_size);

    bool read(FileDesc fd, off_t pos, char* dst, size_t size);
    void write(FileDesc fd, off_t pos, const char* src, size_t size) noexcept;

private:
    enum EncryptionMode {
#if REALM_PLATFORM_APPLE
        mode_Encrypt = kCCEncrypt,
        mode_Decrypt = kCCDecrypt
#elif defined(_WIN32)
        mode_Encrypt = 0,
        mode_Decrypt = 1
#else
        mode_Encrypt = 1,
        mode_Decrypt = 0
#endif
    };

#if REALM_PLATFORM_APPLE
    CCCryptorRef m_encr;
    CCCryptorRef m_decr;
#elif defined(_WIN32)
    BCRYPT_KEY_HANDLE m_aes_key_handle;
#else
    uint8_t m_aesKey[32];
    EVP_CIPHER_CTX* m_ctx;
#endif

    uint8_t m_hmacKey[32];
    std::vector<iv_table> m_iv_buffer;
    std::unique_ptr<char[]> m_rw_buffer;
    std::unique_ptr<char[]> m_dst_buffer;

    void calc_hmac(const void* src, size_t len, uint8_t* dst, const uint8_t* key) const;
    bool check_hmac(const void* data, size_t len, const uint8_t* hmac) const;
    void crypt(EncryptionMode mode, off_t pos, char* dst, const char* src, const char* stored_iv) noexcept;
    iv_table& get_iv_table(FileDesc fd, off_t data_pos) noexcept;
    void handle_error();
};

struct ReaderInfo {
    const void* reader_ID;
    uint64_t version;
};

struct SharedFileInfo {
    FileDesc fd;
    AESCryptor cryptor;
    std::vector<EncryptedFileMapping*> mappings;
    uint64_t last_scanned_version = 0;
    uint64_t current_version = 0;
    size_t num_decrypted_pages = 0;
    size_t num_reclaimed_pages = 0;
    size_t progress_index = 0;
    std::vector<ReaderInfo> readers;

    SharedFileInfo(const uint8_t* key, FileDesc file_descriptor);
};
}
}

#endif // REALM_ENABLE_ENCRYPTION
<|endoftext|>


<commit_before>#include "def_lang/JSON_Serializer.h"
#include "def_lang/ts_assert.h"
#include "def_lang/Result.h"

namespace ts
{
namespace serialization
{

static void to_json(Value const& value, std::string& dst, size_t ident)
{
    switch (value.get_type())
    {
    case Value::Type::BOOL: dst += value.get_as_bool() ? "true" : "false"; break;
    case Value::Type::INT8: dst += std::to_string(value.get_as_int8()); break;
    case Value::Type::UINT8: dst += std::to_string(value.get_as_uint8()); break;
    case Value::Type::INT16: dst += std::to_string(value.get_as_int16()); break;
    case Value::Type::UINT16: dst += std::to_string(value.get_as_uint16()); break;
    case Value::Type::INT32: dst += std::to_string(value.get_as_int32()); break;
    case Value::Type::UINT32: dst += std::to_string(value.get_as_uint32()); break;
    case Value::Type::INT64: dst += std::to_string(value.get_as_int64()); break;
    case Value::Type::UINT64: dst += std::to_string(value.get_as_uint64()); break;
    case Value::Type::FLOAT: dst += std::to_string(value.get_as_float()); break;
    case Value::Type::DOUBLE: dst += std::to_string(value.get_as_double()); break;
    case Value::Type::STRING: dst += "\"" + value.get_as_string() + "\""; break;
    case Value::Type::OBJECT:
    {
        std::string ident_str(ident > 0 ? ident - 1 : ident, '\t');
        std::string member_ident_str(ident, '\t');
        dst += "{\n";
        for (size_t i = 0; i < value.get_object_member_count(); i++)
        {
            dst += member_ident_str;
            dst += "\"";
            dst += value.get_object_member_name(i);
            dst += "\":";
            to_json(value.get_object_member_value(i), dst, ident + 1);
            dst += ",\n";
        }
        dst += ident_str;
        dst += "}";
        break;
    }
    case Value::Type::ARRAY:
    {
        std::string ident_str(ident > 0 ? ident - 1 : ident, '\t');
        std::string element_ident_str(ident, '\t');
        dst += "[\n";
        for (size_t i = 0; i < value.get_array_element_count(); i++)
        {
            dst += element_ident_str;
            to_json(value.get_array_element_value(i), dst, ident + 1);
            dst += ",\n";
        }
        dst += ident_str;
        dst += "]";
        break;
    }
    default: TS_ASSERT(false); break;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////

static size_t skip_whitespace(std::string const& json, size_t offset)
{
    const char* data = json.data() + offset;
    const char* end = data + json.size();
    while (data < end)
    {
        char ch = *data;
        if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r')
        {
            return data - json.data();
        }
        data++;
    }
    return std::string::npos;
}

static Result<std::string> parse_string(std::string const& json, size_t& offset)
{
    if (json[offset] != '"')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing string value");
    }
    offset++;

    char prev_ch = 0;

    const char* data = json.data() + offset;
    const char* start = data;
    const char* end = data + json.size();
    while (data < end)
    {
        char ch = *data;
        if (ch == '"' && prev_ch != '\\')
        {
            offset = data - json.data() + 1;
            return std::string(start, data);
        }
        prev_ch = ch;
        data++;
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_string_value(std::string const& json, size_t& offset)
{
    auto result = parse_string(json, offset);
    if (result != success)
    {
        return result.error();
    }
    return Value(result.extract_payload());
}

static Result<Value> parse_value(std::string const& json, size_t& offset);

static Result<Value> parse_object_value(std::string const& json, size_t& offset)
{
    if (json[offset] != '{')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing object value");
    }
    offset++;

    Value object_value(Value::Type::OBJECT);

    while (true)
    {
        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] == '}')
        {
            offset++;
            return std::move(object_value);
        }

        if (object_value.get_object_member_count() > 0)
        {
            if (json[offset] != ',')
            {
                return Error("Missing ',' while parsing object value");
            }
            offset++;
            //treat the case of stray comma after the last member of an object
            offset = skip_whitespace(json, offset);
            if (offset == std::string::npos)
            {
                return Error("Unexpected end of string");
            }
            if (json[offset] == '}')
            {
                offset++;
                return std::move(object_value);
            }
        }

        auto name_result = parse_string(json, offset);
        if (name_result != success)
        {
            return name_result.error();
        }
        std::string name = name_result.extract_payload();

        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] != ':')
        {
            return Error("Missing ':' while parsing object value");
        }
        offset++;

        auto result = parse_value(json, offset);
        if (result != success)
        {
            return std::move(result);
        }

        object_value.add_object_member(std::move(name), result.extract_payload());
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_array_value(std::string const& json, size_t& offset)
{
    if (json[offset] != '[')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing array value");
    }
    offset++;

    Value array_value(Value::Type::ARRAY);

    while (true)
    {
        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] == ']')
        {
            offset++;
            return std::move(array_value);
        }

        if (array_value.get_array_element_count() > 0)
        {
            if (json[offset] != ',')
            {
                return Error("Missing ',' while parsing array value");
            }
            offset++;

            //handle the case of stray comma after the last element of an array
            offset = skip_whitespace(json, offset);
            if (offset == std::string::npos)
            {
                return Error("Unexpected end of string");
            }

            if (json[offset] == ']')
            {
                offset++;
                return std::move(array_value);
            }
        }

        auto result = parse_value(json, offset);
        if (result != success)
        {
            return std::move(result);
        }

        array_value.add_array_element(result.extract_payload());
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_true_value(std::string const& json, size_t& offset)
{
    if (json.find("true", offset, 4) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 4;
    return Value(true);
}

static Result<Value> parse_false_value(std::string const& json, size_t& offset)
{
    if (json.find("false", offset, 5) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 5;
    return Value(false);
}

static Result<Value> parse_null_value(std::string const& json, size_t& offset)
{
    if (json.find("null", offset, 4) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 4;
    return Value(Value::Type::EMPTY);
}

static Result<Value> parse_number_value(std::string const& json, size_t& offset)
{
    if (offset + 1 >= json.size())
    {
        return Error("Malformed number");
    }

    int64_t sign = 1;
    if (json[offset] == '-')
    {
        sign = -1;
        offset++;
    }

    int64_t whole = 0;
    int64_t decimal = 0;
    uint32_t decimal_digit_count = 0;
    int64_t exponent = 0;
    int32_t exponent_sign = 1;

    const char* data = json.c_str() + offset;
    while (data != 0)
    {
        char ch = *data;
        if (ch < '0' || ch > '9')
        {
            break;
        }
        whole = whole * 10 + (ch - '0');
        data++;
    }

    if (*data == '.')
    {
        data++; //skip the '.'
        while (data != 0)
        {
            char ch = *data;
            if (ch < '0' || ch > '9')
            {
                break;
            }
            decimal = decimal * 10 + (ch - '0');
            decimal_digit_count++;
            data++;
        }
    }
    if (*data == 'e' || *data == 'E')
    {
        data++; //skip the 'e'

        if (*data == '-')
        {
            exponent_sign = -1;
            data++;
        }

        while (data != 0)
        {
            char ch = *data;
            if (ch < '0' || ch > '9')
            {
                break;
            }
            exponent = exponent * 10 + (ch - '0');
            data++;
        }
    }

    offset = data - json.data();

    whole *= sign;

    if (decimal_digit_count == 0)
    {
        static constexpr int64_t s_pow[15] = {
                1,
                10,
                100,
                1000,
                10000,
                100000,
                1000000,
                10000000,
                100000000,
                1000000000,
                10000000000,
                100000000000,
                1000000000000,
                10000000000000,
                100000000000000,
        };

        whole = whole * exponent_sign * s_pow[exponent];
        return Value(whole);
    }

    if (decimal_digit_count > 15)
    {
        return Error("Too many decimals");
    }
    if (exponent > 15)
    {
        return Error("Exponent too big");
    }

    static constexpr double s_pow[15] = { 1.0,
                                          10.0,
                                          100.0,
                                          1000.0,
                                          10000.0,
                                          100000.0,
                                          1000000.0,
                                          10000000.0,
                                          100000000.0,
                                          1000000000.0,
                                          10000000000.0,
                                          100000000000.0,
                                          1000000000000.0,
                                          10000000000000.0,
                                          100000000000000.0,
                                        };

    double value = static_cast<double>(whole);
    value += static_cast<double>(decimal) / s_pow[decimal_digit_count];

    value *= exponent_sign * s_pow[exponent];

    return Value(value);
}

static Result<Value> parse_value(std::string const& json, size_t& offset)
{
    offset = skip_whitespace(json, offset);
    if (offset == std::string::npos)
    {
        return Error("Unexpected end of string");
    }

    char ch = json[offset];
    switch (ch)
    {
    case '"': return parse_string_value(json, offset);
    case '{': return parse_object_value(json, offset);
    case '[': return parse_array_value(json, offset);
    case 't': return parse_true_value(json, offset);
    case 'f': return parse_false_value(json, offset);
    case 'n': return parse_null_value(json, offset);
    default: return parse_number_value(json, offset);
    }
}

/////////////////////////////////////////////////////////////////////////////////////

std::string to_json(Value const& value)
{
    std::string json;
    to_json(value, json, 1);
    return json;
}

Result<Value> from_json(std::string const& json)
{
    size_t offset = 0;
    return parse_value(json, offset);
}

}
}
<commit_msg>Fixed missing EMPTY (null) handler<commit_after>#include "def_lang/JSON_Serializer.h"
#include "def_lang/ts_assert.h"
#include "def_lang/Result.h"

namespace ts
{
namespace serialization
{

static void to_json(Value const& value, std::string& dst, size_t ident)
{
    switch (value.get_type())
    {
    case Value::Type::EMPTY: dst += "null"; break;
    case Value::Type::BOOL: dst += value.get_as_bool() ? "true" : "false"; break;
    case Value::Type::INT8: dst += std::to_string(value.get_as_int8()); break;
    case Value::Type::UINT8: dst += std::to_string(value.get_as_uint8()); break;
    case Value::Type::INT16: dst += std::to_string(value.get_as_int16()); break;
    case Value::Type::UINT16: dst += std::to_string(value.get_as_uint16()); break;
    case Value::Type::INT32: dst += std::to_string(value.get_as_int32()); break;
    case Value::Type::UINT32: dst += std::to_string(value.get_as_uint32()); break;
    case Value::Type::INT64: dst += std::to_string(value.get_as_int64()); break;
    case Value::Type::UINT64: dst += std::to_string(value.get_as_uint64()); break;
    case Value::Type::FLOAT: dst += std::to_string(value.get_as_float()); break;
    case Value::Type::DOUBLE: dst += std::to_string(value.get_as_double()); break;
    case Value::Type::STRING: dst += "\"" + value.get_as_string() + "\""; break;
    case Value::Type::OBJECT:
    {
        std::string ident_str(ident > 0 ? ident - 1 : ident, '\t');
        std::string member_ident_str(ident, '\t');
        dst += "{\n";
        for (size_t i = 0; i < value.get_object_member_count(); i++)
        {
            dst += member_ident_str;
            dst += "\"";
            dst += value.get_object_member_name(i);
            dst += "\":";
            to_json(value.get_object_member_value(i), dst, ident + 1);
            dst += ",\n";
        }
        dst += ident_str;
        dst += "}";
        break;
    }
    case Value::Type::ARRAY:
    {
        std::string ident_str(ident > 0 ? ident - 1 : ident, '\t');
        std::string element_ident_str(ident, '\t');
        dst += "[\n";
        for (size_t i = 0; i < value.get_array_element_count(); i++)
        {
            dst += element_ident_str;
            to_json(value.get_array_element_value(i), dst, ident + 1);
            dst += ",\n";
        }
        dst += ident_str;
        dst += "]";
        break;
    }
    default: TS_ASSERT(false); break;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////

static size_t skip_whitespace(std::string const& json, size_t offset)
{
    const char* data = json.data() + offset;
    const char* end = data + json.size();
    while (data < end)
    {
        char ch = *data;
        if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r')
        {
            return data - json.data();
        }
        data++;
    }
    return std::string::npos;
}

static Result<std::string> parse_string(std::string const& json, size_t& offset)
{
    if (json[offset] != '"')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing string value");
    }
    offset++;

    char prev_ch = 0;

    const char* data = json.data() + offset;
    const char* start = data;
    const char* end = data + json.size();
    while (data < end)
    {
        char ch = *data;
        if (ch == '"' && prev_ch != '\\')
        {
            offset = data - json.data() + 1;
            return std::string(start, data);
        }
        prev_ch = ch;
        data++;
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_string_value(std::string const& json, size_t& offset)
{
    auto result = parse_string(json, offset);
    if (result != success)
    {
        return result.error();
    }
    return Value(result.extract_payload());
}

static Result<Value> parse_value(std::string const& json, size_t& offset);

static Result<Value> parse_object_value(std::string const& json, size_t& offset)
{
    if (json[offset] != '{')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing object value");
    }
    offset++;

    Value object_value(Value::Type::OBJECT);

    while (true)
    {
        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] == '}')
        {
            offset++;
            return std::move(object_value);
        }

        if (object_value.get_object_member_count() > 0)
        {
            if (json[offset] != ',')
            {
                return Error("Missing ',' while parsing object value");
            }
            offset++;
            //treat the case of stray comma after the last member of an object
            offset = skip_whitespace(json, offset);
            if (offset == std::string::npos)
            {
                return Error("Unexpected end of string");
            }
            if (json[offset] == '}')
            {
                offset++;
                return std::move(object_value);
            }
        }

        auto name_result = parse_string(json, offset);
        if (name_result != success)
        {
            return name_result.error();
        }
        std::string name = name_result.extract_payload();

        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] != ':')
        {
            return Error("Missing ':' while parsing object value");
        }
        offset++;

        auto result = parse_value(json, offset);
        if (result != success)
        {
            return std::move(result);
        }

        object_value.add_object_member(std::move(name), result.extract_payload());
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_array_value(std::string const& json, size_t& offset)
{
    if (json[offset] != '[')
    {
        return Error("Unexpected char '" + std::to_string(json[offset]) + "' while parsing array value");
    }
    offset++;

    Value array_value(Value::Type::ARRAY);

    while (true)
    {
        offset = skip_whitespace(json, offset);
        if (offset == std::string::npos)
        {
            return Error("Unexpected end of string");
        }

        if (json[offset] == ']')
        {
            offset++;
            return std::move(array_value);
        }

        if (array_value.get_array_element_count() > 0)
        {
            if (json[offset] != ',')
            {
                return Error("Missing ',' while parsing array value");
            }
            offset++;

            //handle the case of stray comma after the last element of an array
            offset = skip_whitespace(json, offset);
            if (offset == std::string::npos)
            {
                return Error("Unexpected end of string");
            }

            if (json[offset] == ']')
            {
                offset++;
                return std::move(array_value);
            }
        }

        auto result = parse_value(json, offset);
        if (result != success)
        {
            return std::move(result);
        }

        array_value.add_array_element(result.extract_payload());
    }

    return Error("Unexpected end of string");
}

static Result<Value> parse_true_value(std::string const& json, size_t& offset)
{
    if (json.find("true", offset, 4) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 4;
    return Value(true);
}

static Result<Value> parse_false_value(std::string const& json, size_t& offset)
{
    if (json.find("false", offset, 5) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 5;
    return Value(false);
}

static Result<Value> parse_null_value(std::string const& json, size_t& offset)
{
    if (json.find("null", offset, 4) != offset)
    {
        return Error("Unexpected value");
    }
    offset += 4;
    return Value(Value::Type::EMPTY);
}

static Result<Value> parse_number_value(std::string const& json, size_t& offset)
{
    if (offset + 1 >= json.size())
    {
        return Error("Malformed number");
    }

    int64_t sign = 1;
    if (json[offset] == '-')
    {
        sign = -1;
        offset++;
    }

    int64_t whole = 0;
    int64_t decimal = 0;
    uint32_t decimal_digit_count = 0;
    int64_t exponent = 0;
    int32_t exponent_sign = 1;

    const char* data = json.c_str() + offset;
    while (data != 0)
    {
        char ch = *data;
        if (ch < '0' || ch > '9')
        {
            break;
        }
        whole = whole * 10 + (ch - '0');
        data++;
    }

    if (*data == '.')
    {
        data++; //skip the '.'
        while (data != 0)
        {
            char ch = *data;
            if (ch < '0' || ch > '9')
            {
                break;
            }
            decimal = decimal * 10 + (ch - '0');
            decimal_digit_count++;
            data++;
        }
    }
    if (*data == 'e' || *data == 'E')
    {
        data++; //skip the 'e'

        if (*data == '-')
        {
            exponent_sign = -1;
            data++;
        }

        while (data != 0)
        {
            char ch = *data;
            if (ch < '0' || ch > '9')
            {
                break;
            }
            exponent = exponent * 10 + (ch - '0');
            data++;
        }
    }

    offset = data - json.data();

    whole *= sign;

    if (decimal_digit_count == 0)
    {
        static constexpr int64_t s_pow[15] = {
                1,
                10,
                100,
                1000,
                10000,
                100000,
                1000000,
                10000000,
                100000000,
                1000000000,
                10000000000,
                100000000000,
                1000000000000,
                10000000000000,
                100000000000000,
        };

        whole = whole * exponent_sign * s_pow[exponent];
        return Value(whole);
    }

    if (decimal_digit_count > 15)
    {
        return Error("Too many decimals");
    }
    if (exponent > 15)
    {
        return Error("Exponent too big");
    }

    static constexpr double s_pow[15] = { 1.0,
                                          10.0,
                                          100.0,
                                          1000.0,
                                          10000.0,
                                          100000.0,
                                          1000000.0,
                                          10000000.0,
                                          100000000.0,
                                          1000000000.0,
                                          10000000000.0,
                                          100000000000.0,
                                          1000000000000.0,
                                          10000000000000.0,
                                          100000000000000.0,
                                        };

    double value = static_cast<double>(whole);
    value += static_cast<double>(decimal) / s_pow[decimal_digit_count];

    value *= exponent_sign * s_pow[exponent];

    return Value(value);
}

static Result<Value> parse_value(std::string const& json, size_t& offset)
{
    offset = skip_whitespace(json, offset);
    if (offset == std::string::npos)
    {
        return Error("Unexpected end of string");
    }

    char ch = json[offset];
    switch (ch)
    {
    case '"': return parse_string_value(json, offset);
    case '{': return parse_object_value(json, offset);
    case '[': return parse_array_value(json, offset);
    case 't': return parse_true_value(json, offset);
    case 'f': return parse_false_value(json, offset);
    case 'n': return parse_null_value(json, offset);
    default: return parse_number_value(json, offset);
    }
}

/////////////////////////////////////////////////////////////////////////////////////

std::string to_json(Value const& value)
{
    std::string json;
    to_json(value, json, 1);
    return json;
}

Result<Value> from_json(std::string const& json)
{
    size_t offset = 0;
    return parse_value(json, offset);
}

}
}
<|endoftext|>


<commit_before><commit_msg>Added VertexType link test<commit_after><|endoftext|>