<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/verifycommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "verifycommand.h"

#include <QFile>
#include <QObject>
#include <QIODevice>
#include <QMessageBox>

#include <kleo/verifyopaquejob.h>
#include <kleo/verifydetachedjob.h>
#include <kleo/cryptobackendfactory.h>

#include <gpgme++/error.h>
#include <gpgme++/verificationresult.h>

#include <gpg-error.h>

#include <cassert>

#include <boost/bind.hpp>

using namespace Kleo;
namespace {

    struct VerifyException : public std::exception {
        VerifyException( const char* _text )
        :text(_text)
        {}
        virtual ~VerifyException() throw() {}
        const QByteArray text;
    };
}

class VerifyCommand::Private : public QObject
{
    Q_OBJECT
public:
    Private( VerifyCommand * qq )
        :q( qq ), backend(0), showDetails(false)
    {}

    VerifyCommand *q;
    const CryptoBackend::Protocol *backend;
    bool showDetails;

    void findCryptoBackend();

    struct Input
    {
        Input() : type( Detached ), message( 0 ), signature( 0 ) {}
        enum SignatureType {
            Detached=0,
            Opaque
        };

        SignatureType type;
        QIODevice* message;
        QString messageFileName;
        QIODevice* signature;
    };

    QList<Input> inputList;
    QList<Input> setupInput( GpgME::Error& error, QString& errorDetails ) const;

public Q_SLOTS:
    void slotVerifyOpaqueResult(const GpgME::VerificationResult &, const QByteArray &);
    void slotVerifyDetachedResult(const GpgME::VerificationResult &);
    void slotProgress( const QString& what, int current, int total );
    void parseCommandLine( const std::string & line );
private:
    void sendBriefResult( const GpgME::VerificationResult & result ) const;
};

VerifyCommand::VerifyCommand()
    : AssuanCommandMixin<VerifyCommand>(),
      d( new Private( this ) )
{
}

VerifyCommand::~VerifyCommand() {}

void VerifyCommand::Private::findCryptoBackend()
{
    // FIXME this could be either SMIME or OpenPGP, find out from headers
    const bool isSMIME = true;
    if ( isSMIME )
        backend = Kleo::CryptoBackendFactory::instance()->smime();
    else
        backend = Kleo::CryptoBackendFactory::instance()->openpgp();
}

QList<VerifyCommand::Private::Input> VerifyCommand::Private::setupInput( GpgME::Error& error, QString& errorDetails ) const
{
    error = GpgME::Error();
    errorDetails = QString();

    const int numSignatures = q->numBulkInputDevices( "INPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    if ( numSignatures == 0 )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT );
        errorDetails = "At least one signature must be provided";
        return QList<Input>();
    }

    if ( numMessages > 0 && numMessages != numSignatures )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "The number of MESSAGE inputs must be either equal to the number of signatures or zero";
        return QList<Input>();
    }

    QList<Input> inputs;

    if ( numMessages == numSignatures )
    {
        for ( int i = 0; i < numSignatures; ++i )
        {
            Input input;
            input.type = Input::Detached;
            input.signature = q->bulkInputDevice( "INPUT", i );
            input.message = q->bulkInputDevice( "MESSAGE", i );
            assert( input.signature );
            assert( input.message );
            inputs.append( input );
        }
        return inputs;
    }

    assert( numMessages == 0 );

    for ( int i = 0; i < numSignatures; ++i )
    {
        Input input;
        input.signature = q->bulkInputDevice( "INPUT", i );
        assert( input.signature );
        const QString fname = q->bulkInputDeviceFileName( "INPUT", i );
        if ( !fname.isEmpty() && fname.endsWith( ".sig", Qt::CaseInsensitive )
                || fname.endsWith( ".asc", Qt::CaseInsensitive ) )
        { //detached signature file
            const QString msgFileName = fname.left( fname.length() - 4 );
            // TODO: handle error if msg file does not exist
            input.type = Input::Detached;
            input.messageFileName = msgFileName;
        }
        else // opaque
        {
            input.type = Input::Opaque;
        }
        inputs.append( input );
    }
    return inputs;
}

void VerifyCommand::Private::sendBriefResult( const GpgME::VerificationResult & result ) const
{
    // handle errors
}

void VerifyCommand::Private::slotVerifyOpaqueResult( const GpgME::VerificationResult & result ,
                                                     const QByteArray & stuff )
{
    sendBriefResult( result );
    if (!showDetails) {
        q->done();
        return;
    }

    q->done();
}

void VerifyCommand::Private::slotVerifyDetachedResult( const GpgME::VerificationResult & result )
{
    sendBriefResult( result );
    if (!showDetails) {
        q->done();
        return;
    }
    q->done();
}

void VerifyCommand::Private::slotProgress( const QString& what, int current, int total )
{
    // FIXME report progress, via sendStatus()
}

void VerifyCommand::Private::parseCommandLine( const std::string & line )
{
    // FIXME robustify, extract
    QList<QByteArray> tokens = QByteArray( line.c_str() ).split( ' ' );
    tokens.erase( std::remove_if( tokens.begin(), tokens.end(),
                                  bind( &QByteArray::isEmpty, _1 ) ),
                  tokens.end() );
    showDetails = !tokens.contains( "--silent" );

}

int VerifyCommand::start( const std::string & line )
{
    d->parseCommandLine(line);

    {
        GpgME::Error error;
        QString details;
        d->inputList = d->setupInput( error, details );
        if ( error )
        {
            done( error, details );
            return error;
        }
    }

    // FIXME check options

    d->findCryptoBackend(); // decide on smime or openpgp
    assert(d->backend);

    assert( !d->inputList.isEmpty() );

    const Private::Input input = d->inputList.first();

    if ( input.type == Private::Input::Opaque )
    {
        //fire off appropriate kleo verification job
        VerifyOpaqueJob * const job = d->backend->verifyOpaqueJob();
        assert(job);
        QObject::connect( job, SIGNAL(result(GpgME::VerificationResult,QByteArray)),
                        d.get(),  SLOT(slotVerifyOpaqueResult(GpgME::VerificationResult,QByteArray)) );
        QObject::connect( job, SIGNAL(progress(QString,int,int)),
                        d.get(), SLOT(slotProgress(QString,int,int)) );

        //FIXME: readAll() save enough?
        const GpgME::Error error = job->start( input.signature->readAll() );
        if ( error )
            done( error );
        return error;
    }
    else
    {
        //fire off appropriate kleo verification job
        VerifyDetachedJob * const job = d->backend->verifyDetachedJob();
        assert(job);
        QObject::connect( job, SIGNAL(result(GpgME::VerificationResult)),
                        d.get(),  SLOT(slotVerifyDetachedResult(GpgME::VerificationResult)) );
        QObject::connect( job, SIGNAL(progress(QString,int,int)),
                        d.get(), SLOT(slotProgress(QString,int,int)) );

        //FIXME: readAll save enough
        const QByteArray signature = input.signature->readAll();
        QByteArray message;
        if ( input.message )
        {
            message = input.message->readAll();
        }
        else
        {
            QFile file( input.messageFileName );
            if ( !file.open( QIODevice::ReadOnly ) )
            {
                done( GPG_ERR_ASS_NO_INPUT, QString( "Couldn't read file %1" ).arg( input.messageFileName ) ); // FIXME: use better error code
                return GPG_ERR_ASS_NO_INPUT;
            }
            message = file.readAll();
            file.close();
        }
        const GpgME::Error error = job->start( signature, message );
        if ( error )
            done( error );
        return error;
    }

    assert( false );
    return 0; // never reached
}

void VerifyCommand::canceled()
{
}

#include "verifycommand.moc"
<commit_msg>Start processing signatures.<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/verifycommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "verifycommand.h"

#include <QFile>
#include <QObject>
#include <QIODevice>
#include <QMessageBox>

#include <kleo/verifyopaquejob.h>
#include <kleo/verifydetachedjob.h>
#include <kleo/cryptobackendfactory.h>

#include <gpgme++/error.h>
#include <gpgme++/verificationresult.h>

#include <gpg-error.h>

#include <cassert>

#include <boost/bind.hpp>

using namespace Kleo;
namespace {

    struct VerifyException : public std::exception {
        VerifyException( const char* _text )
        :text(_text)
        {}
        virtual ~VerifyException() throw() {}
        const QByteArray text;
    };
}

class VerifyCommand::Private : public QObject
{
    Q_OBJECT
public:
    Private( VerifyCommand * qq )
        :q( qq ), backend(0), showDetails(false)
    {}

    VerifyCommand *q;
    const CryptoBackend::Protocol *backend;
    bool showDetails;

    void findCryptoBackend();

    struct Input
    {
        Input() : type( Detached ), message( 0 ), signature( 0 ) {}
        enum SignatureType {
            Detached=0,
            Opaque
        };

        SignatureType type;
        QIODevice* message;
        QString messageFileName;
        QIODevice* signature;
    };

    QList<Input> inputList;
    QList<Input> setupInput( GpgME::Error& error, QString& errorDetails ) const;

public Q_SLOTS:
    void slotVerifyOpaqueResult(const GpgME::VerificationResult &, const QByteArray &);
    void slotVerifyDetachedResult(const GpgME::VerificationResult &);
    void slotProgress( const QString& what, int current, int total );
    void parseCommandLine( const std::string & line );
private:
    void sendBriefResult( const GpgME::VerificationResult & result ) const;
    void processSignature( const GpgME::Signature& sig ) const;
};

VerifyCommand::VerifyCommand()
    : AssuanCommandMixin<VerifyCommand>(),
      d( new Private( this ) )
{
}

VerifyCommand::~VerifyCommand() {}

void VerifyCommand::Private::findCryptoBackend()
{
    // FIXME this could be either SMIME or OpenPGP, find out from headers
    const bool isSMIME = true;
    if ( isSMIME )
        backend = Kleo::CryptoBackendFactory::instance()->smime();
    else
        backend = Kleo::CryptoBackendFactory::instance()->openpgp();
}

