<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

*******************************************************************************/

//==============================================================================
// File manager
//==============================================================================

#include "cliutils.h"
#include "filemanager.h"

//==============================================================================

#include <QApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QIODevice>
#include <QTemporaryFile>
#include <QTextStream>
#include <QTimer>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

FileManager::FileManager() :
    mActive(true),
    mFiles(QList<File *>()),
    mFilesReadable(QMap<QString, bool>()),
    mFilesWritable(QMap<QString, bool>())
{
    // Create our timer

    mTimer = new QTimer(this);

    // A connection to handle the timing out of our timer

    connect(mTimer, SIGNAL(timeout()),
            this, SLOT(checkFiles()));
}

//==============================================================================

FileManager::~FileManager()
{
    // Delete some internal objects

    delete mTimer;

    // Remove all the managed files

    foreach (File *file, mFiles)
        delete file;
}

//==============================================================================

FileManager * FileManager::instance()
{
    // Return the 'global' instance of our file manager class

    static FileManager instance;

    return static_cast<FileManager *>(Core::globalInstance("OpenCOR::Core::FileManager::instance()",
                                                           &instance));
}

//==============================================================================

FileManager::Status FileManager::manage(const QString &pFileName,
                                        const File::Type &pType,
                                        const QString &pUrl)
{
    // Manage the given file, should it not be already managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (QFile::exists(nativeFileName)) {
        if (isManaged(nativeFileName)) {
            // The file is already managed, so...

            return AlreadyManaged;
        } else {
            // The file isn't already managed, so add it to our list of managed
            // files, let people know about it being now managed

            mFiles << new File(nativeFileName, pType, pUrl);

            if (!mTimer->isActive())
                mTimer->start(1000);

            emit fileManaged(nativeFileName);

            return Added;
        }
    } else {
        // The file doesn't exist, so...

        return DoesNotExist;
    }
}

//==============================================================================

FileManager::Status FileManager::unmanage(const QString &pFileName)
{
    // Unmanage the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (QFile::exists(nativeFileName)) {
        File *file = isManaged(nativeFileName);

        if (file) {
            // The file is managed, so we can remove it

            mFiles.removeAt(mFiles.indexOf(file));

            delete file;

            if (mFiles.isEmpty())
                mTimer->stop();

            emit fileUnmanaged(nativeFileName);

            return Removed;
        } else {
            // The file isn't managed, so...

            return NotManaged;
        }
    } else {
        // The file doesn't exist, so...

        return NotManaged;
    }
}

//==============================================================================

File * FileManager::isManaged(const QString &pFileName) const
{
    // Return whether the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    foreach (File *file, mFiles)
        if (!file->fileName().compare(nativeFileName))
            // The file has been found meaning it is managed

            return file;

    // The file couldn't be found meaning it's not managed

    return 0;
}

//==============================================================================

bool FileManager::isActive() const
{
    // Return whether we are active

    return mActive;
}

//==============================================================================

void FileManager::setActive(const bool &pActive)
{
    // Set whether we are active

    mActive = pActive;
}

//==============================================================================

void FileManager::reset(const QString &pFileName)
{
    // Reset the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file)
        file->reset();
}

//==============================================================================

int FileManager::newIndex(const QString &pFileName) const
{
    // Return the given file's new index, if it is being managed

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->newIndex();
    else
        return 0;
}

//==============================================================================

QString FileManager::url(const QString &pFileName) const
{
    // Return the given file's URL, if it is being managed

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->url();
    else
        return QString();
}

//==============================================================================

bool FileManager::isNew(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is new

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isNew();
    else
        return false;
}

//==============================================================================

bool FileManager::isRemote(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is a remote one

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isRemote();
    else
        return false;
}

//==============================================================================

bool FileManager::isModified(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, has been modified

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isModified();
    else
        return false;
}

//==============================================================================

bool FileManager::isNewOrModified(const QString &pFileName) const
{
    // Return whether the given file is new or modified

    return isNew(pFileName) || isModified(pFileName);
}

//==============================================================================

void FileManager::setModified(const QString &pFileName, const bool &pModified)
{
    // Set the modified state of the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file && file->setModified(pModified))
        emit fileModified(nativeFileName, pModified);
}

//==============================================================================

bool FileManager::isReadable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is readable

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isReadable();
    else
        return false;
}

//==============================================================================

bool FileManager::isWritable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is writable

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isWritable();
    else
        return false;
}

//==============================================================================

bool FileManager::isReadableAndWritable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is readable and
    // writable

    return isReadable(pFileName) && isWritable(pFileName);
}

//==============================================================================

bool FileManager::isLocked(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is locked

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isLocked();
    else
        return false;
}

//==============================================================================

FileManager::Status FileManager::setLocked(const QString &pFileName,
                                           const bool &pLocked)
{
    // Set the locked status of the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file) {
        File::Status status = file->setLocked(pLocked);

        if (status == File::LockedSet)
            emit filePermissionsChanged(nativeFileName);

        if (status == File::LockedNotNeeded)
            return LockedNotNeeded;
        else if (status == File::LockedSet)
            return LockedSet;
        else
            return LockedNotSet;
    } else {
        return NotManaged;
    }
}

//==============================================================================

void FileManager::reload(const QString &pFileName)
{
    // Make sure that the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (isManaged(nativeFileName))
        // The file is managed, so let people know that it should be reloaded

        emit fileReloaded(nativeFileName);
}

//==============================================================================

FileManager::Status FileManager::create(const QString &pUrl,
                                        const QString &pContents)
{
    // Create a new file

    QTemporaryFile createdFile(QDir::tempPath()+QDir::separator()+QFileInfo(qApp->applicationFilePath()).baseName()+"_XXXXXX.tmp");

    if (createdFile.open()) {
        createdFile.setAutoRemove(false);
        // Note: by default, a temporary file is to autoremove itself, but we
        //       clearly don't want that here...

        QTextStream createdFileOut(&createdFile);

        createdFileOut << pContents;

        createdFile.close();

        // Let people know that we have created a file

        emit fileCreated(createdFile.fileName(), pUrl);

        return Created;
    } else {
        return NotCreated;
    }
}

//==============================================================================

FileManager::Status FileManager::rename(const QString &pOldFileName,
                                        const QString &pNewFileName)
{
    // Make sure that the given 'old' file is managed

    QString oldNativeFileName = nativeCanonicalFileName(pOldFileName);
    File *file = isManaged(oldNativeFileName);

    if (file) {
        // The 'old' file is managed, so rename it and let people know about it

        QString newNativeFileName = nativeCanonicalFileName(pNewFileName);

        if (file->setFileName(newNativeFileName)) {
            emit fileRenamed(oldNativeFileName, newNativeFileName);

            return Renamed;
        } else {
            return RenamingNotNeeded;
        }
    } else {
        return NotManaged;
    }
}

//==============================================================================

FileManager::Status FileManager::duplicate(const QString &pFileName)
{
    // Make sure that the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file) {
        // The file is managed, so retrieve its contents

        QString fileContents;

        if (Core::readTextFromFile(pFileName, fileContents)) {
            // Now, we can create a new file, which contents will be that of our
            // given file

            QTemporaryFile duplicatedFile(QDir::tempPath()+QDir::separator()+QFileInfo(qApp->applicationFilePath()).baseName()+"_XXXXXX."+QFileInfo(pFileName).completeSuffix());

            if (duplicatedFile.open()) {
                duplicatedFile.setAutoRemove(false);
                // Note: by default, a temporary file is to autoremove itself,
                //       but we clearly don't want that here...

                QTextStream duplicatedFileOut(&duplicatedFile);

                duplicatedFileOut << fileContents;

                duplicatedFile.close();

                // Let people know that we have duplicated a file

                emit fileDuplicated(duplicatedFile.fileName());

                return Duplicated;
            } else {
                return NotDuplicated;
            }
        } else {
            return NotDuplicated;
        }
    } else {
        return NotManaged;
    }
}