QList<VerifyCommand::Private::Input> VerifyCommand::Private::setupInput( GpgME::Error& error, QString& errorDetails ) const
{
    error = GpgME::Error();
    errorDetails = QString();

    const int numSignatures = q->numBulkInputDevices( "INPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    if ( numSignatures == 0 )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT );
        errorDetails = "At least one signature must be provided";
        return QList<Input>();
    }

    if ( numMessages > 0 && numMessages != numSignatures )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "The number of MESSAGE inputs must be either equal to the number of signatures or zero";
        return QList<Input>();
    }

    QList<Input> inputs;

    if ( numMessages == numSignatures )
    {
        for ( int i = 0; i < numSignatures; ++i )
        {
            Input input;
            input.type = Input::Detached;
            input.signature = q->bulkInputDevice( "INPUT", i );
            input.message = q->bulkInputDevice( "MESSAGE", i );
            assert( input.signature );
            assert( input.message );
            inputs.append( input );
        }
        return inputs;
    }

    assert( numMessages == 0 );

    for ( int i = 0; i < numSignatures; ++i )
    {
        Input input;
        input.signature = q->bulkInputDevice( "INPUT", i );
        assert( input.signature );
        const QString fname = q->bulkInputDeviceFileName( "INPUT", i );
        if ( !fname.isEmpty() && fname.endsWith( ".sig", Qt::CaseInsensitive )
                || fname.endsWith( ".asc", Qt::CaseInsensitive ) )
        { //detached signature file
            const QString msgFileName = fname.left( fname.length() - 4 );
            // TODO: handle error if msg file does not exist
            input.type = Input::Detached;
            input.messageFileName = msgFileName;
        }
        else // opaque
        {
            input.type = Input::Opaque;
        }
        inputs.append( input );
    }
    return inputs;
}

void VerifyCommand::Private::processSignature( const GpgME::Signature& sig ) const
{
    if ( sig.isNull() ) {
        q->sendStatus("null sig", "");
        q->done( makeError(GPG_ERR_GENERAL) );
        return;
    }

    QString data = QString::number( sig.summary() );
    if ( const int err = q->sendStatus( "VERIFY", data ) )
        q->done( err );
}

void VerifyCommand::Private::sendBriefResult( const GpgME::VerificationResult & result ) const
{
    if ( result.isNull() ) {
        q->sendStatus("no result", "");
        q->done( makeError(GPG_ERR_GENERAL) );
        return;
    }
    std::vector<GpgME::Signature> sigs = result.signatures();
    if ( sigs.size() == 0 ) {
        q->sendStatus("no sigs", "");
        q->done( makeError(GPG_ERR_GENERAL) );
        return;
    }

    Q_FOREACH( GpgME::Signature sig, sigs )
        processSignature( sig );
}

void VerifyCommand::Private::slotVerifyOpaqueResult( const GpgME::VerificationResult & result ,
                                                     const QByteArray & stuff )
{
    sendBriefResult( result );
    if (!showDetails) {
        q->done();
        return;
    }

    q->done();
}

void VerifyCommand::Private::slotVerifyDetachedResult( const GpgME::VerificationResult & result )
{
    sendBriefResult( result );
    if (!showDetails) {
        q->done();
        return;
    }
    q->done();
}

void VerifyCommand::Private::slotProgress( const QString& what, int current, int total )
{
    // FIXME report progress, via sendStatus()
}

void VerifyCommand::Private::parseCommandLine( const std::string & line )
{
    // FIXME robustify, extract
    QList<QByteArray> tokens = QByteArray( line.c_str() ).split( ' ' );
    tokens.erase( std::remove_if( tokens.begin(), tokens.end(),
                                  bind( &QByteArray::isEmpty, _1 ) ),
                  tokens.end() );
    showDetails = !tokens.contains( "--silent" );

}

int VerifyCommand::start( const std::string & line )
{
    d->parseCommandLine(line);

    {
        GpgME::Error error;
        QString details;
        d->inputList = d->setupInput( error, details );
        if ( error )
        {
            done( error, details );
            return error;
        }
    }

    // FIXME check options

    d->findCryptoBackend(); // decide on smime or openpgp
    assert(d->backend);

    assert( !d->inputList.isEmpty() );

    const Private::Input input = d->inputList.first();

    if ( input.type == Private::Input::Opaque )
    {
        //fire off appropriate kleo verification job
        VerifyOpaqueJob * const job = d->backend->verifyOpaqueJob();
        assert(job);
        QObject::connect( job, SIGNAL(result(GpgME::VerificationResult,QByteArray)),
                        d.get(),  SLOT(slotVerifyOpaqueResult(GpgME::VerificationResult,QByteArray)) );
        QObject::connect( job, SIGNAL(progress(QString,int,int)),
                        d.get(), SLOT(slotProgress(QString,int,int)) );

        //FIXME: readAll() save enough?
        const GpgME::Error error = job->start( input.signature->readAll() );
        if ( error )
            done( error );
        return error;
    }
    else
    {
        //fire off appropriate kleo verification job
        VerifyDetachedJob * const job = d->backend->verifyDetachedJob();
        assert(job);
        QObject::connect( job, SIGNAL(result(GpgME::VerificationResult)),
                        d.get(),  SLOT(slotVerifyDetachedResult(GpgME::VerificationResult)) );
        QObject::connect( job, SIGNAL(progress(QString,int,int)),
                        d.get(), SLOT(slotProgress(QString,int,int)) );

        //FIXME: readAll save enough
        const QByteArray signature = input.signature->readAll();
        QByteArray message;
        if ( input.message )
        {
            message = input.message->readAll();
        }
        else
        {
            QFile file( input.messageFileName );
            if ( !file.open( QIODevice::ReadOnly ) )
            {
                done( GPG_ERR_ASS_NO_INPUT, QString( "Couldn't read file %1" ).arg( input.messageFileName ) ); // FIXME: use better error code
                return GPG_ERR_ASS_NO_INPUT;
            }
            message = file.readAll();
            file.close();
        }
        const GpgME::Error error = job->start( signature, message );
        if ( error )
            done( error );
        return error;
    }

    assert( false );
    return 0; // never reached
}

void VerifyCommand::canceled()
{
}

#include "verifycommand.moc"
<|endoftext|>


<commit_before>/*
 * Copyright(c) 2021 Intel Corporation.
 *
 * 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.
 */
#ifndef _TDI_PORT_TABLE_IMPL_HPP
#define _TDI_PORT_TABLE_IMPL_HPP

//#include <tdi_rt/tdi_port/tdi_table_impl.hpp>
//#include <tdi_port/dpdk/tdi_port_table_data_impl.hpp>
#include <tdi_rt/tdi_port/dpdk/tdi_port_table_data_impl.hpp>
#include <tdi_rt/tdi_port/tdi_port_table_key_impl.hpp>
//#include <tdi_rt/tdi_dpdk_defs.h>

namespace tdi {

class TdiInfo;
/*
 * PortCfgTable
 * PortStatTable
 */

typedef struct key_size_ {
  size_t bytes;
  size_t bits;
} key_size_t;

typedef uint32_t pipe_tbl_hdl_t;
typedef uint32_t pipe_act_fn_hdl_t;

/* Struct to keep info regarding a reference to a table */
typedef struct tdi_table_ref_info_ {
  std::string name;
  tdi_id_t id;
  pipe_tbl_hdl_t tbl_hdl;
  // A flag to indicate if the reference is indirect. TRUE when it is, FALSE
  // when the refernece is direct
  bool indirect_ref;
} tdi_table_ref_info_t;

/* Structure to keep action info */
typedef struct tdi_info_action_info_ {
  tdi_id_t action_id;
  std::string name;
  pipe_act_fn_hdl_t act_fn_hdl;
  // Map of table_data_fields
  std::map<tdi_id_t, std::unique_ptr<DataFieldInfo>> data_fields;
  // Map of table_data_fields with names
  std::map<std::string, DataFieldInfo *> data_fields_names;
  // Size of the action data in bytes
  size_t dataSz;
  // Size of the action data in bits (not including byte padding)
  size_t dataSzbits;
  std::set<Annotation> annotations{};
} tdi_info_action_info_t;

class PortCfgTable : public Table {
 public:
  PortCfgTable(const tdi::TableInfo *table_info) : tdi::Table(table_info) {
    mapInit();
    LOG_ERROR("Creating PortCfgTable table for %s", table_info->nameGet().c_str());
  };
#if 0
  PortCfgTable(const std::string &program_name,
                   tdi_id_t id,
                   std::string name,
                   const size_t &size)
      : Table(program_name,
                     id,
                     name,
                     size,
                     TableType::PORT_CFG,
                     std::set<TableApi>{
                         TableApi::ADD,
                         TableApi::DELETE,
                     }) {
    mapInit();
  };
#endif

  tdi_status_t entryAdd(const Session & /*session*/,
                        const Target &dev_tgt,
			const Flags &flags,
                        const TableKey &key,
                        const TableData &data) const override;

  tdi_status_t entryDel(const Session & /*session*/,
                        const Target &dev_tgt,
			const Flags &flags,
                        const TableKey &key) const override;

  tdi_status_t keyAllocate(
      std::unique_ptr<TableKey> *key_ret) const override;