//==============================================================================

int FileManager::count() const
{
    // Return the number of files currently being managed

    return mFiles.count();
}

//==============================================================================

void FileManager::checkFiles()
{
    // We only want to check our files if we are active and if there is no
    // currently active dialog box

    if (!mActive || QApplication::activeModalWidget())
        return;

    // Check our various files, as well as their locked status, but only if they
    // are not being ignored

    foreach (File *file, mFiles) {
        switch (file->check()) {
            case File::Changed:
                // The file has changed, so let people know about it

                emit fileChanged(file->fileName());

                break;
            case File::Deleted:
                // The file has been deleted, so let people know about it

                emit fileDeleted(file->fileName());

                break;
            default:
                // The file is unchanged, so do nothing...

                ;
        }

        bool fileReadable = isReadable(file->fileName());
        bool fileWritable = isWritable(file->fileName());

        if (    (fileReadable != mFilesReadable.value(file->fileName(), false))
            ||  (fileWritable != mFilesWritable.value(file->fileName(), false))
            || !(   mFilesReadable.contains(file->fileName())
                 && mFilesWritable.contains(file->fileName()))) {
            emit filePermissionsChanged(file->fileName());

            mFilesReadable.insert(file->fileName(), fileReadable);
            mFilesWritable.insert(file->fileName(), fileWritable);
        }
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you 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.

*******************************************************************************/

//==============================================================================
// File manager
//==============================================================================

#include "cliutils.h"
#include "filemanager.h"

//==============================================================================

#include <QApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QIODevice>
#include <QTemporaryFile>
#include <QTextStream>
#include <QTimer>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

FileManager::FileManager() :
    mActive(true),
    mFiles(QList<File *>()),
    mFilesReadable(QMap<QString, bool>()),
    mFilesWritable(QMap<QString, bool>())
{
    // Create our timer

    mTimer = new QTimer(this);

    // A connection to handle the timing out of our timer

    connect(mTimer, SIGNAL(timeout()),
            this, SLOT(checkFiles()));
}

//==============================================================================

FileManager::~FileManager()
{
    // Delete some internal objects

    delete mTimer;

    // Remove all the managed files

    foreach (File *file, mFiles)
        delete file;
}

//==============================================================================

FileManager * FileManager::instance()
{
    // Return the 'global' instance of our file manager class

    static FileManager instance;

    return static_cast<FileManager *>(Core::globalInstance("OpenCOR::Core::FileManager::instance()",
                                                           &instance));
}

//==============================================================================

FileManager::Status FileManager::manage(const QString &pFileName,
                                        const File::Type &pType,
                                        const QString &pUrl)
{
    // Manage the given file, should it not be already managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (QFile::exists(nativeFileName)) {
        if (isManaged(nativeFileName)) {
            // The file is already managed, so...

            return AlreadyManaged;
        } else {
            // The file isn't already managed, so add it to our list of managed
            // files, let people know about it being now managed

            mFiles << new File(nativeFileName, pType, pUrl);

            if (!mTimer->isActive())
                mTimer->start(1000);

            emit fileManaged(nativeFileName);

            return Added;
        }
    } else {
        // The file doesn't exist, so...

        return DoesNotExist;
    }
}

//==============================================================================

FileManager::Status FileManager::unmanage(const QString &pFileName)
{
    // Unmanage the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (QFile::exists(nativeFileName)) {
        File *file = isManaged(nativeFileName);

        if (file) {
            // The file is managed, so we can remove it

            mFiles.removeAt(mFiles.indexOf(file));

            delete file;

            if (mFiles.isEmpty())
                mTimer->stop();

            emit fileUnmanaged(nativeFileName);

            return Removed;
        } else {
            // The file isn't managed, so...

            return NotManaged;
        }
    } else {
        // The file doesn't exist, so...

        return NotManaged;
    }
}

//==============================================================================

File * FileManager::isManaged(const QString &pFileName) const
{
    // Return whether the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    foreach (File *file, mFiles)
        if (!file->fileName().compare(nativeFileName))
            // The file has been found meaning it is managed

            return file;

    // The file couldn't be found meaning it's not managed

    return 0;
}

//==============================================================================

bool FileManager::isActive() const
{
    // Return whether we are active

    return mActive;
}

//==============================================================================

void FileManager::setActive(const bool &pActive)
{
    // Set whether we are active

    mActive = pActive;
}

//==============================================================================

void FileManager::reset(const QString &pFileName)
{
    // Reset the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file)
        file->reset();
}

//==============================================================================

int FileManager::newIndex(const QString &pFileName) const
{
    // Return the given file's new index, if it is being managed

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->newIndex();
    else
        return 0;
}

//==============================================================================

QString FileManager::url(const QString &pFileName) const
{
    // Return the given file's URL, if it is being managed

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->url();
    else
        return QString();
}

//==============================================================================

bool FileManager::isNew(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is new

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isNew();
    else
        return false;
}

//==============================================================================

bool FileManager::isRemote(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is a remote one

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isRemote();
    else
        return false;
}

//==============================================================================

bool FileManager::isModified(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, has been modified

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isModified();
    else
        return false;
}

//==============================================================================

bool FileManager::isNewOrModified(const QString &pFileName) const
{
    // Return whether the given file is new or modified

    return isNew(pFileName) || isModified(pFileName);
}

//==============================================================================

void FileManager::setModified(const QString &pFileName, const bool &pModified)
{
    // Set the modified state of the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file && file->setModified(pModified))
        emit fileModified(nativeFileName, pModified);
}

//==============================================================================

bool FileManager::isReadable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is readable

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isReadable();
    else
        return false;
}

//==============================================================================

bool FileManager::isWritable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is writable

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isWritable();
    else
        return false;
}

//==============================================================================

bool FileManager::isReadableAndWritable(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is readable and
    // writable

    return isReadable(pFileName) && isWritable(pFileName);
}

//==============================================================================

bool FileManager::isLocked(const QString &pFileName) const
{
    // Return whether the given file, if it is being managed, is locked

    File *file = isManaged(nativeCanonicalFileName(pFileName));

    if (file)
        return file->isLocked();
    else
        return false;
}

//==============================================================================

FileManager::Status FileManager::setLocked(const QString &pFileName,
                                           const bool &pLocked)
{
    // Set the locked status of the given file, should it be managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file) {
        File::Status status = file->setLocked(pLocked);

        if (status == File::LockedSet)
            emit filePermissionsChanged(nativeFileName);

        if (status == File::LockedNotNeeded)
            return LockedNotNeeded;
        else if (status == File::LockedSet)
            return LockedSet;
        else
            return LockedNotSet;
    } else {
        return NotManaged;
    }
}

//==============================================================================

void FileManager::reload(const QString &pFileName)
{
    // Make sure that the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);

    if (isManaged(nativeFileName))
        // The file is managed, so let people know that it should be reloaded

        emit fileReloaded(nativeFileName);
}

//==============================================================================

FileManager::Status FileManager::create(const QString &pUrl,
                                        const QString &pContents)
{
    // Create a new file

    QTemporaryFile createdFile(QDir::tempPath()+QDir::separator()+QFileInfo(qApp->applicationFilePath()).baseName()+"_XXXXXX.tmp");

    if (createdFile.open()) {
        createdFile.setAutoRemove(false);
        // Note: by default, a temporary file is to autoremove itself, but we
        //       clearly don't want that here...

        QTextStream createdFileOut(&createdFile);

        createdFileOut << pContents;

        createdFile.close();

        // Let people know that we have created a file

        emit fileCreated(createdFile.fileName(), pUrl);

        return Created;
    } else {
        return NotCreated;
    }
}