  tdi_status_t dataAllocate(
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataAllocate(
      const std::vector<tdi_id_t> &fields,
      std::unique_ptr<TableData> *data_ret) const /*override*/;

  tdi_status_t keyReset(TableKey *key) const override final;

  //tdi_status_t dataReset(TableData *data) const override final;
  tdi_status_t dataReset(TableData *data) const;
  //tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
  //                      TableData *data) const override final;
  tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
                         TableData *data) const;
  // Attribute APIs
#if 0
  // wait for attribute core class defined.
  tdi_status_t attributeAllocate(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
  tdi_status_t attributeReset(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
  tdi_status_t tableAttributesSet(
      const Session & /*session*/,
      const Target &dev_tgt,
      const TableAttributes &tableAttributes) const override;
#endif

 private:
  void mapInit();
  std::map<std::string, dpdk_port_type_t> portTypeMap;
  std::map<std::string, bf_pm_port_dir_e> portDirMap;

  tdi_status_t entryAdd(const Session & /*session*/,
                                      const Target & /*dev_tgt*/,
                                      const TableKey &key,
                                      const TableData &data) const;
};

class PortStatTable : public Table {
 public:
  PortStatTable(const tdi::TableInfo *table_info) : tdi::Table(table_info) {
    LOG_ERROR("Creating PortStatTable table for %s", table_info->nameGet().c_str());
  };

  tdi_status_t entryGet(const Session &session,
                        const Target &dev_tgt,
			const Flags &flag,
                        const TableKey &key,
                        //const Table::TableGetFlag &flag,
                        TableData *data) const override;
  tdi_status_t keyAllocate(
      std::unique_ptr<TableKey> *key_ret) const override;

  tdi_status_t dataAllocate(
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataAllocate(
      const std::vector<tdi_id_t> &fields,
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataReset(TableData *data) const override final;
  tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
                        TableData *data) const override final;
#if 0
  // Attribute APIs
  tdi_status_t attributeAllocate(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
#endif

 private:
  tdi_status_t entryGet_internal(const Target &dev_tgt,
                                 const uint32_t &dev_port,
                                 PortStatTableData *data) const;
};
}  // tdi

#endif  // _TDI_PORT_TABLE_IMPL_HPP
<commit_msg>remove the definitions which should be part of generic table not part of port table.<commit_after>/*
 * Copyright(c) 2021 Intel Corporation.
 *
 * 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.
 */
#ifndef _TDI_PORT_TABLE_IMPL_HPP
#define _TDI_PORT_TABLE_IMPL_HPP

//#include <tdi_rt/tdi_port/tdi_table_impl.hpp>
//#include <tdi_port/dpdk/tdi_port_table_data_impl.hpp>
#include <tdi_rt/tdi_port/dpdk/tdi_port_table_data_impl.hpp>
#include <tdi_rt/tdi_port/tdi_port_table_key_impl.hpp>
//#include <tdi_rt/tdi_dpdk_defs.h>

namespace tdi {

class TdiInfo;
/*
 * PortCfgTable
 * PortStatTable
 */

class PortCfgTable : public Table {
 public:
  PortCfgTable(const tdi::TableInfo *table_info) : tdi::Table(table_info) {
    mapInit();
    LOG_ERROR("Creating PortCfgTable table for %s", table_info->nameGet().c_str());
  };
#if 0
  PortCfgTable(const std::string &program_name,
                   tdi_id_t id,
                   std::string name,
                   const size_t &size)
      : Table(program_name,
                     id,
                     name,
                     size,
                     TableType::PORT_CFG,
                     std::set<TableApi>{
                         TableApi::ADD,
                         TableApi::DELETE,
                     }) {
    mapInit();
  };
#endif

  tdi_status_t entryAdd(const Session & /*session*/,
                        const Target &dev_tgt,
			const Flags &flags,
                        const TableKey &key,
                        const TableData &data) const override;

  tdi_status_t entryDel(const Session & /*session*/,
                        const Target &dev_tgt,
			const Flags &flags,
                        const TableKey &key) const override;

  tdi_status_t keyAllocate(
      std::unique_ptr<TableKey> *key_ret) const override;

  tdi_status_t dataAllocate(
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataAllocate(
      const std::vector<tdi_id_t> &fields,
      std::unique_ptr<TableData> *data_ret) const /*override*/;

  tdi_status_t keyReset(TableKey *key) const override final;

  //tdi_status_t dataReset(TableData *data) const override final;
  tdi_status_t dataReset(TableData *data) const;
  //tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
  //                      TableData *data) const override final;
  tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
                         TableData *data) const;
  // Attribute APIs
#if 0
  // wait for attribute core class defined.
  tdi_status_t attributeAllocate(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
  tdi_status_t attributeReset(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
  tdi_status_t tableAttributesSet(
      const Session & /*session*/,
      const Target &dev_tgt,
      const TableAttributes &tableAttributes) const override;
#endif

 private:
  void mapInit();
  std::map<std::string, dpdk_port_type_t> portTypeMap;
  std::map<std::string, bf_pm_port_dir_e> portDirMap;

  tdi_status_t entryAdd(const Session & /*session*/,
                                      const Target & /*dev_tgt*/,
                                      const TableKey &key,
                                      const TableData &data) const;
};

class PortStatTable : public Table {
 public:
  PortStatTable(const tdi::TableInfo *table_info) : tdi::Table(table_info) {
    LOG_DBG("Creating PortStatTable table for %s", table_info->nameGet().c_str());
  };

  tdi_status_t entryGet(const Session &session,
                        const Target &dev_tgt,
			const Flags &flag,
                        const TableKey &key,
                        //const Table::TableGetFlag &flag,
                        TableData *data) const override;
  tdi_status_t keyAllocate(
      std::unique_ptr<TableKey> *key_ret) const override;

  tdi_status_t dataAllocate(
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataAllocate(
      const std::vector<tdi_id_t> &fields,
      std::unique_ptr<TableData> *data_ret) const override;

  tdi_status_t dataReset(TableData *data) const override final;
  tdi_status_t dataReset(const std::vector<tdi_id_t> &fields,
                        TableData *data) const override final;
#if 0
  // Attribute APIs
  tdi_status_t attributeAllocate(
      const TableAttributesType &type,
      std::unique_ptr<TableAttributes> *attr) const override;
#endif

 private:
  tdi_status_t entryGet_internal(const Target &dev_tgt,
                                 const uint32_t &dev_port,
                                 PortStatTableData *data) const;
};
}  // tdi

#endif  // _TDI_PORT_TABLE_IMPL_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/bookmark_bubble_view.h"

#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/event.h"
#include "views/standard_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"
#include "views/window/client_view.h"
#include "views/window/window.h"

using views::Combobox;
using views::ColumnSet;
using views::GridLayout;
using views::Label;
using views::Link;
using views::NativeButton;
using views::View;

// Padding between "Title:" and the actual title.
static const int kTitlePadding = 4;

// Minimum width for the fields - they will push out the size of the bubble if
// necessary. This should be big enough so that the field pushes the right side
// of the bubble far enough so that the edit button's left edge is to the right
// of the field's left edge.
static const int kMinimumFieldSize = 180;

// Bubble close image.
static SkBitmap* kCloseImage = NULL;

// Declared in browser_dialogs.h so callers don't have to depend on our header.

namespace browser {

void ShowBookmarkBubbleView(views::Window* parent,
                            const gfx::Rect& bounds,
                            InfoBubbleDelegate* delegate,
                            Profile* profile,
                            const GURL& url,
                            bool newly_bookmarked) {
  BookmarkBubbleView::Show(parent, bounds, delegate, profile, url,
                           newly_bookmarked);
}

void HideBookmarkBubbleView() {
  BookmarkBubbleView::Hide();
}

bool IsBookmarkBubbleViewShowing() {
  return BookmarkBubbleView::IsShowing();
}

}  // namespace browser

// BookmarkBubbleView ---------------------------------------------------------

BookmarkBubbleView* BookmarkBubbleView::bubble_ = NULL;

// static
void BookmarkBubbleView::Show(views::Window* parent,
                              const gfx::Rect& bounds,
                              InfoBubbleDelegate* delegate,
                              Profile* profile,
                              const GURL& url,
                              bool newly_bookmarked) {
  if (IsShowing())
    return;

  bubble_ = new BookmarkBubbleView(delegate, profile, url, newly_bookmarked);
  InfoBubble* info_bubble = InfoBubble::Show(
      parent->GetClientView()->GetWidget(), bounds, BubbleBorder::TOP_RIGHT,
      bubble_, bubble_);
  bubble_->set_info_bubble(info_bubble);
  GURL url_ptr(url);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_SHOWN,
      Source<Profile>(profile->GetOriginalProfile()),
      Details<GURL>(&url_ptr));
  bubble_->BubbleShown();
}

// static
bool BookmarkBubbleView::IsShowing() {
  return bubble_ != NULL;
}

void BookmarkBubbleView::Hide() {
  if (IsShowing())
    bubble_->Close();
}

BookmarkBubbleView::~BookmarkBubbleView() {
  if (apply_edits_) {
    ApplyEdits();
  } else if (remove_bookmark_) {
    BookmarkModel* model = profile_->GetBookmarkModel();
    const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
    if (node)
      model->Remove(node->GetParent(), node->GetParent()->IndexOfChild(node));
  }
}

void BookmarkBubbleView::DidChangeBounds(const gfx::Rect& previous,
                                         const gfx::Rect& current) {
  Layout();
}

void BookmarkBubbleView::BubbleShown() {
  DCHECK(GetWidget());
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(app::VKEY_RETURN, false, false, false), this);

  title_tf_->RequestFocus();
  title_tf_->SelectAll();
}

bool BookmarkBubbleView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  if (accelerator.GetKeyCode() != app::VKEY_RETURN)
    return false;

  if (edit_button_->HasFocus())
    HandleButtonPressed(edit_button_);
  else
    HandleButtonPressed(close_button_);
  return true;
}

void BookmarkBubbleView::ViewHierarchyChanged(bool is_add, View* parent,
                                              View* child) {
  if (is_add && child == this)
    Init();
}

BookmarkBubbleView::BookmarkBubbleView(InfoBubbleDelegate* delegate,
                                       Profile* profile,
                                       const GURL& url,
                                       bool newly_bookmarked)
    : delegate_(delegate),
      profile_(profile),
      url_(url),
      newly_bookmarked_(newly_bookmarked),
      parent_model_(
          profile_->GetBookmarkModel(),
          profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url)),
      remove_bookmark_(false),
      apply_edits_(true) {
}

void BookmarkBubbleView::Init() {
  static SkColor kTitleColor;
  static bool initialized = false;
  if (!initialized) {
    kTitleColor = color_utils::GetReadableColor(SkColorSetRGB(6, 45, 117),
                                                InfoBubble::kBackgroundColor);
    kCloseImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFO_BUBBLE_CLOSE);

    initialized = true;
  }

  remove_link_ = new Link(l10n_util::GetString(
      IDS_BOOMARK_BUBBLE_REMOVE_BOOKMARK));
  remove_link_->SetController(this);

  edit_button_ = new NativeButton(
      this, l10n_util::GetString(IDS_BOOMARK_BUBBLE_OPTIONS));

  close_button_ = new NativeButton(this, l10n_util::GetString(IDS_DONE));
  close_button_->SetIsDefault(true);

  Label* combobox_label = new Label(
      l10n_util::GetString(IDS_BOOMARK_BUBBLE_FOLDER_TEXT));

  parent_combobox_ = new Combobox(&parent_model_);
  parent_combobox_->SetSelectedItem(parent_model_.node_parent_index());
  parent_combobox_->set_listener(this);
  parent_combobox_->SetAccessibleName(combobox_label->GetText());

  Label* title_label = new Label(l10n_util::GetString(
      newly_bookmarked_ ? IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED :
                          IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK));
  title_label->SetFont(
      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
  title_label->SetColor(kTitleColor);

  GridLayout* layout = new GridLayout(this);
  SetLayoutManager(layout);

  ColumnSet* cs = layout->AddColumnSet(0);

  // Top (title) row.
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);
  cs->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);

  // Middle (input field) rows.
  cs = layout->AddColumnSet(2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                GridLayout::USE_PREF, 0, 0);
  cs->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                GridLayout::USE_PREF, 0, kMinimumFieldSize);

  // Bottom (buttons) row.
  cs = layout->AddColumnSet(3);
  cs->AddPaddingColumn(1, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);
  // We subtract 2 to account for the natural button padding, and
  // to bring the separation visually in line with the row separation
  // height.
  cs->AddPaddingColumn(0, kRelatedButtonHSpacing - 2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, 0);
  layout->AddView(title_label);
  layout->AddView(remove_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, 2);
  layout->AddView(
      new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
  title_tf_ = new views::Textfield();
  title_tf_->SetText(GetTitle());
  layout->AddView(title_tf_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 2);
  layout->AddView(combobox_label);
  layout->AddView(parent_combobox_);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 3);
  layout->AddView(edit_button_);
  layout->AddView(close_button_);
}

string16 BookmarkBubbleView::GetTitle() {
  BookmarkModel* bookmark_model= profile_->GetBookmarkModel();
  const BookmarkNode* node =
      bookmark_model->GetMostRecentlyAddedNodeForURL(url_);
  if (node)
    return node->GetTitle();
  else
    NOTREACHED();
  return string16();
}

void BookmarkBubbleView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  HandleButtonPressed(sender);
}

void BookmarkBubbleView::LinkActivated(Link* source, int event_flags) {
  DCHECK(source == remove_link_);
  UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
                            profile_);

  // Set this so we remove the bookmark after the window closes.
  remove_bookmark_ = true;
  apply_edits_ = false;

  info_bubble_->set_fade_away_on_close(true);
  Close();
}

void BookmarkBubbleView::ItemChanged(Combobox* combobox,
                                     int prev_index,
                                     int new_index) {
  if (new_index + 1 == parent_model_.GetItemCount()) {
    UserMetrics::RecordAction(
              UserMetricsAction("BookmarkBubble_EditFromCombobox"), profile_);

    ShowEditor();
    return;
  }
}

void BookmarkBubbleView::InfoBubbleClosing(InfoBubble* info_bubble,
                                           bool closed_by_escape) {
  if (closed_by_escape) {
    remove_bookmark_ = newly_bookmarked_;
    apply_edits_ = false;
  }

  // We have to reset |bubble_| here, not in our destructor, because we'll be
  // destroyed asynchronously and the shown state will be checked before then.
  DCHECK(bubble_ == this);
  bubble_ = NULL;

  if (delegate_)
    delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_HIDDEN,
      Source<Profile>(profile_->GetOriginalProfile()),
      NotificationService::NoDetails());
}

bool BookmarkBubbleView::CloseOnEscape() {
  return delegate_ ? delegate_->CloseOnEscape() : true;
}

std::wstring BookmarkBubbleView::accessible_name() {
  return l10n_util::GetString(IDS_BOOMARK_BUBBLE_ADD_BOOKMARK);
}

void BookmarkBubbleView::Close() {
  static_cast<InfoBubble*>(GetWidget())->Close();
}

void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
  if (sender == edit_button_) {
    UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
                              profile_);
    info_bubble_->set_fade_away_on_close(true);
    ShowEditor();
  } else {
    DCHECK(sender == close_button_);
    info_bubble_->set_fade_away_on_close(true);
    Close();
  }
  // WARNING: we've most likely been deleted when CloseWindow returns.
}

void BookmarkBubbleView::ShowEditor() {
  const BookmarkNode* node =
      profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url_);

  // Commit any edits now.
  ApplyEdits();

#if defined(OS_WIN)
  // Parent the editor to our root ancestor (not the root we're in, as that
  // is the info bubble and will close shortly).
  HWND parent = GetAncestor(GetWidget()->GetNativeView(), GA_ROOTOWNER);

  // We're about to show the bookmark editor. When the bookmark editor closes
  // we want the browser to become active. WidgetWin::Hide() does a hide in
  // a such way that activation isn't changed, which means when we close
  // Windows gets confused as to who it should give active status to. We
  // explicitly hide the bookmark bubble window in such a way that activation
  // status changes. That way, when the editor closes, activation is properly
  // restored to the browser.
  ShowWindow(GetWidget()->GetNativeView(), SW_HIDE);
#else
  gfx::NativeWindow parent = GTK_WINDOW(
      static_cast<views::WidgetGtk*>(GetWidget())->GetTransientParent());
#endif

  // Even though we just hid the window, we need to invoke Close to schedule
  // the delete and all that.
  Close();

  if (node) {
    BookmarkEditor::Show(parent, profile_, NULL,
                         BookmarkEditor::EditDetails(node),
                         BookmarkEditor::SHOW_TREE);
  }
}

void BookmarkBubbleView::ApplyEdits() {
  // Set this to make sure we don't attempt to apply edits again.
  apply_edits_ = false;

  BookmarkModel* model = profile_->GetBookmarkModel();
  const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
  if (node) {
    const string16 new_title = title_tf_->text();
    if (new_title != node->GetTitle()) {
      model->SetTitle(node, new_title);
      UserMetrics::RecordAction(
          UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
          profile_);
    }
    // Last index means 'Choose another folder...'
    if (parent_combobox_->selected_item() <
        parent_model_.GetItemCount() - 1) {
      const BookmarkNode* new_parent =
          parent_model_.GetNodeAt(parent_combobox_->selected_item());
      if (new_parent != node->GetParent()) {
        UserMetrics::RecordAction(
            UserMetricsAction("BookmarkBubble_ChangeParent"), profile_);
        model->Move(node, new_parent, new_parent->GetChildCount());
      }
    }
  }
}
<commit_msg>Sizes bookmark bubble after it was shown.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/bookmark_bubble_view.h"

#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/event.h"
#include "views/standard_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"
#include "views/window/client_view.h"
#include "views/window/window.h"

using views::Combobox;
using views::ColumnSet;
using views::GridLayout;
using views::Label;
using views::Link;
using views::NativeButton;
using views::View;

// Padding between "Title:" and the actual title.
static const int kTitlePadding = 4;

// Minimum width for the fields - they will push out the size of the bubble if
// necessary. This should be big enough so that the field pushes the right side
// of the bubble far enough so that the edit button's left edge is to the right
// of the field's left edge.
static const int kMinimumFieldSize = 180;

// Bubble close image.
static SkBitmap* kCloseImage = NULL;

// Declared in browser_dialogs.h so callers don't have to depend on our header.

namespace browser {

void ShowBookmarkBubbleView(views::Window* parent,
                            const gfx::Rect& bounds,
                            InfoBubbleDelegate* delegate,
                            Profile* profile,
                            const GURL& url,
                            bool newly_bookmarked) {
  BookmarkBubbleView::Show(parent, bounds, delegate, profile, url,
                           newly_bookmarked);
}

void HideBookmarkBubbleView() {
  BookmarkBubbleView::Hide();
}

bool IsBookmarkBubbleViewShowing() {
  return BookmarkBubbleView::IsShowing();
}

}  // namespace browser

// BookmarkBubbleView ---------------------------------------------------------

BookmarkBubbleView* BookmarkBubbleView::bubble_ = NULL;

// static
void BookmarkBubbleView::Show(views::Window* parent,
                              const gfx::Rect& bounds,
                              InfoBubbleDelegate* delegate,
                              Profile* profile,
                              const GURL& url,
                              bool newly_bookmarked) {
  if (IsShowing())
    return;

  bubble_ = new BookmarkBubbleView(delegate, profile, url, newly_bookmarked);
  InfoBubble* info_bubble = InfoBubble::Show(
      parent->GetClientView()->GetWidget(), bounds, BubbleBorder::TOP_RIGHT,
      bubble_, bubble_);
  bubble_->set_info_bubble(info_bubble);
  info_bubble->SizeToContents();
  GURL url_ptr(url);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_SHOWN,
      Source<Profile>(profile->GetOriginalProfile()),
      Details<GURL>(&url_ptr));
  bubble_->BubbleShown();
}

// static
bool BookmarkBubbleView::IsShowing() {
  return bubble_ != NULL;
}

void BookmarkBubbleView::Hide() {
  if (IsShowing())
    bubble_->Close();
}

BookmarkBubbleView::~BookmarkBubbleView() {
  if (apply_edits_) {
    ApplyEdits();
  } else if (remove_bookmark_) {
    BookmarkModel* model = profile_->GetBookmarkModel();
    const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
    if (node)
      model->Remove(node->GetParent(), node->GetParent()->IndexOfChild(node));
  }
}

void BookmarkBubbleView::DidChangeBounds(const gfx::Rect& previous,
                                         const gfx::Rect& current) {
  Layout();
}

void BookmarkBubbleView::BubbleShown() {
  DCHECK(GetWidget());
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(app::VKEY_RETURN, false, false, false), this);

  title_tf_->RequestFocus();
  title_tf_->SelectAll();
}

bool BookmarkBubbleView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  if (accelerator.GetKeyCode() != app::VKEY_RETURN)
    return false;

  if (edit_button_->HasFocus())
    HandleButtonPressed(edit_button_);
  else
    HandleButtonPressed(close_button_);
  return true;
}

void BookmarkBubbleView::ViewHierarchyChanged(bool is_add, View* parent,
                                              View* child) {
  if (is_add && child == this)
    Init();
}

BookmarkBubbleView::BookmarkBubbleView(InfoBubbleDelegate* delegate,
                                       Profile* profile,
                                       const GURL& url,
                                       bool newly_bookmarked)
    : delegate_(delegate),
      profile_(profile),
      url_(url),
      newly_bookmarked_(newly_bookmarked),
      parent_model_(
          profile_->GetBookmarkModel(),
          profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url)),
      remove_bookmark_(false),
      apply_edits_(true) {
}

void BookmarkBubbleView::Init() {
  static SkColor kTitleColor;
  static bool initialized = false;
  if (!initialized) {
    kTitleColor = color_utils::GetReadableColor(SkColorSetRGB(6, 45, 117),
                                                InfoBubble::kBackgroundColor);
    kCloseImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFO_BUBBLE_CLOSE);

    initialized = true;
  }

  remove_link_ = new Link(l10n_util::GetString(
      IDS_BOOMARK_BUBBLE_REMOVE_BOOKMARK));
  remove_link_->SetController(this);

  edit_button_ = new NativeButton(
      this, l10n_util::GetString(IDS_BOOMARK_BUBBLE_OPTIONS));

  close_button_ = new NativeButton(this, l10n_util::GetString(IDS_DONE));
  close_button_->SetIsDefault(true);

  Label* combobox_label = new Label(
      l10n_util::GetString(IDS_BOOMARK_BUBBLE_FOLDER_TEXT));

  parent_combobox_ = new Combobox(&parent_model_);
  parent_combobox_->SetSelectedItem(parent_model_.node_parent_index());
  parent_combobox_->set_listener(this);
  parent_combobox_->SetAccessibleName(combobox_label->GetText());

  Label* title_label = new Label(l10n_util::GetString(
      newly_bookmarked_ ? IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED :
                          IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK));
  title_label->SetFont(
      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
  title_label->SetColor(kTitleColor);

  GridLayout* layout = new GridLayout(this);
  SetLayoutManager(layout);

  ColumnSet* cs = layout->AddColumnSet(0);

  // Top (title) row.
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);
  cs->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);

  // Middle (input field) rows.
  cs = layout->AddColumnSet(2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                GridLayout::USE_PREF, 0, 0);
  cs->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                GridLayout::USE_PREF, 0, kMinimumFieldSize);

  // Bottom (buttons) row.
  cs = layout->AddColumnSet(3);
  cs->AddPaddingColumn(1, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);
  // We subtract 2 to account for the natural button padding, and
  // to bring the separation visually in line with the row separation
  // height.
  cs->AddPaddingColumn(0, kRelatedButtonHSpacing - 2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, 0);
  layout->AddView(title_label);
  layout->AddView(remove_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, 2);
  layout->AddView(
      new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
  title_tf_ = new views::Textfield();
  title_tf_->SetText(GetTitle());
  layout->AddView(title_tf_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 2);
  layout->AddView(combobox_label);
  layout->AddView(parent_combobox_);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 3);
  layout->AddView(edit_button_);
  layout->AddView(close_button_);
}