//==============================================================================

FileManager::Status FileManager::rename(const QString &pOldFileName,
                                        const QString &pNewFileName)
{
    // Make sure that the given 'old' file is managed

    QString oldNativeFileName = nativeCanonicalFileName(pOldFileName);
    File *file = isManaged(oldNativeFileName);

    if (file) {
        // The 'old' file is managed, so rename it and let people know about it

        QString newNativeFileName = nativeCanonicalFileName(pNewFileName);

        if (file->setFileName(newNativeFileName)) {
            emit fileRenamed(oldNativeFileName, newNativeFileName);

            return Renamed;
        } else {
            return RenamingNotNeeded;
        }
    } else {
        return NotManaged;
    }
}

//==============================================================================

FileManager::Status FileManager::duplicate(const QString &pFileName)
{
    // Make sure that the given file is managed

    QString nativeFileName = nativeCanonicalFileName(pFileName);
    File *file = isManaged(nativeFileName);

    if (file) {
        // The file is managed, so retrieve its contents

        QString fileContents;

        if (Core::readTextFromFile(pFileName, fileContents)) {
            // Now, we can create a new file, which contents will be that of our
            // given file

            QTemporaryFile duplicatedFile(QDir::tempPath()+QDir::separator()+QFileInfo(qApp->applicationFilePath()).baseName()+"_XXXXXX."+QFileInfo(pFileName).completeSuffix());

            if (duplicatedFile.open()) {
                duplicatedFile.setAutoRemove(false);
                // Note: by default, a temporary file is to autoremove itself,
                //       but we clearly don't want that here...

                QTextStream duplicatedFileOut(&duplicatedFile);

                duplicatedFileOut << fileContents;

                duplicatedFile.close();

                // Let people know that we have duplicated a file

                emit fileDuplicated(duplicatedFile.fileName());

                return Duplicated;
            } else {
                return NotDuplicated;
            }
        } else {
            return NotDuplicated;
        }
    } else {
        return NotManaged;
    }
}

//==============================================================================

int FileManager::count() const
{
    // Return the number of files currently being managed

    return mFiles.count();
}

//==============================================================================