string16 BookmarkBubbleView::GetTitle() {
  BookmarkModel* bookmark_model= profile_->GetBookmarkModel();
  const BookmarkNode* node =
      bookmark_model->GetMostRecentlyAddedNodeForURL(url_);
  if (node)
    return node->GetTitle();
  else
    NOTREACHED();
  return string16();
}

void BookmarkBubbleView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  HandleButtonPressed(sender);
}

void BookmarkBubbleView::LinkActivated(Link* source, int event_flags) {
  DCHECK(source == remove_link_);
  UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
                            profile_);

  // Set this so we remove the bookmark after the window closes.
  remove_bookmark_ = true;
  apply_edits_ = false;

  info_bubble_->set_fade_away_on_close(true);
  Close();
}

void BookmarkBubbleView::ItemChanged(Combobox* combobox,
                                     int prev_index,
                                     int new_index) {
  if (new_index + 1 == parent_model_.GetItemCount()) {
    UserMetrics::RecordAction(
              UserMetricsAction("BookmarkBubble_EditFromCombobox"), profile_);

    ShowEditor();
    return;
  }
}

void BookmarkBubbleView::InfoBubbleClosing(InfoBubble* info_bubble,
                                           bool closed_by_escape) {
  if (closed_by_escape) {
    remove_bookmark_ = newly_bookmarked_;
    apply_edits_ = false;
  }

  // We have to reset |bubble_| here, not in our destructor, because we'll be
  // destroyed asynchronously and the shown state will be checked before then.
  DCHECK(bubble_ == this);
  bubble_ = NULL;

  if (delegate_)
    delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_HIDDEN,
      Source<Profile>(profile_->GetOriginalProfile()),
      NotificationService::NoDetails());
}

bool BookmarkBubbleView::CloseOnEscape() {
  return delegate_ ? delegate_->CloseOnEscape() : true;
}

std::wstring BookmarkBubbleView::accessible_name() {
  return l10n_util::GetString(IDS_BOOMARK_BUBBLE_ADD_BOOKMARK);
}

void BookmarkBubbleView::Close() {
  static_cast<InfoBubble*>(GetWidget())->Close();
}

void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
  if (sender == edit_button_) {
    UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
                              profile_);
    info_bubble_->set_fade_away_on_close(true);
    ShowEditor();
  } else {
    DCHECK(sender == close_button_);
    info_bubble_->set_fade_away_on_close(true);
    Close();
  }
  // WARNING: we've most likely been deleted when CloseWindow returns.
}

void BookmarkBubbleView::ShowEditor() {
  const BookmarkNode* node =
      profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url_);

  // Commit any edits now.
  ApplyEdits();

#if defined(OS_WIN)
  // Parent the editor to our root ancestor (not the root we're in, as that
  // is the info bubble and will close shortly).
  HWND parent = GetAncestor(GetWidget()->GetNativeView(), GA_ROOTOWNER);

  // We're about to show the bookmark editor. When the bookmark editor closes
  // we want the browser to become active. WidgetWin::Hide() does a hide in
  // a such way that activation isn't changed, which means when we close
  // Windows gets confused as to who it should give active status to. We
  // explicitly hide the bookmark bubble window in such a way that activation
  // status changes. That way, when the editor closes, activation is properly
  // restored to the browser.
  ShowWindow(GetWidget()->GetNativeView(), SW_HIDE);
#else
  gfx::NativeWindow parent = GTK_WINDOW(
      static_cast<views::WidgetGtk*>(GetWidget())->GetTransientParent());
#endif

  // Even though we just hid the window, we need to invoke Close to schedule
  // the delete and all that.
  Close();

  if (node) {
    BookmarkEditor::Show(parent, profile_, NULL,
                         BookmarkEditor::EditDetails(node),
                         BookmarkEditor::SHOW_TREE);
  }
}