void FileManager::checkFiles()
{
    // We only want to check our files if we are active and if there is no
    // currently active dialog box

    if (!mActive || QApplication::activeModalWidget())
        return;

    // Check our various files, as well as their locked status, but only if they
    // are not being ignored

    foreach (File *file, mFiles) {
        switch (file->check()) {
        case File::Changed:
            // The file has changed, so let people know about it

            emit fileChanged(file->fileName());

            break;
        case File::Deleted:
            // The file has been deleted, so let people know about it

            emit fileDeleted(file->fileName());

            break;
        default:
            // The file is unchanged, so do nothing...

            ;
        }

        bool fileReadable = isReadable(file->fileName());
        bool fileWritable = isWritable(file->fileName());

        if (    (fileReadable != mFilesReadable.value(file->fileName(), false))
            ||  (fileWritable != mFilesWritable.value(file->fileName(), false))
            || !(   mFilesReadable.contains(file->fileName())
                 && mFilesWritable.contains(file->fileName()))) {
            emit filePermissionsChanged(file->fileName());

            mFilesReadable.insert(file->fileName(), fileReadable);
            mFilesWritable.insert(file->fileName(), fileWritable);
        }
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>
#pragma once

#include "geometry/identity.hpp"

#include "base/mappable.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/sign.hpp"

namespace principia {
namespace geometry {
namespace internal_identity {

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame>::Identity() {}

template<typename FromFrame, typename ToFrame>
Sign Identity<FromFrame, ToFrame>::Determinant() const {
  return Sign::Positive();
}

template<typename FromFrame, typename ToFrame>
Identity<ToFrame, FromFrame> Identity<FromFrame, ToFrame>::Inverse() const {
  return Identity<ToFrame, FromFrame>();
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Vector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Vector<Scalar, FromFrame> const& vector) const {
  return Vector<Scalar, ToFrame>(vector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Bivector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Bivector<Scalar, FromFrame> const& bivector) const {
  return Bivector<Scalar, ToFrame>(bivector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Trivector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Trivector<Scalar, FromFrame> const& trivector) const {
  return Trivector<Scalar, ToFrame>(trivector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
SymmetricBilinearForm<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    SymmetricBilinearForm<Scalar, FromFrame> const& form) const {
  return SymmetricBilinearForm<Scalar, ToFrame>(form.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename T>
typename base::Mappable<Identity<FromFrame, ToFrame>, T>::type
Identity<FromFrame, ToFrame>::operator()(T const& t) const {
  return base::Mappable<Identity, T>::Do(*this, t);
}

template<typename FromFrame, typename ToFrame>
OrthogonalMap<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::Forget() const {
  return OrthogonalMap<FromFrame, ToFrame>(
      Determinant(),
      Rotation<FromFrame, ToFrame>::Identity());
}

template<typename FromFrame, typename ToFrame>
void Identity<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::LinearMap*> const message) const {
  LinearMap<FromFrame, ToFrame>::WriteToMessage(message);
  WriteToMessage(message->MutableExtension(serialization::Identity::extension));
}

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::ReadFromMessage(
    serialization::LinearMap const& message) {
  LinearMap<FromFrame, ToFrame>::ReadFromMessage(message);
  CHECK(message.HasExtension(serialization::Identity::extension));
  return ReadFromMessage(
      message.GetExtension(serialization::Identity::extension));
}

template<typename FromFrame, typename ToFrame>
void Identity<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::Identity*> const message) const {}

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::ReadFromMessage(
    serialization::Identity const& message) {
  return Identity();
}

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
Identity<FromFrame, ToFrame> operator*(
    Identity<ThroughFrame, ToFrame> const& left,
    Identity<FromFrame, ThroughFrame> const& right) {
  return Identity<FromFrame, ToFrame>();
}

template<typename FromFrame, typename ToFrame>
std::ostream& operator<<(std::ostream& out,
                         Identity<FromFrame, ToFrame> const& identity) {
  return out << "𝟙";
}

}  // namespace internal_identity
}  // namespace geometry
}  // namespace principia
<commit_msg>After egg's review.<commit_after>
#pragma once

#include "geometry/identity.hpp"

#include "base/mappable.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/sign.hpp"

namespace principia {
namespace geometry {
namespace internal_identity {

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame>::Identity() {}

template<typename FromFrame, typename ToFrame>
Sign Identity<FromFrame, ToFrame>::Determinant() const {
  return Sign::Positive();
}

template<typename FromFrame, typename ToFrame>
Identity<ToFrame, FromFrame> Identity<FromFrame, ToFrame>::Inverse() const {
  return Identity<ToFrame, FromFrame>();
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Vector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Vector<Scalar, FromFrame> const& vector) const {
  return Vector<Scalar, ToFrame>(vector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Bivector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Bivector<Scalar, FromFrame> const& bivector) const {
  return Bivector<Scalar, ToFrame>(bivector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Trivector<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    Trivector<Scalar, FromFrame> const& trivector) const {
  return Trivector<Scalar, ToFrame>(trivector.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
SymmetricBilinearForm<Scalar, ToFrame> Identity<FromFrame, ToFrame>::operator()(
    SymmetricBilinearForm<Scalar, FromFrame> const& form) const {
  return SymmetricBilinearForm<Scalar, ToFrame>(form.coordinates());
}

template<typename FromFrame, typename ToFrame>
template<typename T>
typename base::Mappable<Identity<FromFrame, ToFrame>, T>::type
Identity<FromFrame, ToFrame>::operator()(T const& t) const {
  return base::Mappable<Identity, T>::Do(*this, t);
}

template<typename FromFrame, typename ToFrame>
OrthogonalMap<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::Forget() const {
  return OrthogonalMap<FromFrame, ToFrame>(
      Determinant(),
      Rotation<FromFrame, ToFrame>::Identity());
}

template<typename FromFrame, typename ToFrame>
void Identity<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::LinearMap*> const message) const {
  LinearMap<FromFrame, ToFrame>::WriteToMessage(message);
  WriteToMessage(message->MutableExtension(serialization::Identity::extension));
}

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::ReadFromMessage(
    serialization::LinearMap const& message) {
  LinearMap<FromFrame, ToFrame>::ReadFromMessage(message);
  CHECK(message.HasExtension(serialization::Identity::extension));
  return ReadFromMessage(
      message.GetExtension(serialization::Identity::extension));
}

template<typename FromFrame, typename ToFrame>
void Identity<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::Identity*> const message) const {}

template<typename FromFrame, typename ToFrame>
Identity<FromFrame, ToFrame> Identity<FromFrame, ToFrame>::ReadFromMessage(
    serialization::Identity const& message) {
  return Identity();
}

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
Identity<FromFrame, ToFrame> operator*(
    Identity<ThroughFrame, ToFrame> const& left,
    Identity<FromFrame, ThroughFrame> const& right) {
  return Identity<FromFrame, ToFrame>();
}

template<typename FromFrame, typename ToFrame>
std::ostream& operator<<(std::ostream& out,
                         Identity<FromFrame, ToFrame> const& identity) {
  return out << u8"𝟙";
}

}  // namespace internal_identity
}  // namespace geometry
}  // namespace principia
<|endoftext|>


<commit_before>// Copyright 2008, 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.

#include "chrome/common/rand_util.h"

#include <stdlib.h>
#include <time.h>

#include "base/logging.h"
#include "base/thread_local_storage.h"
#include "base/win_util.h"

namespace rand_util {

// Using TLS since srand() needs to be called once in each thread.
int g_tls_index = ThreadLocalStorage::Alloc();

int RandInt(int min, int max) {
  if (ThreadLocalStorage::Get(g_tls_index) == 0) {
    ThreadLocalStorage::Set(g_tls_index, reinterpret_cast<void*>(1));
    srand(static_cast<unsigned int>(time(0)));
  }

  // From the rand man page, use this instead of just rand() % max, so that the
  // higher bits are used.
  return min + static_cast<int>(static_cast<double>(max - min + 1) *
    (::rand() / (RAND_MAX + 1.0)));
}

int RandIntSecure(int min, int max) {
  if (win_util::GetWinVersion() < win_util::WINVERSION_XP) {
    // rand_s needs XP and later.
    return RandInt(min, max);
  }

  unsigned int number;
  errno_t rv = rand_s(&number);
  DCHECK(rv == 0) << "rand_s failed with error " << rv;

  // From the rand man page, use this instead of just rand() % max, so that the
  // higher bits are used.
  return min + static_cast<int>(static_cast<double>(max - min + 1.0) *
      (number / (UINT_MAX + 1.0)));
}

}  // namespace rand_util
<commit_msg>Using a better seed.  Using time() causes the random sequence to start with the same number when run several times consecutively.<commit_after>// Copyright 2008, 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.

#include "chrome/common/rand_util.h"

#include <stdlib.h>
#include <time.h>

#include "base/logging.h"
#include "base/thread_local_storage.h"
#include "base/time.h"
#include "base/win_util.h"

namespace rand_util {

// Using TLS since srand() needs to be called once in each thread.
int g_tls_index = ThreadLocalStorage::Alloc();

int RandInt(int min, int max) {
  if (ThreadLocalStorage::Get(g_tls_index) == 0) {
    ThreadLocalStorage::Set(g_tls_index, reinterpret_cast<void*>(1));
    TimeDelta now = TimeTicks::UnreliableHighResNow() - TimeTicks();
    unsigned int seed = static_cast<unsigned int>(now.InMicroseconds());
    srand(seed);
  }

  // From the rand man page, use this instead of just rand() % max, so that the
  // higher bits are used.
  return min + static_cast<int>(static_cast<double>(max - min + 1) *
    (::rand() / (RAND_MAX + 1.0)));
}

int RandIntSecure(int min, int max) {
  if (win_util::GetWinVersion() < win_util::WINVERSION_XP) {
    // rand_s needs XP and later.
    return RandInt(min, max);
  }

  unsigned int number;
  errno_t rv = rand_s(&number);
  DCHECK(rv == 0) << "rand_s failed with error " << rv;

  // From the rand man page, use this instead of just rand() % max, so that the
  // higher bits are used.
  return min + static_cast<int>(static_cast<double>(max - min + 1.0) *
      (number / (UINT_MAX + 1.0)));
}

}  // namespace rand_util
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
	@brief  メイン @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "ignitor.hpp"

typedef app::ignitor start_app;

static const char* window_key_ = { "application/window" };
static const char* app_title_ = { "ignitor app" };
static const vtx::spos start_pos_(10, 40);
static const vtx::spos start_size_(1400, 840);
static const vtx::spos limit_size_(1400, 840);

int main(int argc, char** argv)
{
	gl::core& core = gl::core::get_instance();

	if(!core.initialize(argc, argv)) {
		std::cerr << "Core initialize error" << std::endl;
		return -1;
	}

	std::string pref = core.get_exec_path();
	pref += ".pre";

	utils::director<app::core> director;

	director.at().preference_.load(pref);

	vtx::srect rect(start_pos_, start_size_);
	if(!director.at().preference_.load_rect(window_key_, rect)) {
//		std::cerr << "Load preference error: '" << window_key_ << "'" << std::endl;
	}

	if(!core.setup(rect, app_title_, false)) {
		std::cerr << "Core setup error" << std::endl;
		return -1;
	}
	core.set_limit_size(limit_size_);

//	director.at().sound_.initialize(16);

	director.at().widget_director_.initialize();

	director.install_scene<start_app>();

	while(!core.get_exit_signal()) {
		core.service();

		glClearColor(0, 0, 0, 255);
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		gl::glColor(img::rgbaf(1.0f));

		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glDisable(GL_DEPTH_TEST);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		director.render();

		core.flip_frame();

//		director.at().sound_.service();
	}
	// プログラム終了の廃棄
	director.erase_scene();
	director.render();

	{
		const vtx::srect& rect = core.get_rect();
		director.at().preference_.save_rect(window_key_, rect);
	}

	director.at().preference_.save(pref);

	core.destroy();
}
<commit_msg>update: start windows size<commit_after>//=====================================================================//
/*! @file
	@brief  メイン @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "ignitor.hpp"

typedef app::ignitor start_app;

static const char* window_key_ = { "application/window" };
static const char* app_title_ = { "ignitor app" };
static const vtx::spos start_pos_(10, 40);
static const vtx::spos start_size_(1550, 840);
static const vtx::spos limit_size_(1550, 840);

int main(int argc, char** argv)
{
	gl::core& core = gl::core::get_instance();

	if(!core.initialize(argc, argv)) {
		std::cerr << "Core initialize error" << std::endl;
		return -1;
	}

	std::string pref = core.get_exec_path();
	pref += ".pre";

	utils::director<app::core> director;

	director.at().preference_.load(pref);

	vtx::srect rect(start_pos_, start_size_);
	if(!director.at().preference_.load_rect(window_key_, rect)) {
//		std::cerr << "Load preference error: '" << window_key_ << "'" << std::endl;
	}

	if(!core.setup(rect, app_title_, false)) {
		std::cerr << "Core setup error" << std::endl;
		return -1;
	}
	core.set_limit_size(limit_size_);

//	director.at().sound_.initialize(16);

	director.at().widget_director_.initialize();

	director.install_scene<start_app>();

	while(!core.get_exit_signal()) {
		core.service();

		glClearColor(0, 0, 0, 255);
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		gl::glColor(img::rgbaf(1.0f));

		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glDisable(GL_DEPTH_TEST);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		director.render();

		core.flip_frame();

//		director.at().sound_.service();
	}
	// プログラム終了の廃棄
	director.erase_scene();
	director.render();

	{
		const vtx::srect& rect = core.get_rect();
		director.at().preference_.save_rect(window_key_, rect);
	}

	director.at().preference_.save(pref);

	core.destroy();
}
<|endoftext|>


<commit_before>#include "imagefetcher.h"
using namespace AhoViewer::Booru;

int ImageFetcher::socket_cb(CURL*, curl_socket_t s, int action, void *userp, void *sockp)
{
    ImageFetcher *self = static_cast<ImageFetcher*>(userp);
    SockInfo *fdp = static_cast<SockInfo*>(sockp);

    if (action == CURL_POLL_REMOVE && fdp)
    {
        delete fdp;
    }
    else
    {
        if (!fdp)
        {
            fdp = new SockInfo();
            fdp->chan = Glib::IOChannel::create_from_fd(s);
            curl_multi_assign(self->m_MultiHandle, s, fdp);
        }

        Glib::IOCondition kind;
        if (action & CURL_POLL_IN)  kind |= Glib::IO_IN;
        if (action & CURL_POLL_OUT) kind |= Glib::IO_OUT;

        Glib::RefPtr<Glib::IOSource> source = fdp->chan->create_watch(kind);
        fdp->sockfd = s;

        if (fdp->conn)
            fdp->conn.disconnect();

        fdp->conn = source->connect(sigc::bind<0>(sigc::mem_fun(self, &ImageFetcher::event_cb), s));
        source->attach(self->m_MainContext);
    }

    return 0;
}

int ImageFetcher::timer_cb(CURLM*, long timeout_ms, void *userp)
{
    ImageFetcher *self = static_cast<ImageFetcher*>(userp);

    self->m_TimeoutConn = self->m_MainContext->signal_timeout().connect(
            sigc::mem_fun(self, &ImageFetcher::timeout_cb), timeout_ms);

    return 0;
}

ImageFetcher::ImageFetcher()
  : m_MainContext(Glib::MainContext::create()),
    m_MainLoop(Glib::MainLoop::create(m_MainContext)),
    m_MultiHandle(curl_multi_init()),
    m_RunningHandles(0)
{
    m_Thread = std::thread([ this ]() { m_MainLoop->run(); });

    curl_multi_setopt(m_MultiHandle, CURLMOPT_SOCKETFUNCTION, &ImageFetcher::socket_cb);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_SOCKETDATA, this);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_TIMERFUNCTION, &ImageFetcher::timer_cb);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_TIMERDATA, this);
}

ImageFetcher::~ImageFetcher()
{
    m_MainLoop->quit();
    m_Thread.join();

    for (Curler *c : m_Curlers)
        remove_handle(c);

    curl_multi_cleanup(m_MultiHandle);
}

void ImageFetcher::add_handle(Curler *curler)
{
    std::lock_guard<std::mutex> lock(m_Mutex);

    curl_easy_setopt(curler->m_EasyHandle, CURLOPT_PRIVATE, curler);

    curler->m_Cancel->reset();
    curler->clear();

    m_Curlers.push_back(curler);
    curl_multi_add_handle(m_MultiHandle, curler->m_EasyHandle);

    curler->m_Active = true;
    curler->m_StartTime = std::chrono::steady_clock::now();
}

void ImageFetcher::remove_handle(Curler *curler)
{
    if (!curler)
        return;

    if (curler->m_EasyHandle)
        curl_multi_remove_handle(m_MultiHandle, curler->m_EasyHandle);

    m_Curlers.erase(std::remove(m_Curlers.begin(), m_Curlers.end(), curler), m_Curlers.end());

    curler->m_Active = false;
}

bool ImageFetcher::event_cb(curl_socket_t sockfd, Glib::IOCondition cond)
{
    int action = (cond & Glib::IO_IN ? CURL_CSELECT_IN : 0) |
                 (cond & Glib::IO_OUT ? CURL_CSELECT_OUT : 0);

    curl_multi_socket_action(m_MultiHandle, sockfd, action, &m_RunningHandles);
    read_info();

    if (m_RunningHandles == 0)
    {
        m_TimeoutConn.disconnect();
        return false;
    }

    return true;
}

bool ImageFetcher::timeout_cb()
{
    curl_multi_socket_action(m_MultiHandle, CURL_SOCKET_TIMEOUT, 0, &m_RunningHandles);
    read_info();

    return false;
}

void ImageFetcher::read_info()
{
    int msgs;
    CURLMsg *msg = nullptr;

    while ((msg = curl_multi_info_read(m_MultiHandle, &msgs)))
    {
        if (msg->msg == CURLMSG_DONE)
        {
            Curler *curler = nullptr;
            curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &curler);

            if (curler)
            {
                remove_handle(curler);

                if (!curler->is_cancelled())
                    curler->m_SignalFinished();
            }
        }
    }
}
<commit_msg>Revert "booru/imagefetcher: Remove unneeded mutex locks"<commit_after>#include "imagefetcher.h"
using namespace AhoViewer::Booru;

int ImageFetcher::socket_cb(CURL*, curl_socket_t s, int action, void *userp, void *sockp)
{
    ImageFetcher *self = static_cast<ImageFetcher*>(userp);
    SockInfo *fdp = static_cast<SockInfo*>(sockp);

    if (action == CURL_POLL_REMOVE && fdp)
    {
        delete fdp;
    }
    else
    {
        if (!fdp)
        {
            fdp = new SockInfo();
            fdp->chan = Glib::IOChannel::create_from_fd(s);
            curl_multi_assign(self->m_MultiHandle, s, fdp);
        }

        Glib::IOCondition kind;
        if (action & CURL_POLL_IN)  kind |= Glib::IO_IN;
        if (action & CURL_POLL_OUT) kind |= Glib::IO_OUT;

        Glib::RefPtr<Glib::IOSource> source = fdp->chan->create_watch(kind);
        fdp->sockfd = s;

        if (fdp->conn)
            fdp->conn.disconnect();

        fdp->conn = source->connect(sigc::bind<0>(sigc::mem_fun(self, &ImageFetcher::event_cb), s));
        source->attach(self->m_MainContext);
    }

    return 0;
}

int ImageFetcher::timer_cb(CURLM*, long timeout_ms, void *userp)
{
    ImageFetcher *self = static_cast<ImageFetcher*>(userp);

    self->m_TimeoutConn = self->m_MainContext->signal_timeout().connect(
            sigc::mem_fun(self, &ImageFetcher::timeout_cb), timeout_ms);

    return 0;
}

ImageFetcher::ImageFetcher()
  : m_MainContext(Glib::MainContext::create()),
    m_MainLoop(Glib::MainLoop::create(m_MainContext)),
    m_MultiHandle(curl_multi_init()),
    m_RunningHandles(0)
{
    m_Thread = std::thread([ this ]() { m_MainLoop->run(); });

    curl_multi_setopt(m_MultiHandle, CURLMOPT_SOCKETFUNCTION, &ImageFetcher::socket_cb);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_SOCKETDATA, this);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_TIMERFUNCTION, &ImageFetcher::timer_cb);
    curl_multi_setopt(m_MultiHandle, CURLMOPT_TIMERDATA, this);
}

ImageFetcher::~ImageFetcher()
{
    std::lock_guard<std::mutex> lock(m_Mutex);

    m_MainLoop->quit();
    m_Thread.join();

    for (Curler *c : m_Curlers)
        remove_handle(c);

    curl_multi_cleanup(m_MultiHandle);
}

void ImageFetcher::add_handle(Curler *curler)
{
    std::lock_guard<std::mutex> lock(m_Mutex);

    curl_easy_setopt(curler->m_EasyHandle, CURLOPT_PRIVATE, curler);

    curler->m_Cancel->reset();
    curler->clear();

    m_Curlers.push_back(curler);
    curl_multi_add_handle(m_MultiHandle, curler->m_EasyHandle);

    curler->m_Active = true;
    curler->m_StartTime = std::chrono::steady_clock::now();
}

void ImageFetcher::remove_handle(Curler *curler)
{
    if (!curler)
        return;

    if (curler->m_EasyHandle)
        curl_multi_remove_handle(m_MultiHandle, curler->m_EasyHandle);

    m_Curlers.erase(std::remove(m_Curlers.begin(), m_Curlers.end(), curler), m_Curlers.end());

    curler->m_Active = false;
}

bool ImageFetcher::event_cb(curl_socket_t sockfd, Glib::IOCondition cond)
{
    int action = (cond & Glib::IO_IN ? CURL_CSELECT_IN : 0) |
                 (cond & Glib::IO_OUT ? CURL_CSELECT_OUT : 0);

    {
        std::lock_guard<std::mutex> lock(m_Mutex);
        curl_multi_socket_action(m_MultiHandle, sockfd, action, &m_RunningHandles);
    }
    read_info();

    if (m_RunningHandles == 0)
    {
        m_TimeoutConn.disconnect();
        return false;
    }

    return true;
}

bool ImageFetcher::timeout_cb()
{
    curl_multi_socket_action(m_MultiHandle, CURL_SOCKET_TIMEOUT, 0, &m_RunningHandles);
    read_info();

    return false;
}

void ImageFetcher::read_info()
{
    int msgs;
    CURLMsg *msg = nullptr;
    std::lock_guard<std::mutex> lock(m_Mutex);

    while ((msg = curl_multi_info_read(m_MultiHandle, &msgs)))
    {
        if (msg->msg == CURLMSG_DONE)
        {
            Curler *curler = nullptr;
            curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &curler);

            if (curler)
            {
                remove_handle(curler);

                if (!curler->is_cancelled())
                    curler->m_SignalFinished();
            }
        }
    }
}
<|endoftext|>


<commit_before>#include "processor/external_symbol_supplier.h"

#include <sys/wait.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include "google_breakpad/processor/code_module.h"
#include "processor/logging.h"

using std::stringstream;

namespace google_breakpad {

ExternalSymbolSupplier::ExternalSymbolSupplier(const string& fetch_command)
  : symbol_fetch_command_(fetch_command) {
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetSymbolFile(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file) {
  BPLOG_ERROR << "GetSymbolFile() is not implemented";
  return INTERRUPT;
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetSymbolFile(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file,
                                       string *symbol_data) {
  BPLOG_ERROR << "GetSymbolFile() is not implemented";
  return INTERRUPT;
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetCStringSymbolData(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file,
                                       char **symbol_data) {
  // search for already-loaded debug info
  map<string,string>::const_iterator it = symbol_cache_.find(module->code_file());
  if (it != symbol_cache_.end()) {
    const std::string& content = it->second;
    if (content.empty()) {
      // debug info has been requested before but was not found previously
      return NOT_FOUND;
    } else {
      *symbol_data = const_cast<char*>(content.data());
      return FOUND;
    }
  }

  // run external command to fetch debug info
  stringstream symbol_content;
  stringstream fetch_command;
  fetch_command << symbol_fetch_command_ << " " << module->debug_file() << " " << module->debug_identifier();
  FILE *child_proc = popen(fetch_command.str().data(), "r");
  if (!child_proc) {
    BPLOG_ERROR << "Failed to start symbol fetcher " << fetch_command.str();
    return INTERRUPT;
  }

  const int BUF_SIZE = 4096;
  char buffer[BUF_SIZE];
  while (!feof(child_proc)) {
    size_t nread = fread(buffer, 1, BUF_SIZE, child_proc);
    symbol_content.write(buffer, nread);
  }
  int status = pclose(child_proc);
  if (!WIFEXITED(status)) {
    BPLOG_INFO << fetch_command.str() << " failed";
    return INTERRUPT;
  }

  int exitCode = WEXITSTATUS(status);
  if (exitCode == 127) {
    // command not found
    BPLOG_INFO << "Failed to run symbol fetch command: " << fetch_command.str();
    return INTERRUPT;
  }

  if (exitCode != 0) {
    // no matching debug info found,
    // cache the omission to avoid repeated lookups for the same module
    symbol_cache_[module->code_file()] = std::string();
    BPLOG_INFO << "No symbols found with " << fetch_command.str() << " (status: " << exitCode << ")";
    return NOT_FOUND;
  }

  // cache and return debug info
  symbol_cache_[module->code_file()] = symbol_content.str();
  return GetCStringSymbolData(module, system_info, symbol_file, symbol_data);
}

void ExternalSymbolSupplier::FreeSymbolData(const CodeModule *module) {
  map<string,string>::iterator it = symbol_cache_.find(module->code_file());
  if (it != symbol_cache_.end()) {
    symbol_cache_.erase(it);
  }
}

}

<commit_msg>Fix passing of module names to external symbol fetchers on Windows<commit_after>#include "processor/external_symbol_supplier.h"

#include <sys/wait.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include "google_breakpad/processor/code_module.h"
#include "processor/logging.h"

using std::stringstream;

namespace google_breakpad {

ExternalSymbolSupplier::ExternalSymbolSupplier(const string& fetch_command)
  : symbol_fetch_command_(fetch_command) {
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetSymbolFile(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file) {
  BPLOG_ERROR << "GetSymbolFile() is not implemented";
  return INTERRUPT;
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetSymbolFile(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file,
                                       string *symbol_data) {
  BPLOG_ERROR << "GetSymbolFile() is not implemented";
  return INTERRUPT;
}

std::string ShellEscape(const std::string& arg)
{
  std::string result = "'";
  for (int i=0; i < arg.size(); i++) {
    if (arg[i] == '\'') {
      result += '\\';
    }
    result += arg[i];
  }
  result += "'";
  return result;
}

// Returns the part of 'path' following the final trailing slash.
//
// To support both Windows and Unix minidump paths, both '\' and '/'
// are considered path component separators.
std::string FileBasename(const std::string& path)
{
  int basename_start_pos = path.size();
  while (basename_start_pos > 0) {
    if (path[basename_start_pos-1] == '/' ||
        path[basename_start_pos-1] == '\\') {
      break;
    }
    --basename_start_pos;
  }
  return path.substr(basename_start_pos);
}

SymbolSupplier::SymbolResult ExternalSymbolSupplier::GetCStringSymbolData(const CodeModule *module,
                                       const SystemInfo *system_info,
                                       string *symbol_file,
                                       char **symbol_data) {
  // search for already-loaded debug info
  map<string,string>::const_iterator it = symbol_cache_.find(module->code_file());
  if (it != symbol_cache_.end()) {
    const std::string& content = it->second;
    if (content.empty()) {
      // debug info has been requested before but was not found previously
      return NOT_FOUND;
    } else {
      *symbol_data = const_cast<char*>(content.data());
      return FOUND;
    }
  }

  // run external command to fetch debug info
  std::string debug_file_basename = FileBasename(module->debug_file());
  stringstream symbol_content;
  stringstream fetch_command;
  fetch_command << symbol_fetch_command_ << " " << ShellEscape(debug_file_basename) << " " << ShellEscape(module->debug_identifier());
  FILE *child_proc = popen(fetch_command.str().data(), "r");
  if (!child_proc) {
    BPLOG_ERROR << "Failed to start symbol fetcher " << fetch_command.str();
    return INTERRUPT;
  }

  const int BUF_SIZE = 4096;
  char buffer[BUF_SIZE];
  while (!feof(child_proc)) {
    size_t nread = fread(buffer, 1, BUF_SIZE, child_proc);
    symbol_content.write(buffer, nread);
  }
  int status = pclose(child_proc);
  if (!WIFEXITED(status)) {
    BPLOG_INFO << fetch_command.str() << " failed";
    return INTERRUPT;
  }

  int exitCode = WEXITSTATUS(status);
  if (exitCode == 127) {
    // command not found
    BPLOG_INFO << "Failed to run symbol fetch command: " << fetch_command.str();
    return INTERRUPT;
  }

  if (exitCode != 0) {
    // no matching debug info found,
    // cache the omission to avoid repeated lookups for the same module
    symbol_cache_[module->code_file()] = std::string();
    BPLOG_INFO << "No symbols found with " << fetch_command.str() << " (status: " << exitCode << ")";
    return NOT_FOUND;
  }

  // cache and return debug info
  symbol_cache_[module->code_file()] = symbol_content.str();
  return GetCStringSymbolData(module, system_info, symbol_file, symbol_data);
}

void ExternalSymbolSupplier::FreeSymbolData(const CodeModule *module) {
  map<string,string>::iterator it = symbol_cache_.find(module->code_file());
  if (it != symbol_cache_.end()) {
    symbol_cache_.erase(it);
  }
}

}

<|endoftext|>


<commit_before>/*
    Copyright 2011 Google Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

#include "GrGLInterface.h"

#include <Windows.h>
#include <GL/GL.h>

/*
 * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
 * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
 * Otherwise, a springboard would be needed that hides the calling convention.
 */

#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);

void GrGLSetDefaultGLInterface() {
    static GrGLInterface gDefaultInterface;
    static bool gDefaultInterfaceInit;
    if (!gDefaultInterfaceInit) {

        // wglGetProcAddress requires a context.
        if (NULL != wglGetCurrentContext()) {
            int major, minor;
            const char* versionString = (const char*) glGetString(GL_VERSION);
            const char* extString = (const char*) glGetString(GL_EXTENSIONS);
            gl_version_from_string(&major, &minor, versionString);

            if (major == 1 && minor < 5) {
                // We must have array and element_array buffer objects.
                return;
            }

            // Functions that are part of GL 1.1 will return NULL in
            // wglGetProcAddress
            gDefaultInterface.fBlendFunc = glBlendFunc;
            gDefaultInterface.fClear = glClear;
            gDefaultInterface.fClearColor = glClearColor;
            gDefaultInterface.fClearStencil = glClearStencil;
            gDefaultInterface.fColor4ub = glColor4ub;
            gDefaultInterface.fColorMask = glColorMask;
            gDefaultInterface.fColorPointer = glColorPointer;
            gDefaultInterface.fCullFace = glCullFace;
            gDefaultInterface.fDeleteTextures = glDeleteTextures;
            gDefaultInterface.fDepthMask = glDepthMask;
            gDefaultInterface.fDisable = glDisable;
            gDefaultInterface.fDisableClientState = glDisableClientState;
            gDefaultInterface.fDrawArrays = glDrawArrays;
            gDefaultInterface.fDrawElements = glDrawElements;
            gDefaultInterface.fEnable = glEnable;
            gDefaultInterface.fEnableClientState = glEnableClientState;
            gDefaultInterface.fFrontFace = glFrontFace;
            gDefaultInterface.fGenTextures = glGenTextures;
            gDefaultInterface.fGetError = glGetError;
            gDefaultInterface.fGetIntegerv = glGetIntegerv;
            gDefaultInterface.fGetString = glGetString;
            gDefaultInterface.fLineWidth = glLineWidth;
            gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
            gDefaultInterface.fMatrixMode = glMatrixMode;
            gDefaultInterface.fPixelStorei = glPixelStorei;
            gDefaultInterface.fPointSize = glPointSize;
            gDefaultInterface.fReadPixels = glReadPixels;
            gDefaultInterface.fScissor = glScissor;
            gDefaultInterface.fShadeModel = glShadeModel;
            gDefaultInterface.fStencilFunc = glStencilFunc;
            gDefaultInterface.fStencilMask = glStencilMask;
            gDefaultInterface.fStencilOp = glStencilOp;
            gDefaultInterface.fTexImage2D = glTexImage2D;
            gDefaultInterface.fTexParameteri = glTexParameteri;
            gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
            gDefaultInterface.fTexEnvi = glTexEnvi;
            gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
            gDefaultInterface.fViewport = glViewport;
            gDefaultInterface.fVertexPointer = glVertexPointer;

            GR_GL_GET_PROC(ActiveTexture);
            GR_GL_GET_PROC(AttachShader);
            GR_GL_GET_PROC(BindAttribLocation);
            GR_GL_GET_PROC(BindBuffer);
            GR_GL_GET_PROC(BindTexture);
            GR_GL_GET_PROC(BlendColor);
            GR_GL_GET_PROC(BufferData);
            GR_GL_GET_PROC(BufferSubData);
            GR_GL_GET_PROC(ClientActiveTexture);
            GR_GL_GET_PROC(CompileShader);
            GR_GL_GET_PROC(CompressedTexImage2D);
            GR_GL_GET_PROC(CreateProgram);
            GR_GL_GET_PROC(CreateShader);
            GR_GL_GET_PROC(DeleteBuffers);
            GR_GL_GET_PROC(DeleteProgram);
            GR_GL_GET_PROC(DeleteShader);
            GR_GL_GET_PROC(DisableVertexAttribArray);
            GR_GL_GET_PROC(EnableVertexAttribArray);
            GR_GL_GET_PROC(GenBuffers);
            GR_GL_GET_PROC(GetBufferParameteriv);
            GR_GL_GET_PROC(GetProgramInfoLog);
            GR_GL_GET_PROC(GetProgramiv);
            GR_GL_GET_PROC(GetShaderInfoLog);
            GR_GL_GET_PROC(GetShaderiv);
            GR_GL_GET_PROC(GetUniformLocation);
            GR_GL_GET_PROC(LinkProgram);
            GR_GL_GET_PROC(ShaderSource);
            GR_GL_GET_PROC(StencilFuncSeparate);
            GR_GL_GET_PROC(StencilMaskSeparate);
            GR_GL_GET_PROC(StencilOpSeparate);
            GR_GL_GET_PROC(Uniform1fv);
            GR_GL_GET_PROC(Uniform1i);
            GR_GL_GET_PROC(Uniform4fv);
            GR_GL_GET_PROC(UniformMatrix3fv);
            GR_GL_GET_PROC(UseProgram);
            GR_GL_GET_PROC(VertexAttrib4fv);
            GR_GL_GET_PROC(VertexAttribPointer);

            // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
            // GL_ARB_framebuffer_object doesn't use ARB suffix.)
            if (major >= 3 || has_gl_extension("GL_ARB_framebuffer_object")) {
                GR_GL_GET_PROC(GenFramebuffers);
                GR_GL_GET_PROC(BindFramebuffer);
                GR_GL_GET_PROC(FramebufferTexture2D);
                GR_GL_GET_PROC(CheckFramebufferStatus);
                GR_GL_GET_PROC(DeleteFramebuffers);
                GR_GL_GET_PROC(RenderbufferStorage);
                GR_GL_GET_PROC(GenRenderbuffers);
                GR_GL_GET_PROC(DeleteRenderbuffers);
                GR_GL_GET_PROC(FramebufferRenderbuffer);
                GR_GL_GET_PROC(BindRenderbuffer);
                GR_GL_GET_PROC(RenderbufferStorageMultisample);
                GR_GL_GET_PROC(BlitFramebuffer);
            } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object",
                                                    extString)) {
                GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
                GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
                GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
                GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
                GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
                GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
                if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
                                                 extString)) {
                    GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
                }
                if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
                                                 extString)) {
                    GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
                }
            } else {
                // we must have FBOs
                return;
            }
            GR_GL_GET_PROC(MapBuffer);
            GR_GL_GET_PROC(UnmapBuffer);

            gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;

            gDefaultInterfaceInit = true;
        }
    }
    if (gDefaultInterfaceInit) {
        GrGLSetGLInterface(&gDefaultInterface);
    }
}
<commit_msg>Use has_gl_extension_from_string in GrGLDefaultInterface_win.cpp (before the GL iface is installed).<commit_after>/*
    Copyright 2011 Google Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

#include "GrGLInterface.h"

#include <Windows.h>
#include <GL/GL.h>

/*
 * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
 * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
 * Otherwise, a springboard would be needed that hides the calling convention.
 */

#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);

void GrGLSetDefaultGLInterface() {
    static GrGLInterface gDefaultInterface;
    static bool gDefaultInterfaceInit;
    if (!gDefaultInterfaceInit) {

        // wglGetProcAddress requires a context.
        if (NULL != wglGetCurrentContext()) {
            int major, minor;
            const char* versionString = (const char*) glGetString(GL_VERSION);
            const char* extString = (const char*) glGetString(GL_EXTENSIONS);
            gl_version_from_string(&major, &minor, versionString);

            if (major == 1 && minor < 5) {
                // We must have array and element_array buffer objects.
                return;
            }

            // Functions that are part of GL 1.1 will return NULL in
            // wglGetProcAddress
            gDefaultInterface.fBlendFunc = glBlendFunc;
            gDefaultInterface.fClear = glClear;
            gDefaultInterface.fClearColor = glClearColor;
            gDefaultInterface.fClearStencil = glClearStencil;
            gDefaultInterface.fColor4ub = glColor4ub;
            gDefaultInterface.fColorMask = glColorMask;
            gDefaultInterface.fColorPointer = glColorPointer;
            gDefaultInterface.fCullFace = glCullFace;
            gDefaultInterface.fDeleteTextures = glDeleteTextures;
            gDefaultInterface.fDepthMask = glDepthMask;
            gDefaultInterface.fDisable = glDisable;
            gDefaultInterface.fDisableClientState = glDisableClientState;
            gDefaultInterface.fDrawArrays = glDrawArrays;
            gDefaultInterface.fDrawElements = glDrawElements;
            gDefaultInterface.fEnable = glEnable;
            gDefaultInterface.fEnableClientState = glEnableClientState;
            gDefaultInterface.fFrontFace = glFrontFace;
            gDefaultInterface.fGenTextures = glGenTextures;
            gDefaultInterface.fGetError = glGetError;
            gDefaultInterface.fGetIntegerv = glGetIntegerv;
            gDefaultInterface.fGetString = glGetString;
            gDefaultInterface.fLineWidth = glLineWidth;
            gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
            gDefaultInterface.fMatrixMode = glMatrixMode;
            gDefaultInterface.fPixelStorei = glPixelStorei;
            gDefaultInterface.fPointSize = glPointSize;
            gDefaultInterface.fReadPixels = glReadPixels;
            gDefaultInterface.fScissor = glScissor;
            gDefaultInterface.fShadeModel = glShadeModel;
            gDefaultInterface.fStencilFunc = glStencilFunc;
            gDefaultInterface.fStencilMask = glStencilMask;
            gDefaultInterface.fStencilOp = glStencilOp;
            gDefaultInterface.fTexImage2D = glTexImage2D;
            gDefaultInterface.fTexParameteri = glTexParameteri;
            gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
            gDefaultInterface.fTexEnvi = glTexEnvi;
            gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
            gDefaultInterface.fViewport = glViewport;
            gDefaultInterface.fVertexPointer = glVertexPointer;

            GR_GL_GET_PROC(ActiveTexture);
            GR_GL_GET_PROC(AttachShader);
            GR_GL_GET_PROC(BindAttribLocation);
            GR_GL_GET_PROC(BindBuffer);
            GR_GL_GET_PROC(BindTexture);
            GR_GL_GET_PROC(BlendColor);
            GR_GL_GET_PROC(BufferData);
            GR_GL_GET_PROC(BufferSubData);
            GR_GL_GET_PROC(ClientActiveTexture);
            GR_GL_GET_PROC(CompileShader);
            GR_GL_GET_PROC(CompressedTexImage2D);
            GR_GL_GET_PROC(CreateProgram);
            GR_GL_GET_PROC(CreateShader);
            GR_GL_GET_PROC(DeleteBuffers);
            GR_GL_GET_PROC(DeleteProgram);
            GR_GL_GET_PROC(DeleteShader);
            GR_GL_GET_PROC(DisableVertexAttribArray);
            GR_GL_GET_PROC(EnableVertexAttribArray);
            GR_GL_GET_PROC(GenBuffers);
            GR_GL_GET_PROC(GetBufferParameteriv);
            GR_GL_GET_PROC(GetProgramInfoLog);
            GR_GL_GET_PROC(GetProgramiv);
            GR_GL_GET_PROC(GetShaderInfoLog);
            GR_GL_GET_PROC(GetShaderiv);
            GR_GL_GET_PROC(GetUniformLocation);
            GR_GL_GET_PROC(LinkProgram);
            GR_GL_GET_PROC(ShaderSource);
            GR_GL_GET_PROC(StencilFuncSeparate);
            GR_GL_GET_PROC(StencilMaskSeparate);
            GR_GL_GET_PROC(StencilOpSeparate);
            GR_GL_GET_PROC(Uniform1fv);
            GR_GL_GET_PROC(Uniform1i);
            GR_GL_GET_PROC(Uniform4fv);
            GR_GL_GET_PROC(UniformMatrix3fv);
            GR_GL_GET_PROC(UseProgram);
            GR_GL_GET_PROC(VertexAttrib4fv);
            GR_GL_GET_PROC(VertexAttribPointer);

            // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
            // GL_ARB_framebuffer_object doesn't use ARB suffix.)
            if (major >= 3 || has_gl_extension_from_string("GL_ARB_framebuffer_object", extString)) {
                GR_GL_GET_PROC(GenFramebuffers);
                GR_GL_GET_PROC(BindFramebuffer);
                GR_GL_GET_PROC(FramebufferTexture2D);
                GR_GL_GET_PROC(CheckFramebufferStatus);
                GR_GL_GET_PROC(DeleteFramebuffers);
                GR_GL_GET_PROC(RenderbufferStorage);
                GR_GL_GET_PROC(GenRenderbuffers);
                GR_GL_GET_PROC(DeleteRenderbuffers);
                GR_GL_GET_PROC(FramebufferRenderbuffer);
                GR_GL_GET_PROC(BindRenderbuffer);
                GR_GL_GET_PROC(RenderbufferStorageMultisample);
                GR_GL_GET_PROC(BlitFramebuffer);
            } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object", extString)) {
                GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
                GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
                GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
                GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
                GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
                GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
                GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
                if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", extString)) {
                    GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
                }
                if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", extString)) {
                    GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
                }
            } else {
                // we must have FBOs
                return;
            }
            GR_GL_GET_PROC(MapBuffer);
            GR_GL_GET_PROC(UnmapBuffer);

            gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;

            gDefaultInterfaceInit = true;
        }
    }
    if (gDefaultInterfaceInit) {
        GrGLSetGLInterface(&gDefaultInterface);
    }
}
<|endoftext|>