void BookmarkBubbleView::ApplyEdits() {
  // Set this to make sure we don't attempt to apply edits again.
  apply_edits_ = false;

  BookmarkModel* model = profile_->GetBookmarkModel();
  const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
  if (node) {
    const string16 new_title = title_tf_->text();
    if (new_title != node->GetTitle()) {
      model->SetTitle(node, new_title);
      UserMetrics::RecordAction(
          UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
          profile_);
    }
    // Last index means 'Choose another folder...'
    if (parent_combobox_->selected_item() <
        parent_model_.GetItemCount() - 1) {
      const BookmarkNode* new_parent =
          parent_model_.GetNodeAt(parent_combobox_->selected_item());
      if (new_parent != node->GetParent()) {
        UserMetrics::RecordAction(
            UserMetricsAction("BookmarkBubble_ChangeParent"), profile_);
        model->Move(node, new_parent, new_parent->GetChildCount());
      }
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @file   ProfileTest.cpp
 * @brief  Profile class tester.
 * @author zer0
 * @date   2016-09-21
 */

#include <gtest/gtest.h>
#include <libtbag/debug/Profile.hpp>

using namespace libtbag;
using namespace libtbag::debug;

TEST(ProfileTest, Default)
{
    std::size_t const CYCLE =  2;
    std::size_t const TOTAL = 11;

    int update_callback = 0;

    Profile profile(CYCLE, [&](Profile::Rep average){
        ++update_callback;
    });

    for (std::size_t i = 0; i < TOTAL; ++i) {
        profile.tick();
    }

    ASSERT_EQ(static_cast<std::size_t>(TOTAL / CYCLE), update_callback);
}

TEST(ProfileTest, GetUnitString)
{
    ASSERT_FALSE(std::string(Profile::getTimeUnitString()).empty());
}

<commit_msg>Trivial commit.<commit_after>/**
 * @file   ProfileTest.cpp
 * @brief  Profile class tester.
 * @author zer0
 * @date   2016-09-21
 */

#include <gtest/gtest.h>
#include <libtbag/debug/Profile.hpp>

using namespace libtbag;
using namespace libtbag::debug;

TEST(ProfileTest, Default)
{
    std::size_t const CYCLE =  2;
    std::size_t const TOTAL = 11;

    int update_callback = 0;

    Profile profile(CYCLE, [&](Profile::Rep average){
        ++update_callback;
    });

    for (std::size_t i = 0; i < TOTAL; ++i) {
        profile.tick();
    }

    ASSERT_EQ(static_cast<std::size_t>(TOTAL / CYCLE), update_callback);
}

TEST(ProfileTest, GetUnitString)
{
    auto const text = Profile::getTimeUnitString();
    std::cout << "TimeUnit: " << text << std::endl;
    ASSERT_FALSE(std::string(text).empty());
}

<|endoftext|>


<commit_before>// Copyright (c) 2013 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// exploitability_linux.cc: Linux specific exploitability engine.
//
// Provides a guess at the exploitability of the crash for the Linux
// platform given a minidump and process_state.
//
// Author: Matthew Riley

#include "processor/exploitability_linux.h"

#include "google_breakpad/common/minidump_exception_linux.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/process_state.h"
#include "google_breakpad/processor/stack_frame.h"
#include "processor/logging.h"

namespace {

// This function in libc is called if the program was compiled with
// -fstack-protector and a function's stack canary changes.
const char kStackCheckFailureFunction[] = "__stack_chk_fail";

// This function in libc is called if the program was compiled with
// -D_FORTIFY_SOURCE=2, a function like strcpy() is called, and the runtime
// can determine that the call would overflow the target buffer.
const char kBoundsCheckFailureFunction[] = "__chk_fail";

}  // namespace

namespace google_breakpad {

ExploitabilityLinux::ExploitabilityLinux(Minidump *dump,
                                         ProcessState *process_state)
    : Exploitability(dump, process_state) { }

ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() {
  // Check the crashing thread for functions suggesting a buffer overflow or
  // stack smash.
  if (process_state_->requesting_thread() != -1) {
    CallStack* crashing_thread =
        process_state_->threads()->at(process_state_->requesting_thread());
    const vector<StackFrame*>& crashing_thread_frames =
        *crashing_thread->frames();
    for (size_t i = 0; i < crashing_thread_frames.size(); ++i) {
      if (crashing_thread_frames[i]->function_name ==
          kStackCheckFailureFunction) {
        return EXPLOITABILITY_HIGH;
      }

      if (crashing_thread_frames[i]->function_name ==
          kBoundsCheckFailureFunction) {
        return EXPLOITABILITY_HIGH;
      }
    }
  }

  // Check if the instruction pointer is in a valid instruction region
  // by finding if it maps to an executable part of memory.
  uint64_t instruction_ptr = 0;

  // Getting exception data. (It should exist for all minidumps.)
  MinidumpException *exception = dump_->GetException();
  if (exception == NULL) {
    BPLOG(INFO) << "No exception record.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }
  const MinidumpContext *context = exception->GetContext();
  if (context == NULL) {
    BPLOG(INFO) << "No exception context.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Getting the instruction pointer.
  if (!context->GetInstructionPointer(&instruction_ptr)) {
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Checking for the instruction pointer in a valid instruction region.
  if (!this->InstructionPointerInCode(instruction_ptr)) {
    return EXPLOITABILITY_HIGH;
  }

  const MDRawExceptionStream *raw_exception_stream = exception->exception();
  if (raw_exception_stream == NULL) {
    BPLOG(INFO) << "No raw exception stream.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Checking for benign exceptions that caused the crash.
  if (this->BenignCrashTrigger(raw_exception_stream)) {
    return EXPLOITABILITY_NONE;
  }

  return EXPLOITABILITY_INTERESTING;
}

bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
  // Here we get memory mapping. Most minidumps will not contain a memory
  // mapping, so we will commonly resort to checking modules.
  MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList();
  const MinidumpMemoryInfo *mem_info =
      mem_info_list ?
      mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL;

  // Checking if the memory mapping at the instruction pointer is executable.
  // If there is no memory mapping, we will use the modules as reference.
  if (mem_info != NULL) {
    return mem_info->IsExecutable();
  }

  // If the memory mapping retrieval fails, we will check the modules
  // to see if the instruction pointer is inside a module.
  // TODO(liuandrew): Check if the instruction pointer lies in an executable
  // region within the module.
  MinidumpModuleList *minidump_module_list = dump_->GetModuleList();
  return !minidump_module_list ||
          minidump_module_list->GetModuleForAddress(instruction_ptr);
}

bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
                                                  *raw_exception_stream) {
  // Here we check the cause of crash.
  // If the exception of the crash is a benign exception,
  // it is probably not exploitable.
  switch (raw_exception_stream->exception_record.exception_code) {
    case MD_EXCEPTION_CODE_LIN_SIGHUP:
    case MD_EXCEPTION_CODE_LIN_SIGINT:
    case MD_EXCEPTION_CODE_LIN_SIGQUIT:
    case MD_EXCEPTION_CODE_LIN_SIGTRAP:
    case MD_EXCEPTION_CODE_LIN_SIGABRT:
    case MD_EXCEPTION_CODE_LIN_SIGFPE:
    case MD_EXCEPTION_CODE_LIN_SIGKILL:
    case MD_EXCEPTION_CODE_LIN_SIGUSR1:
    case MD_EXCEPTION_CODE_LIN_SIGUSR2:
    case MD_EXCEPTION_CODE_LIN_SIGPIPE:
    case MD_EXCEPTION_CODE_LIN_SIGALRM:
    case MD_EXCEPTION_CODE_LIN_SIGTERM:
    case MD_EXCEPTION_CODE_LIN_SIGCHLD:
    case MD_EXCEPTION_CODE_LIN_SIGCONT:
    case MD_EXCEPTION_CODE_LIN_SIGSTOP:
    case MD_EXCEPTION_CODE_LIN_SIGTSTP:
    case MD_EXCEPTION_CODE_LIN_SIGTTIN:
    case MD_EXCEPTION_CODE_LIN_SIGTTOU:
    case MD_EXCEPTION_CODE_LIN_SIGURG:
    case MD_EXCEPTION_CODE_LIN_SIGXCPU:
    case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
    case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
    case MD_EXCEPTION_CODE_LIN_SIGPROF:
    case MD_EXCEPTION_CODE_LIN_SIGWINCH:
    case MD_EXCEPTION_CODE_LIN_SIGIO:
    case MD_EXCEPTION_CODE_LIN_SIGPWR:
    case MD_EXCEPTION_CODE_LIN_SIGSYS:
    case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
      return true;
      break;
    default:
      return false;
      break;
  }
}

}  // namespace google_breakpad
<commit_msg>Set exception whitelist check as earlier check instead of last check.<commit_after>// Copyright (c) 2013 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// exploitability_linux.cc: Linux specific exploitability engine.
//
// Provides a guess at the exploitability of the crash for the Linux
// platform given a minidump and process_state.
//
// Author: Matthew Riley

#include "processor/exploitability_linux.h"

#include "google_breakpad/common/minidump_exception_linux.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/process_state.h"
#include "google_breakpad/processor/stack_frame.h"
#include "processor/logging.h"

namespace {

// This function in libc is called if the program was compiled with
// -fstack-protector and a function's stack canary changes.
const char kStackCheckFailureFunction[] = "__stack_chk_fail";

// This function in libc is called if the program was compiled with
// -D_FORTIFY_SOURCE=2, a function like strcpy() is called, and the runtime
// can determine that the call would overflow the target buffer.
const char kBoundsCheckFailureFunction[] = "__chk_fail";

}  // namespace

namespace google_breakpad {

ExploitabilityLinux::ExploitabilityLinux(Minidump *dump,
                                         ProcessState *process_state)
    : Exploitability(dump, process_state) { }

ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() {
  // Check the crashing thread for functions suggesting a buffer overflow or
  // stack smash.
  if (process_state_->requesting_thread() != -1) {
    CallStack* crashing_thread =
        process_state_->threads()->at(process_state_->requesting_thread());
    const vector<StackFrame*>& crashing_thread_frames =
        *crashing_thread->frames();
    for (size_t i = 0; i < crashing_thread_frames.size(); ++i) {
      if (crashing_thread_frames[i]->function_name ==
          kStackCheckFailureFunction) {
        return EXPLOITABILITY_HIGH;
      }

      if (crashing_thread_frames[i]->function_name ==
          kBoundsCheckFailureFunction) {
        return EXPLOITABILITY_HIGH;
      }
    }
  }

  // Getting exception data. (It should exist for all minidumps.)
  MinidumpException *exception = dump_->GetException();
  if (exception == NULL) {
    BPLOG(INFO) << "No exception record.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }
  const MDRawExceptionStream *raw_exception_stream = exception->exception();
  if (raw_exception_stream == NULL) {
    BPLOG(INFO) << "No raw exception stream.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Checking for benign exceptions that caused the crash.
  if (this->BenignCrashTrigger(raw_exception_stream)) {
    return EXPLOITABILITY_NONE;
  }

  // Check if the instruction pointer is in a valid instruction region
  // by finding if it maps to an executable part of memory.
  uint64_t instruction_ptr = 0;

  const MinidumpContext *context = exception->GetContext();
  if (context == NULL) {
    BPLOG(INFO) << "No exception context.";
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Getting the instruction pointer.
  if (!context->GetInstructionPointer(&instruction_ptr)) {
    return EXPLOITABILITY_ERR_PROCESSING;
  }

  // Checking for the instruction pointer in a valid instruction region.
  if (!this->InstructionPointerInCode(instruction_ptr)) {
    return EXPLOITABILITY_HIGH;
  }

  return EXPLOITABILITY_INTERESTING;
}

bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
  // Here we get memory mapping. Most minidumps will not contain a memory
  // mapping, so we will commonly resort to checking modules.
  MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList();
  const MinidumpMemoryInfo *mem_info =
      mem_info_list ?
      mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL;

  // Checking if the memory mapping at the instruction pointer is executable.
  // If there is no memory mapping, we will use the modules as reference.
  if (mem_info != NULL) {
    return mem_info->IsExecutable();
  }

  // If the memory mapping retrieval fails, we will check the modules
  // to see if the instruction pointer is inside a module.
  // TODO(liuandrew): Check if the instruction pointer lies in an executable
  // region within the module.
  MinidumpModuleList *minidump_module_list = dump_->GetModuleList();
  return !minidump_module_list ||
          minidump_module_list->GetModuleForAddress(instruction_ptr);
}

bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
                                                  *raw_exception_stream) {
  // Here we check the cause of crash.
  // If the exception of the crash is a benign exception,
  // it is probably not exploitable.
  switch (raw_exception_stream->exception_record.exception_code) {
    case MD_EXCEPTION_CODE_LIN_SIGHUP:
    case MD_EXCEPTION_CODE_LIN_SIGINT:
    case MD_EXCEPTION_CODE_LIN_SIGQUIT:
    case MD_EXCEPTION_CODE_LIN_SIGTRAP:
    case MD_EXCEPTION_CODE_LIN_SIGABRT:
    case MD_EXCEPTION_CODE_LIN_SIGFPE:
    case MD_EXCEPTION_CODE_LIN_SIGKILL:
    case MD_EXCEPTION_CODE_LIN_SIGUSR1:
    case MD_EXCEPTION_CODE_LIN_SIGUSR2:
    case MD_EXCEPTION_CODE_LIN_SIGPIPE:
    case MD_EXCEPTION_CODE_LIN_SIGALRM:
    case MD_EXCEPTION_CODE_LIN_SIGTERM:
    case MD_EXCEPTION_CODE_LIN_SIGCHLD:
    case MD_EXCEPTION_CODE_LIN_SIGCONT:
    case MD_EXCEPTION_CODE_LIN_SIGSTOP:
    case MD_EXCEPTION_CODE_LIN_SIGTSTP:
    case MD_EXCEPTION_CODE_LIN_SIGTTIN:
    case MD_EXCEPTION_CODE_LIN_SIGTTOU:
    case MD_EXCEPTION_CODE_LIN_SIGURG:
    case MD_EXCEPTION_CODE_LIN_SIGXCPU:
    case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
    case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
    case MD_EXCEPTION_CODE_LIN_SIGPROF:
    case MD_EXCEPTION_CODE_LIN_SIGWINCH:
    case MD_EXCEPTION_CODE_LIN_SIGIO:
    case MD_EXCEPTION_CODE_LIN_SIGPWR:
    case MD_EXCEPTION_CODE_LIN_SIGSYS:
    case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
      return true;
      break;
    default:
      return false;
      break;
  }
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before><commit_msg>Add: a anew file<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014 Josh Rickmar.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

#include <volo.h>

using namespace volo;

const std::array<Glib::ustring, 2> recognized_uri_schemes = { {
	"http://",
	"https://",
} };

// has_prefix returns whether the p is a prefix of s.
template <typename T>
bool has_prefix(T s, T p) {
	return s.size() >= p.size() && std::equal(p.begin(), p.end(), s.begin());
}

void guess_uri(Glib::ustring& uri) {
	for (auto& scheme : recognized_uri_schemes) {
		if (has_prefix(uri, scheme)) {
			return;
		}
	}
	uri = "http://" + uri;
}

WebContext WebContext::get_default() {
	return WebContext{webkit_web_context_get_default()};
}

void WebContext::set_process_model(WebKitProcessModel model) {
	webkit_web_context_set_process_model(wc, model);
}

static void WebView_load_changed_callback(WebKitWebView *wv,
	WebKitLoadEvent ev, gpointer signal) {

	static_cast<sigc::signal<void, WebKitLoadEvent> *>(signal)->emit(ev);
}

static void BackForwardList_changed_callback(WebKitBackForwardList *list,
	WebKitBackForwardListItem *item, gpointer removed, gpointer signal) {

	static_cast<sigc::signal<void, WebKitBackForwardList *> *>(signal)->emit(list);
}

static void WebView_notify_title_callback(GObject *, GParamSpec *, gpointer signal) {
	static_cast<sigc::signal<void> *>(signal)->emit();
}

static void WebView_notify_uri_callback(GObject *, GParamSpec *, gpointer signal) {
	static_cast<sigc::signal<void> *>(signal)->emit();
}

WebView::WebView(WebKitWebView *wv) : Gtk::Widget{reinterpret_cast<GtkWidget *>(wv)} {
	g_signal_connect(wv, "load-changed",
		G_CALLBACK(WebView_load_changed_callback),
		&signal_load_changed);

	auto bfl = webkit_web_view_get_back_forward_list(wv);
	g_signal_connect(bfl, "changed",
		G_CALLBACK(BackForwardList_changed_callback),
		&signal_back_forward_list_changed);

	g_signal_connect(wv, "notify::title",
		G_CALLBACK(WebView_notify_title_callback),
		&signal_notify_title);

	g_signal_connect(wv, "notify::uri",
		G_CALLBACK(WebView_notify_uri_callback),
		&signal_notify_uri);
}

WebView::WebView(const Glib::ustring& uri) : WebView{} {
	load_uri(uri);
}

void WebView::load_uri(const Glib::ustring& uri) {
	webkit_web_view_load_uri(gobj(), uri.c_str());
}

Glib::ustring WebView::get_uri() {
	auto uri = webkit_web_view_get_uri(gobj());
	return uri ? uri : "";
}

void WebView::reload() {
	webkit_web_view_reload(gobj());
}

void WebView::go_back() {
	webkit_web_view_go_back(gobj());
}

void WebView::go_forward() {
	webkit_web_view_go_forward(gobj());
}

sigc::connection WebView::connect_load_changed(
	std::function<void(WebKitLoadEvent)> handler) {

	return signal_load_changed.connect(handler);
}

sigc::connection WebView::connect_back_forward_list_changed(
	std::function<void(WebKitBackForwardList *)> handler) {

	return signal_back_forward_list_changed.connect(handler);
}

sigc::connection WebView::connect_notify_title(std::function<void()> handler) {
	return signal_notify_title.connect(handler);
}

sigc::connection WebView::connect_notify_uri(std::function<void()> handler) {
	return signal_notify_uri.connect(handler);
}

URIEntry::URIEntry() {
	set_size_request(600, -1); // TODO: make this dynamic with the window size
	set_margin_left(6);
	set_margin_right(6);
	entry.set_hexpand(true);

	entry.set_input_purpose(Gtk::INPUT_PURPOSE_URL);
	entry.set_icon_from_icon_name("view-refresh", Gtk::ENTRY_ICON_SECONDARY);

	entry.signal_button_release_event().connect(sigc::mem_fun(*this,
		&URIEntry::on_button_release_event), false);
	entry.property_is_focus().signal_changed().connect([this](...) {
		if (!entry.is_focus()) {
			entry.select_region(0, 0);
			editing = false;
		}
	});
	entry.signal_icon_press().connect([this](Gtk::EntryIconPosition pos, ...) {
		refresh_pressed = true;
	});
	entry.signal_icon_release().connect([this](Gtk::EntryIconPosition pos, ...) {
		if (refresh_pressed) {
			signal_refresh.emit();
		}
		refresh_pressed = false;
	});

	add(entry);

	show_all_children();
}

Glib::SignalProxy0<void> URIEntry::signal_uri_entered() {
	return entry.signal_activate();
}

Glib::ustring URIEntry::get_uri() {
	return entry.get_text();
}

void URIEntry::set_uri(const Glib::ustring& uri) {
	if (!entry.is_focus()) {
		entry.set_text(uri);
	}
}

void URIEntry::grab_focus() {
	entry.grab_focus();
}

// This can't be a lambda since we can't create sigc::slots from lambdas
// with return values.
bool URIEntry::on_button_release_event(GdkEventButton *) {
	// If the entry's refresh button was pressed, we do not set
	// editing mode to true and do not grab focus to highlight
	// all text in the entry.
	if (refresh_pressed) {
		return false;
	}

	// If the refresh button was not pressed, and we haven't previously
	// grabbed focus, do so now.  The editing flag will be unset after
	// focus leaves the entry, but until then, the text inside entry can
	// be modified and clicked without forcably selecting all of the text
	// again.
	int start, end;
	if (!editing && !entry.get_selection_bounds(start, end)) {
		entry.grab_focus();
	}
	editing = true;
	return false;
}

sigc::connection URIEntry::connect_refresh(std::function<void()> handler) {
	return signal_refresh.connect(handler);
}

Browser::Browser(const std::vector<Glib::ustring>& uris) {
	// Set navigation button images.  No gtkmm constructor wraps
	// gtk_button_new_from_icon_name (due to a conflict with
	// gtk_button_new_with_label) so this must be done in the Browser
	// constructor.
	back.set_image_from_icon_name("go-previous");
	fwd.set_image_from_icon_name("go-next");
	new_tab.set_image_from_icon_name("add");

	auto histnav_style = histnav.get_style_context();
	histnav_style->add_class("raised");
	histnav_style->add_class("linked");
	histnav.add(back);
	histnav.add(fwd);
	navbar.pack_start(histnav);

	navbar.set_custom_title(nav_entry);

	new_tab.set_can_focus(false);
	new_tab.set_relief(Gtk::RELIEF_NONE);
	new_tab.show();
	navbar.pack_end(new_tab);

	navbar.set_show_close_button(true);

	auto num_uris = uris.size();
	nb.set_show_tabs(num_uris > 1);

	set_title("volo");
	set_default_size(1024, 768);
	set_titlebar(navbar);
	nb.set_scrollable();
	add(nb);

	tabs.reserve(num_uris);
	for (const auto& uri : uris) {
		open_new_tab(uri);
	}

	nav_entry.signal_uri_entered().connect([this] {
		auto uri = nav_entry.get_uri();
		guess_uri(uri);
		visable_tab.webview->load_uri(uri);
		visable_tab.webview->grab_focus();
	});
	nb.signal_switch_page().connect([this] (auto, guint page_num) {
		switch_page(page_num);
	});
	nb.signal_page_added().connect([this] (...) {
		nb.set_show_tabs(true);
	});
	nb.signal_page_removed().connect([this] (...) {
		nb.set_show_tabs(nb.get_n_pages() > 1);
	});
	new_tab.signal_clicked().connect([this] {
		auto n = open_new_tab("");
		nb.set_current_page(n);
	});

	show_webview(0, tabs.front()->wv);

	show_all_children();
}

Browser::Tab::Tab(const Glib::ustring& uri) : wv{uri}, tab_title{"New tab"} {
	tab_title.set_can_focus(false);
	tab_title.set_hexpand(true);
	tab_title.set_ellipsize(Pango::ELLIPSIZE_END);
	tab_title.set_size_request(50, -1);

	tab_close.set_image_from_icon_name("window-close");
}

int Browser::open_new_tab(const Glib::ustring& uri) {
	tabs.emplace_back(std::make_unique<Tab>(uri));
	const auto& tab = tabs.back();
	auto& wv = tab->wv;

	auto tab_content = make_managed<Gtk::Box>();
	tab_content->set_can_focus(false);
	tab_content->add(tab->tab_title);
	tab_content->add(tab->tab_close);

	wv.show_all();
	tab_content->show_all();
	const auto n = nb.append_page(wv, *tab_content);
	nb.set_tab_reorderable(wv, true);

	tab->tab_close.signal_clicked().connect([this, &tab = *tab] {
		// NOTE: This is very fast because it does not need to
		// dereference every pointer in the tabs vector, but it
		// relies on the Tab struct never being moved.  Currently
		// this holds true because moving for this type is disabled
		// (no move constructors or assignment operators exists).
		for (auto it = tabs.begin(); it != tabs.end(); ++it) {
			// Compare using pointer equality.  We intentionally
			// captured a reference to the Tab, and not the
			// vector's unique_ptr<Tab>, so that we could take the
			// address of the actual Tab object without the
			// vector's unique_ptr having been zeroed after a move.
			if (it->get() != &tab) {
				continue;
			}
			tabs.erase(it);
			break;
		}
		if (tabs.size() == 0) {
			close();
		}
	});
	wv.connect_notify_title([this, &tab = *tab] {
		// Update tab title and the window title (if this tab is
		// currently visable) with the new page title.
		auto& wv = tab.wv;
		auto c_title = webkit_web_view_get_title(wv.gobj());
		Glib::ustring title{c_title ? c_title : "(Untitled)"};
		tab.tab_title.set_text(title);
		if (visable_tab.webview == &wv) {
			set_title(title);
		}
	});

	return n;
}

void Browser::show_webview(unsigned int page_num, WebView& wv) {
	visable_tab = VisableTab{page_num, wv};

	// Update navbar/titlebar with the current state of the webview being
	// shown.
	auto c_title = webkit_web_view_get_title(wv.gobj());
	set_title(c_title ? c_title : "volo");
	update_histnav(wv);
	auto uri = wv.get_uri();
	nav_entry.set_uri(uri);

	page_signals = { {
		back.signal_clicked().connect([&wv] { wv.go_back(); }),
		fwd.signal_clicked().connect([&wv] { wv.go_forward(); }),
		wv.connect_back_forward_list_changed([this](WebKitBackForwardList *bfl) {
			if (visable_tab.bfl == bfl) {
				update_histnav(*visable_tab.webview);
			}
		}),
		wv.connect_notify_uri([this, &wv] { nav_entry.set_uri(wv.get_uri()); }),
		nav_entry.connect_refresh([&wv] {
			wv.reload();
			wv.grab_focus();
		}),
	} };

	// Grab URI entry focus if the shown tab is blank.
	//
	// TODO: If this webview is being shown by switching notebook tabs,
	// grabbing the entry focus has no effect.
	if (uri == "") {
		nav_entry.grab_focus();
	}
}

void Browser::update_histnav(WebView& wv) {
	const auto p = wv.gobj();
	back.set_sensitive(webkit_web_view_can_go_back(p));
	fwd.set_sensitive(webkit_web_view_can_go_forward(p));
}

void Browser::switch_page(unsigned int page_num) noexcept {
	// Disconnect previous WebView's signals before showing and connecting
	// the new WebView.
	for (auto& sig : page_signals) {
		sig.disconnect();
	}

	show_webview(page_num, tabs.at(page_num)->wv);
}

int main(int argc, char **argv) {
	const auto app = Gtk::Application::create(argc, argv, "org.jrick.volo");

	auto wc = WebContext::get_default();
	wc.set_process_model(WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);

	Browser b;
	return app->run(b);
}
<commit_msg>Simplify constructor calling syntax where possible.<commit_after>// Copyright (c) 2014 Josh Rickmar.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

#include <volo.h>

using namespace volo;

const std::array<Glib::ustring, 2> recognized_uri_schemes = { {
	"http://",
	"https://",
} };

// has_prefix returns whether the p is a prefix of s.
template <typename T>
bool has_prefix(T s, T p) {
	return s.size() >= p.size() && std::equal(p.begin(), p.end(), s.begin());
}

void guess_uri(Glib::ustring& uri) {
	for (auto& scheme : recognized_uri_schemes) {
		if (has_prefix(uri, scheme)) {
			return;
		}
	}
	uri = "http://" + uri;
}

WebContext WebContext::get_default() {
	return webkit_web_context_get_default();
}

void WebContext::set_process_model(WebKitProcessModel model) {
	webkit_web_context_set_process_model(wc, model);
}

static void WebView_load_changed_callback(WebKitWebView *wv,
	WebKitLoadEvent ev, gpointer signal) {

	static_cast<sigc::signal<void, WebKitLoadEvent> *>(signal)->emit(ev);
}

static void BackForwardList_changed_callback(WebKitBackForwardList *list,
	WebKitBackForwardListItem *item, gpointer removed, gpointer signal) {

	static_cast<sigc::signal<void, WebKitBackForwardList *> *>(signal)->emit(list);
}

static void WebView_notify_title_callback(GObject *, GParamSpec *, gpointer signal) {
	static_cast<sigc::signal<void> *>(signal)->emit();
}

static void WebView_notify_uri_callback(GObject *, GParamSpec *, gpointer signal) {
	static_cast<sigc::signal<void> *>(signal)->emit();
}

WebView::WebView(WebKitWebView *wv) : Gtk::Widget{reinterpret_cast<GtkWidget *>(wv)} {
	g_signal_connect(wv, "load-changed",
		G_CALLBACK(WebView_load_changed_callback),
		&signal_load_changed);

	auto bfl = webkit_web_view_get_back_forward_list(wv);
	g_signal_connect(bfl, "changed",
		G_CALLBACK(BackForwardList_changed_callback),
		&signal_back_forward_list_changed);

	g_signal_connect(wv, "notify::title",
		G_CALLBACK(WebView_notify_title_callback),
		&signal_notify_title);

	g_signal_connect(wv, "notify::uri",
		G_CALLBACK(WebView_notify_uri_callback),
		&signal_notify_uri);
}

WebView::WebView(const Glib::ustring& uri) : WebView{} {
	load_uri(uri);
}

void WebView::load_uri(const Glib::ustring& uri) {
	webkit_web_view_load_uri(gobj(), uri.c_str());
}

Glib::ustring WebView::get_uri() {
	auto uri = webkit_web_view_get_uri(gobj());
	return uri ? uri : "";
}

void WebView::reload() {
	webkit_web_view_reload(gobj());
}

void WebView::go_back() {
	webkit_web_view_go_back(gobj());
}

void WebView::go_forward() {
	webkit_web_view_go_forward(gobj());
}

sigc::connection WebView::connect_load_changed(
	std::function<void(WebKitLoadEvent)> handler) {

	return signal_load_changed.connect(handler);
}

sigc::connection WebView::connect_back_forward_list_changed(
	std::function<void(WebKitBackForwardList *)> handler) {

	return signal_back_forward_list_changed.connect(handler);
}

sigc::connection WebView::connect_notify_title(std::function<void()> handler) {
	return signal_notify_title.connect(handler);
}

sigc::connection WebView::connect_notify_uri(std::function<void()> handler) {
	return signal_notify_uri.connect(handler);
}

URIEntry::URIEntry() {
	set_size_request(600, -1); // TODO: make this dynamic with the window size
	set_margin_left(6);
	set_margin_right(6);
	entry.set_hexpand(true);

	entry.set_input_purpose(Gtk::INPUT_PURPOSE_URL);
	entry.set_icon_from_icon_name("view-refresh", Gtk::ENTRY_ICON_SECONDARY);

	entry.signal_button_release_event().connect(sigc::mem_fun(*this,
		&URIEntry::on_button_release_event), false);
	entry.property_is_focus().signal_changed().connect([this](...) {
		if (!entry.is_focus()) {
			entry.select_region(0, 0);
			editing = false;
		}
	});
	entry.signal_icon_press().connect([this](Gtk::EntryIconPosition pos, ...) {
		refresh_pressed = true;
	});
	entry.signal_icon_release().connect([this](Gtk::EntryIconPosition pos, ...) {
		if (refresh_pressed) {
			signal_refresh.emit();
		}
		refresh_pressed = false;
	});

	add(entry);

	show_all_children();
}

Glib::SignalProxy0<void> URIEntry::signal_uri_entered() {
	return entry.signal_activate();
}

Glib::ustring URIEntry::get_uri() {
	return entry.get_text();
}

void URIEntry::set_uri(const Glib::ustring& uri) {
	if (!entry.is_focus()) {
		entry.set_text(uri);
	}
}

void URIEntry::grab_focus() {
	entry.grab_focus();
}

// This can't be a lambda since we can't create sigc::slots from lambdas
// with return values.
bool URIEntry::on_button_release_event(GdkEventButton *) {
	// If the entry's refresh button was pressed, we do not set
	// editing mode to true and do not grab focus to highlight
	// all text in the entry.
	if (refresh_pressed) {
		return false;
	}

	// If the refresh button was not pressed, and we haven't previously
	// grabbed focus, do so now.  The editing flag will be unset after
	// focus leaves the entry, but until then, the text inside entry can
	// be modified and clicked without forcably selecting all of the text
	// again.
	int start, end;
	if (!editing && !entry.get_selection_bounds(start, end)) {
		entry.grab_focus();
	}
	editing = true;
	return false;
}

sigc::connection URIEntry::connect_refresh(std::function<void()> handler) {
	return signal_refresh.connect(handler);
}

Browser::Browser(const std::vector<Glib::ustring>& uris) {
	// Set navigation button images.  No gtkmm constructor wraps
	// gtk_button_new_from_icon_name (due to a conflict with
	// gtk_button_new_with_label) so this must be done in the Browser
	// constructor.
	back.set_image_from_icon_name("go-previous");
	fwd.set_image_from_icon_name("go-next");
	new_tab.set_image_from_icon_name("add");

	auto histnav_style = histnav.get_style_context();
	histnav_style->add_class("raised");
	histnav_style->add_class("linked");
	histnav.add(back);
	histnav.add(fwd);
	navbar.pack_start(histnav);

	navbar.set_custom_title(nav_entry);

	new_tab.set_can_focus(false);
	new_tab.set_relief(Gtk::RELIEF_NONE);
	new_tab.show();
	navbar.pack_end(new_tab);

	navbar.set_show_close_button(true);

	auto num_uris = uris.size();
	nb.set_show_tabs(num_uris > 1);

	set_title("volo");
	set_default_size(1024, 768);
	set_titlebar(navbar);
	nb.set_scrollable();
	add(nb);

	tabs.reserve(num_uris);
	for (const auto& uri : uris) {
		open_new_tab(uri);
	}

	nav_entry.signal_uri_entered().connect([this] {
		auto uri = nav_entry.get_uri();
		guess_uri(uri);
		visable_tab.webview->load_uri(uri);
		visable_tab.webview->grab_focus();
	});
	nb.signal_switch_page().connect([this] (auto, guint page_num) {
		switch_page(page_num);
	});
	nb.signal_page_added().connect([this] (...) {
		nb.set_show_tabs(true);
	});
	nb.signal_page_removed().connect([this] (...) {
		nb.set_show_tabs(nb.get_n_pages() > 1);
	});
	new_tab.signal_clicked().connect([this] {
		auto n = open_new_tab("");
		nb.set_current_page(n);
	});

	show_webview(0, tabs.front()->wv);

	show_all_children();
}

Browser::Tab::Tab(const Glib::ustring& uri) : wv{uri}, tab_title{"New tab"} {
	tab_title.set_can_focus(false);
	tab_title.set_hexpand(true);
	tab_title.set_ellipsize(Pango::ELLIPSIZE_END);
	tab_title.set_size_request(50, -1);

	tab_close.set_image_from_icon_name("window-close");
}

int Browser::open_new_tab(const Glib::ustring& uri) {
	tabs.emplace_back(std::make_unique<Tab>(uri));
	const auto& tab = tabs.back();
	auto& wv = tab->wv;

	auto tab_content = make_managed<Gtk::Box>();
	tab_content->set_can_focus(false);
	tab_content->add(tab->tab_title);
	tab_content->add(tab->tab_close);

	wv.show_all();
	tab_content->show_all();
	const auto n = nb.append_page(wv, *tab_content);
	nb.set_tab_reorderable(wv, true);

	tab->tab_close.signal_clicked().connect([this, &tab = *tab] {
		// NOTE: This is very fast because it does not need to
		// dereference every pointer in the tabs vector, but it
		// relies on the Tab struct never being moved.  Currently
		// this holds true because moving for this type is disabled
		// (no move constructors or assignment operators exists).
		for (auto it = tabs.begin(); it != tabs.end(); ++it) {
			// Compare using pointer equality.  We intentionally
			// captured a reference to the Tab, and not the
			// vector's unique_ptr<Tab>, so that we could take the
			// address of the actual Tab object without the
			// vector's unique_ptr having been zeroed after a move.
			if (it->get() != &tab) {
				continue;
			}
			tabs.erase(it);
			break;
		}
		if (tabs.size() == 0) {
			close();
		}
	});
	wv.connect_notify_title([this, &tab = *tab] {
		// Update tab title and the window title (if this tab is
		// currently visable) with the new page title.
		auto& wv = tab.wv;
		auto c_title = webkit_web_view_get_title(wv.gobj());
		Glib::ustring title{c_title ? c_title : "(Untitled)"};
		tab.tab_title.set_text(title);
		if (visable_tab.webview == &wv) {
			set_title(title);
		}
	});

	return n;
}

void Browser::show_webview(unsigned int page_num, WebView& wv) {
	visable_tab = {page_num, wv};

	// Update navbar/titlebar with the current state of the webview being
	// shown.
	auto c_title = webkit_web_view_get_title(wv.gobj());
	set_title(c_title ? c_title : "volo");
	update_histnav(wv);
	auto uri = wv.get_uri();
	nav_entry.set_uri(uri);

	page_signals = { {
		back.signal_clicked().connect([&wv] { wv.go_back(); }),
		fwd.signal_clicked().connect([&wv] { wv.go_forward(); }),
		wv.connect_back_forward_list_changed([this](WebKitBackForwardList *bfl) {
			if (visable_tab.bfl == bfl) {
				update_histnav(*visable_tab.webview);
			}
		}),
		wv.connect_notify_uri([this, &wv] { nav_entry.set_uri(wv.get_uri()); }),
		nav_entry.connect_refresh([&wv] {
			wv.reload();
			wv.grab_focus();
		}),
	} };

	// Grab URI entry focus if the shown tab is blank.
	//
	// TODO: If this webview is being shown by switching notebook tabs,
	// grabbing the entry focus has no effect.
	if (uri == "") {
		nav_entry.grab_focus();
	}
}

void Browser::update_histnav(WebView& wv) {
	const auto p = wv.gobj();
	back.set_sensitive(webkit_web_view_can_go_back(p));
	fwd.set_sensitive(webkit_web_view_can_go_forward(p));
}

void Browser::switch_page(unsigned int page_num) noexcept {
	// Disconnect previous WebView's signals before showing and connecting
	// the new WebView.
	for (auto& sig : page_signals) {
		sig.disconnect();
	}

	show_webview(page_num, tabs.at(page_num)->wv);
}

int main(int argc, char **argv) {
	const auto app = Gtk::Application::create(argc, argv, "org.jrick.volo");

	auto wc = WebContext::get_default();
	wc.set_process_model(WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);

	Browser b;
	return app->run(b);
}
<|endoftext|>


<commit_before><commit_msg>Fixes #5950 - While updating ByteCodeUpwardExposedUsed using bailOutOffset, when given a branching instr, do not attempt to update the branching instr's label to the next bytecode instr if the branching instr is conditional.<commit_after><|endoftext|>


<commit_before><commit_msg>nir: Don't set dest in SSBO store glsl_to_nir conversion<commit_after><|endoftext|>