<commit_before>#include "TelegramServer.hpp"

#include <QLoggingCategory>
#include <QTcpServer>
#include <QTcpSocket>

#include "Utils.hpp"
#include "TelegramServerUser.hpp"
#include "TelegramServerClient.hpp"
#include "RemoteServerConnection.hpp"

#include "CServerTcpTransport.hpp"

// Generated RPC Operation Factory includes
#include "AccountOperationFactory.hpp"
#include "AuthOperationFactory.hpp"
#include "BotsOperationFactory.hpp"
#include "ChannelsOperationFactory.hpp"
#include "ContactsOperationFactory.hpp"
#include "HelpOperationFactory.hpp"
#include "LangpackOperationFactory.hpp"
#include "MessagesOperationFactory.hpp"
#include "PaymentsOperationFactory.hpp"
#include "PhoneOperationFactory.hpp"
#include "PhotosOperationFactory.hpp"
#include "StickersOperationFactory.hpp"
#include "UpdatesOperationFactory.hpp"
#include "UploadOperationFactory.hpp"
#include "UsersOperationFactory.hpp"
// End of generated RPC Operation Factory includes

Q_LOGGING_CATEGORY(loggingCategoryServer, "telegram.server.main", QtDebugMsg)
Q_LOGGING_CATEGORY(loggingCategoryServerApi, "telegram.server.api", QtDebugMsg)

namespace Telegram {

namespace Server {

Server::Server(QObject *parent) :
    QObject(parent)
{
    m_rpcOperationFactories = {
        // Generated RPC Operation Factory initialization
        new AccountOperationFactory(),
        new AuthOperationFactory(),
        new BotsOperationFactory(),
        new ChannelsOperationFactory(),
        new ContactsOperationFactory(),
        new HelpOperationFactory(),
        new LangpackOperationFactory(),
        new MessagesOperationFactory(),
        new PaymentsOperationFactory(),
        new PhoneOperationFactory(),
        new PhotosOperationFactory(),
        new StickersOperationFactory(),
        new UpdatesOperationFactory(),
        new UploadOperationFactory(),
        new UsersOperationFactory(),
        // End of generated RPC Operation Factory initialization
    };
    m_serverSocket = new QTcpServer(this);
    connect(m_serverSocket, &QTcpServer::newConnection, this, &Server::onNewConnection);
}

void Server::setDcOption(const DcOption &option)
{
    m_dcOption = option;
}

void Server::setServerPrivateRsaKey(const Telegram::RsaKey &key)
{
    m_key = key;
}

bool Server::start()
{
    if (!m_serverSocket->listen(QHostAddress(m_dcOption.address), m_dcOption.port)) {
        qWarning() << "Unable to listen port" << m_dcOption.port;
        return false;
    }
    qDebug() << "Start a server" << m_dcOption.id << "on" << m_dcOption.address << ":" << m_dcOption.port << "Key:" << m_key.fingerprint;
    return true;
}

void Server::loadData()
{
    const int number = 10;
    for (int i = 0; i < number; ++i) {
        User *newUser = new User(this);
        newUser->setPhoneNumber(QStringLiteral("%1").arg(i, 6, 10, QLatin1Char('0')));
        insertUser(newUser);
    }
}

void Server::setServerConfiguration(const DcConfiguration &config)
{
    m_dcConfiguration = config;
}

void Server::addServerConnection(RemoteServerConnection *remoteServer)
{
    m_remoteServers.insert(remoteServer);
}

quint32 Server::getDcIdForUserIdentifier(const QString &phoneNumber)
{
    if (m_phoneToUserId.contains(phoneNumber)) {
        return m_dcOption.id;
    }
    return 0;
}

void Server::onNewConnection()
{
    QTcpSocket *newConnection = m_serverSocket->nextPendingConnection();
    if (newConnection == nullptr) {
        qCDebug(loggingCategoryServer) << "expected pending connection does not exist";
        return;
    }
    qCDebug(loggingCategoryServer) << "A new incoming connection from" << newConnection->peerAddress().toString();
    TcpTransport *transport = new TcpTransport(newConnection, this);
    newConnection->setParent(transport);
    RemoteClientConnection *client = new RemoteClientConnection(this);
    connect(client, &BaseConnection::statusChanged, this, &Server::onClientConnectionStatusChanged);
    client->setServerRsaKey(m_key);
    client->setTransport(transport);
    client->setServerApi(this);
    client->setRpcFactories(m_rpcOperationFactories);

    m_activeConnections.insert(client);
}

void Server::onClientConnectionStatusChanged()
{
    RemoteClientConnection *client = qobject_cast<RemoteClientConnection*>(sender());
    if (client->status() == RemoteClientConnection::Status::Authenticated) {
        User *u = getUser(client->authId());
        if (u) {
            client->setUser(u);
        } else {
            qDebug() << Q_FUNC_INFO << "A new auth key";
        }
    }
}

User *Server::getLocalUser(const QString &identifier)
{
    quint32 id = m_phoneToUserId.value(identifier);
    if (!id) {
        return nullptr;
    }
    return m_users.value(id);
}

RemoteUser *Server::getRemoteUser(const QString &identifier)
{
    for (RemoteServerConnection *remoteServer : m_remoteServers) {
        RemoteUser *u = remoteServer->getUser(identifier);
        if (u) {
            return u;
        }
    }
    return nullptr;
}

User *Server::getUser(const QString &identifier)
{
    return getLocalUser(identifier);
}

User *Server::getUser(quint64 authId)
{
    quint32 id = m_authIdToUserId.value(authId);
    if (!id) {
        return nullptr;
    }
    return m_users.value(id);
}

User *Server::addUser(const QString &identifier)
{
    qDebug() << Q_FUNC_INFO << identifier;
    User *user = new User(this);
    user->setPhoneNumber(identifier);
    user->setDcId(dcId());
    insertUser(user);
    return user;
}

void Server::insertUser(User *user)
{
    qDebug() << Q_FUNC_INFO << user << user->phoneNumber() << user->id();
    m_users.insert(user->id(), user);
    m_phoneToUserId.insert(user->phoneNumber(), user->id());
    for (const Session &session : user->sessions()) {
        m_authIdToUserId.insert(session.authId, user->id());
    }
}

PhoneStatus Server::getPhoneStatus(const QString &identifier)
{
    PhoneStatus result;
    RemoteUser *user = getLocalOrRemoteUser(identifier);
    if (user) {
        result.online = user->isOnline();
        result.dcId = user->dcId();
    }
    return result;
}

PasswordInfo Server::getPassword(const QString &identifier)
{
    PasswordInfo result;
    User *user = getUser(identifier);
    if (user && user->hasPassword()) {
        result.currentSalt = user->passwordSalt();
        result.hint = user->passwordHint();
    }
    return result;
}

bool Server::checkPassword(const QString &identifier, const QByteArray &hash)
{
    User *user = getUser(identifier);
    if (user && user->hasPassword()) {
        return user->passwordHash() == hash;
    }
    return false;

}

QByteArray Server::sendAppCode(const QString &identifier)
{
    AuthCode code;

#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
    QRandomGenerator;
#endif

    QByteArray randBytes(8, Qt::Uninitialized);
    Utils::randomBytes(&randBytes);
    code.hash = randBytes.toHex();
    code.code = QString::number(Utils::randomBytes<quint32>()).right(5);

    qCDebug(loggingCategoryServerApi) << "sendAppCode(" << identifier << "):" << "hash:" << code.hash << "code:" << code.code;
    m_sentCodeMap.insert(identifier, code);
    return code.hash;
}

ServerApi::AuthCodeStatus Server::getAuthCodeStatus(const QString &identifier, const QByteArray &hash, const QString &code)
{
    if (code.isEmpty()) {
        return AuthCodeStatus::CodeEmpty;
    }
    if (hash.isEmpty()) {
        return AuthCodeStatus::HashEmpty;
    }
    if (!m_sentCodeMap.contains(identifier)) {
        return AuthCodeStatus::PhoneInvalid;
    }
    const AuthCode c = m_sentCodeMap.value(identifier);
    if (c.hash != hash) {
        return AuthCodeStatus::HashInvalid;
    }
    if (c.code != code) {
        return AuthCodeStatus::CodeInvalid;
    }
    return AuthCodeStatus::CodeValid;
}

bool Server::identifierIsValid(const QString &identifier)
{
    const bool result = identifier.length() > 4;
    qCDebug(loggingCategoryServerApi) << "identifierIsValid(" << identifier << "):" << result;
    return result;
}

RemoteUser *Server::getLocalOrRemoteUser(const QString &identifier)
{
    RemoteUser *user = getLocalUser(identifier);
    if (!user) {
        user = getRemoteUser(identifier);
    }
    return user;
}

} // Server

} // Telegram
<commit_msg>TelegramServer: Fix sendAppCode()<commit_after>#include "TelegramServer.hpp"

#include <QLoggingCategory>
#include <QTcpServer>
#include <QTcpSocket>

#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
#include <QRandomGenerator>
#endif

#include "Utils.hpp"
#include "TelegramServerUser.hpp"
#include "TelegramServerClient.hpp"
#include "RemoteServerConnection.hpp"

#include "CServerTcpTransport.hpp"

// Generated RPC Operation Factory includes
#include "AccountOperationFactory.hpp"
#include "AuthOperationFactory.hpp"
#include "BotsOperationFactory.hpp"
#include "ChannelsOperationFactory.hpp"
#include "ContactsOperationFactory.hpp"
#include "HelpOperationFactory.hpp"
#include "LangpackOperationFactory.hpp"
#include "MessagesOperationFactory.hpp"
#include "PaymentsOperationFactory.hpp"
#include "PhoneOperationFactory.hpp"
#include "PhotosOperationFactory.hpp"
#include "StickersOperationFactory.hpp"
#include "UpdatesOperationFactory.hpp"
#include "UploadOperationFactory.hpp"
#include "UsersOperationFactory.hpp"
// End of generated RPC Operation Factory includes

Q_LOGGING_CATEGORY(loggingCategoryServer, "telegram.server.main", QtDebugMsg)
Q_LOGGING_CATEGORY(loggingCategoryServerApi, "telegram.server.api", QtDebugMsg)

namespace Telegram {

namespace Server {

Server::Server(QObject *parent) :
    QObject(parent)
{
    m_rpcOperationFactories = {
        // Generated RPC Operation Factory initialization
        new AccountOperationFactory(),
        new AuthOperationFactory(),
        new BotsOperationFactory(),
        new ChannelsOperationFactory(),
        new ContactsOperationFactory(),
        new HelpOperationFactory(),
        new LangpackOperationFactory(),
        new MessagesOperationFactory(),
        new PaymentsOperationFactory(),
        new PhoneOperationFactory(),
        new PhotosOperationFactory(),
        new StickersOperationFactory(),
        new UpdatesOperationFactory(),
        new UploadOperationFactory(),
        new UsersOperationFactory(),
        // End of generated RPC Operation Factory initialization
    };
    m_serverSocket = new QTcpServer(this);
    connect(m_serverSocket, &QTcpServer::newConnection, this, &Server::onNewConnection);
}

void Server::setDcOption(const DcOption &option)
{
    m_dcOption = option;
}

void Server::setServerPrivateRsaKey(const Telegram::RsaKey &key)
{
    m_key = key;
}

bool Server::start()
{
    if (!m_serverSocket->listen(QHostAddress(m_dcOption.address), m_dcOption.port)) {
        qWarning() << "Unable to listen port" << m_dcOption.port;
        return false;
    }
    qDebug() << "Start a server" << m_dcOption.id << "on" << m_dcOption.address << ":" << m_dcOption.port << "Key:" << m_key.fingerprint;
    return true;
}

void Server::loadData()
{
    const int number = 10;
    for (int i = 0; i < number; ++i) {
        User *newUser = new User(this);
        newUser->setPhoneNumber(QStringLiteral("%1").arg(i, 6, 10, QLatin1Char('0')));
        insertUser(newUser);
    }
}

void Server::setServerConfiguration(const DcConfiguration &config)
{
    m_dcConfiguration = config;
}

void Server::addServerConnection(RemoteServerConnection *remoteServer)
{
    m_remoteServers.insert(remoteServer);
}

quint32 Server::getDcIdForUserIdentifier(const QString &phoneNumber)
{
    if (m_phoneToUserId.contains(phoneNumber)) {
        return m_dcOption.id;
    }
    return 0;
}

void Server::onNewConnection()
{
    QTcpSocket *newConnection = m_serverSocket->nextPendingConnection();
    if (newConnection == nullptr) {
        qCDebug(loggingCategoryServer) << "expected pending connection does not exist";
        return;
    }
    qCDebug(loggingCategoryServer) << "A new incoming connection from" << newConnection->peerAddress().toString();
    TcpTransport *transport = new TcpTransport(newConnection, this);
    newConnection->setParent(transport);
    RemoteClientConnection *client = new RemoteClientConnection(this);
    connect(client, &BaseConnection::statusChanged, this, &Server::onClientConnectionStatusChanged);
    client->setServerRsaKey(m_key);
    client->setTransport(transport);
    client->setServerApi(this);
    client->setRpcFactories(m_rpcOperationFactories);

    m_activeConnections.insert(client);
}

void Server::onClientConnectionStatusChanged()
{
    RemoteClientConnection *client = qobject_cast<RemoteClientConnection*>(sender());
    if (client->status() == RemoteClientConnection::Status::Authenticated) {
        User *u = getUser(client->authId());
        if (u) {
            client->setUser(u);
        } else {
            qDebug() << Q_FUNC_INFO << "A new auth key";
        }
    }
}

User *Server::getLocalUser(const QString &identifier)
{
    quint32 id = m_phoneToUserId.value(identifier);
    if (!id) {
        return nullptr;
    }
    return m_users.value(id);
}

RemoteUser *Server::getRemoteUser(const QString &identifier)
{
    for (RemoteServerConnection *remoteServer : m_remoteServers) {
        RemoteUser *u = remoteServer->getUser(identifier);
        if (u) {
            return u;
        }
    }
    return nullptr;
}

User *Server::getUser(const QString &identifier)
{
    return getLocalUser(identifier);
}

User *Server::getUser(quint64 authId)
{
    quint32 id = m_authIdToUserId.value(authId);
    if (!id) {
        return nullptr;
    }
    return m_users.value(id);
}

User *Server::addUser(const QString &identifier)
{
    qDebug() << Q_FUNC_INFO << identifier;
    User *user = new User(this);
    user->setPhoneNumber(identifier);
    user->setDcId(dcId());
    insertUser(user);
    return user;
}

void Server::insertUser(User *user)
{
    qDebug() << Q_FUNC_INFO << user << user->phoneNumber() << user->id();
    m_users.insert(user->id(), user);
    m_phoneToUserId.insert(user->phoneNumber(), user->id());
    for (const Session &session : user->sessions()) {
        m_authIdToUserId.insert(session.authId, user->id());
    }
}

PhoneStatus Server::getPhoneStatus(const QString &identifier)
{
    PhoneStatus result;
    RemoteUser *user = getLocalOrRemoteUser(identifier);
    if (user) {
        result.online = user->isOnline();
        result.dcId = user->dcId();
    }
    return result;
}

PasswordInfo Server::getPassword(const QString &identifier)
{
    PasswordInfo result;
    User *user = getUser(identifier);
    if (user && user->hasPassword()) {
        result.currentSalt = user->passwordSalt();
        result.hint = user->passwordHint();
    }
    return result;
}

bool Server::checkPassword(const QString &identifier, const QByteArray &hash)
{
    User *user = getUser(identifier);
    if (user && user->hasPassword()) {
        return user->passwordHash() == hash;
    }
    return false;

}

QByteArray Server::sendAppCode(const QString &identifier)
{
    AuthCode code;
    code.hash = Utils::getRandomBytes(8).toHex();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
    // The lowest value is included and the highest one is excluded
    const quint32 numCode = QRandomGenerator::global()->bounded(10000, 100000);
    code.code = QString::number(numCode);
#else
    code.code = QString::number(Utils::randomBytes<quint32>()).right(5);
#endif
    qCDebug(loggingCategoryServerApi) << "sendAppCode(" << identifier << "):" << "hash:" << code.hash << "code:" << code.code;
    m_sentCodeMap.insert(identifier, code);
    return code.hash;
}

ServerApi::AuthCodeStatus Server::getAuthCodeStatus(const QString &identifier, const QByteArray &hash, const QString &code)
{
    if (code.isEmpty()) {
        return AuthCodeStatus::CodeEmpty;
    }
    if (hash.isEmpty()) {
        return AuthCodeStatus::HashEmpty;
    }
    if (!m_sentCodeMap.contains(identifier)) {
        return AuthCodeStatus::PhoneInvalid;
    }
    const AuthCode c = m_sentCodeMap.value(identifier);
    if (c.hash != hash) {
        return AuthCodeStatus::HashInvalid;
    }
    if (c.code != code) {
        return AuthCodeStatus::CodeInvalid;
    }
    return AuthCodeStatus::CodeValid;
}

bool Server::identifierIsValid(const QString &identifier)
{
    const bool result = identifier.length() > 4;
    qCDebug(loggingCategoryServerApi) << "identifierIsValid(" << identifier << "):" << result;
    return result;
}

RemoteUser *Server::getLocalOrRemoteUser(const QString &identifier)
{
    RemoteUser *user = getLocalUser(identifier);
    if (!user) {
        user = getRemoteUser(identifier);
    }
    return user;
}

} // Server

} // Telegram
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkDropShadowImageFilter.h"

#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkReadBuffer.h"
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
#include "SkWriteBuffer.h"

sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy,
                                                   SkScalar sigmaX, SkScalar sigmaY,
                                                   SkColor color, ShadowMode shadowMode,
                                                   sk_sp<SkImageFilter> input,
                                                   const CropRect* cropRect) {
    return sk_sp<SkImageFilter>(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY,
                                                            color, shadowMode,
                                                            std::move(input),
                                                            cropRect));
}

SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
                                                 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
                                                 ShadowMode shadowMode, sk_sp<SkImageFilter> input,
                                                 const CropRect* cropRect)
    : INHERITED(&input, 1, cropRect)
    , fDx(dx)
    , fDy(dy)
    , fSigmaX(sigmaX)
    , fSigmaY(sigmaY)
    , fColor(color)
    , fShadowMode(shadowMode) {
}

sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    SkScalar dx = buffer.readScalar();
    SkScalar dy = buffer.readScalar();
    SkScalar sigmaX = buffer.readScalar();
    SkScalar sigmaY = buffer.readScalar();
    SkColor color = buffer.readColor();
    ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
                            kDrawShadowAndForeground_ShadowMode :
                            static_cast<ShadowMode>(buffer.readInt());
    return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect());
}

void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fDx);
    buffer.writeScalar(fDy);
    buffer.writeScalar(fSigmaX);
    buffer.writeScalar(fSigmaY);
    buffer.writeColor(fColor);
    buffer.writeInt(static_cast<int>(fShadowMode));
}

sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source,
                                                             const Context& ctx,
                                                             SkIPoint* offset) const {
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
    sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
    if (!input) {
        return nullptr;
    }

    const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
                                                  input->width(), input->height());
    SkIRect bounds;
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
        return nullptr;
    }

    sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
    if (!surf) {
        return nullptr;
    }

    SkCanvas* canvas = surf->getCanvas();
    SkASSERT(canvas);

    canvas->clear(0x0);

    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
    ctx.ctm().mapVectors(&sigma, 1);
    sigma.fX = SkMaxScalar(0, sigma.fX);
    sigma.fY = SkMaxScalar(0, sigma.fY);

    SkPaint paint;
    paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
    paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn));

    SkVector offsetVec = SkVector::Make(fDx, fDy);
    ctx.ctm().mapVectors(&offsetVec, 1);

    canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft),
                      SkIntToScalar(inputOffset.fY - bounds.fTop));
    input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);

    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        input->draw(canvas, 0, 0, nullptr);
    }
    offset->fX = bounds.fLeft;
    offset->fY = bounds.fTop;
    return surf->makeImageSnapshot();
}

SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const {
    SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
    SkRect shadowBounds = bounds;
    shadowBounds.offset(fDx, fDy);
    shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
                        SkScalarMul(fSigmaY, SkIntToScalar(3)));
    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        bounds.join(shadowBounds);
    } else {
        bounds = shadowBounds;
    }
    return bounds;
}

SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
                                                    MapDirection direction) const {
    SkVector offsetVec = SkVector::Make(fDx, fDy);
    if (kReverse_MapDirection == direction) {
        offsetVec.negate();
    }
    ctm.mapVectors(&offsetVec, 1);
    SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
                                 SkScalarCeilToInt(offsetVec.y()));
    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
    ctm.mapVectors(&sigma, 1);
    dst.outset(
        SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.x(), SkIntToScalar(3)))),
        SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.y(), SkIntToScalar(3)))));
    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        dst.join(src);
    }
    return dst;
}

#ifndef SK_IGNORE_TO_STRING
void SkDropShadowImageFilter::toString(SkString* str) const {
    str->appendf("SkDropShadowImageFilter: (");

    str->appendf("dX: %f ", fDx);
    str->appendf("dY: %f ", fDy);
    str->appendf("sigmaX: %f ", fSigmaX);
    str->appendf("sigmaY: %f ", fSigmaY);

    str->append("Color: ");
    str->appendHex(fColor);

    static const char* gModeStrings[] = {
        "kDrawShadowAndForeground", "kDrawShadowOnly"
    };

    static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");

    str->appendf(" mode: %s", gModeStrings[fShadowMode]);

    str->append(")");
}
#endif
<commit_msg>Revert "Revert "Add antialiasing to SkDropShadowImageFilter's shadow draw""<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkDropShadowImageFilter.h"

#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkReadBuffer.h"
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
#include "SkWriteBuffer.h"

sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy,
                                                   SkScalar sigmaX, SkScalar sigmaY,
                                                   SkColor color, ShadowMode shadowMode,
                                                   sk_sp<SkImageFilter> input,
                                                   const CropRect* cropRect) {
    return sk_sp<SkImageFilter>(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY,
                                                            color, shadowMode,
                                                            std::move(input),
                                                            cropRect));
}

SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
                                                 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
                                                 ShadowMode shadowMode, sk_sp<SkImageFilter> input,
                                                 const CropRect* cropRect)
    : INHERITED(&input, 1, cropRect)
    , fDx(dx)
    , fDy(dy)
    , fSigmaX(sigmaX)
    , fSigmaY(sigmaY)
    , fColor(color)
    , fShadowMode(shadowMode) {
}

sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    SkScalar dx = buffer.readScalar();
    SkScalar dy = buffer.readScalar();
    SkScalar sigmaX = buffer.readScalar();
    SkScalar sigmaY = buffer.readScalar();
    SkColor color = buffer.readColor();
    ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
                            kDrawShadowAndForeground_ShadowMode :
                            static_cast<ShadowMode>(buffer.readInt());
    return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect());
}

void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fDx);
    buffer.writeScalar(fDy);
    buffer.writeScalar(fSigmaX);
    buffer.writeScalar(fSigmaY);
    buffer.writeColor(fColor);
    buffer.writeInt(static_cast<int>(fShadowMode));
}

sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source,
                                                             const Context& ctx,
                                                             SkIPoint* offset) const {
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
    sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
    if (!input) {
        return nullptr;
    }

    const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
                                                  input->width(), input->height());
    SkIRect bounds;
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
        return nullptr;
    }

    sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
    if (!surf) {
        return nullptr;
    }

    SkCanvas* canvas = surf->getCanvas();
    SkASSERT(canvas);

    canvas->clear(0x0);

    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
    ctx.ctm().mapVectors(&sigma, 1);
    sigma.fX = SkMaxScalar(0, sigma.fX);
    sigma.fY = SkMaxScalar(0, sigma.fY);

    SkPaint paint;
    paint.setAntiAlias(true);
    paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
    paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn));

    SkVector offsetVec = SkVector::Make(fDx, fDy);
    ctx.ctm().mapVectors(&offsetVec, 1);

    canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft),
                      SkIntToScalar(inputOffset.fY - bounds.fTop));
    input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);

    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        input->draw(canvas, 0, 0, nullptr);
    }
    offset->fX = bounds.fLeft;
    offset->fY = bounds.fTop;
    return surf->makeImageSnapshot();
}

SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const {
    SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
    SkRect shadowBounds = bounds;
    shadowBounds.offset(fDx, fDy);
    shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
                        SkScalarMul(fSigmaY, SkIntToScalar(3)));
    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        bounds.join(shadowBounds);
    } else {
        bounds = shadowBounds;
    }
    return bounds;
}

SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
                                                    MapDirection direction) const {
    SkVector offsetVec = SkVector::Make(fDx, fDy);
    if (kReverse_MapDirection == direction) {
        offsetVec.negate();
    }
    ctm.mapVectors(&offsetVec, 1);
    SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
                                 SkScalarCeilToInt(offsetVec.y()));
    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
    ctm.mapVectors(&sigma, 1);
    dst.outset(
        SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.x(), SkIntToScalar(3)))),
        SkScalarCeilToInt(SkScalarAbs(SkScalarMul(sigma.y(), SkIntToScalar(3)))));
    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
        dst.join(src);
    }
    return dst;
}

#ifndef SK_IGNORE_TO_STRING
void SkDropShadowImageFilter::toString(SkString* str) const {
    str->appendf("SkDropShadowImageFilter: (");

    str->appendf("dX: %f ", fDx);
    str->appendf("dY: %f ", fDy);
    str->appendf("sigmaX: %f ", fSigmaX);
    str->appendf("sigmaY: %f ", fSigmaY);

    str->append("Color: ");
    str->appendHex(fColor);

    static const char* gModeStrings[] = {
        "kDrawShadowAndForeground", "kDrawShadowOnly"
    };

    static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");

    str->appendf(" mode: %s", gModeStrings[fShadowMode]);

    str->append(")");
}
#endif
<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB

   This program 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; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>
#include <NDBT_Thread.hpp>
#include <NdbApi.hpp>

NDBT_Thread::NDBT_Thread()
{
  create(0, -1);
}

NDBT_Thread::NDBT_Thread(NDBT_ThreadSet* thread_set, int thread_no)
{
  create(thread_set, thread_no);
}

void
NDBT_Thread::create(NDBT_ThreadSet* thread_set, int thread_no)
{
  m_magic = NDBT_Thread::Magic;

  m_state = Wait;
  m_thread_set = thread_set;
  m_thread_no = thread_no;
  m_func = 0;
  m_input = 0;
  m_output = 0;
  m_ndb = 0;
  m_err = 0;

  m_mutex = NdbMutex_Create();
  assert(m_mutex != 0);
  m_cond = NdbCondition_Create();
  assert(m_cond != 0);

  char buf[20];
  sprintf(buf, "NDBT_%04u");
  const char* name = strdup(buf);
  assert(name != 0);

  unsigned stacksize = 512 * 1024;
  NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
  m_thread = NdbThread_Create(NDBT_Thread_run,
                              (void**)this, stacksize, name, prio);
  assert(m_thread != 0);
}

NDBT_Thread::~NDBT_Thread()
{
  if (m_thread != 0) {
    NdbThread_Destroy(&m_thread);
    m_thread = 0;
  }
  if (m_cond != 0) {
    NdbCondition_Destroy(m_cond);
    m_cond = 0;
  }
  if (m_mutex != 0) {
    NdbMutex_Destroy(m_mutex);
    m_mutex = 0;
  }
}

static void*
NDBT_Thread_run(void* arg)
{
  assert(arg != 0);
  NDBT_Thread& thr = *(NDBT_Thread*)arg;
  assert(thr.m_magic == NDBT_Thread::Magic);
  thr.run();
  return 0;
}

void
NDBT_Thread::run()
{
  while (1) {
    lock();
    while (m_state != Start && m_state != Exit) {
      wait();
    }
    if (m_state == Exit) {
      unlock();
      break;
    }
    (*m_func)(*this);
    m_state = Stop;
    signal();
    unlock();
  }
}

// methods for main process

void
NDBT_Thread::start()
{
  lock();
  m_state = Start;
  signal();
  unlock();
}

void
NDBT_Thread::stop()
{
  lock();
  while (m_state != Stop)
    wait();
  m_state = Wait;
  unlock();
}

void
NDBT_Thread::exit()
{
  lock();
  m_state = Exit;
  signal();
  unlock();
};

void
NDBT_Thread::join()
{
  NdbThread_WaitFor(m_thread, &m_status);
  m_thread = 0;
}

int
NDBT_Thread::connect(class Ndb_cluster_connection* ncc, const char* db)
{
  m_ndb = new Ndb(ncc, db);
  if (m_ndb->init() == -1 ||
      m_ndb->waitUntilReady() == -1) {
    m_err = m_ndb->getNdbError().code;
    return -1;
  }
  return 0;
}

void
NDBT_Thread::disconnect()
{
  delete m_ndb;
  m_ndb = 0;
}

// set of threads

NDBT_ThreadSet::NDBT_ThreadSet(int count)
{
  m_count = count;
  m_thread = new NDBT_Thread* [count];
  for (int n = 0; n < count; n++) {
    m_thread[n] = new NDBT_Thread(this, n);
  }
}

NDBT_ThreadSet::~NDBT_ThreadSet()
{
  delete_output();
  for (int n = 0; n < m_count; n++) {
    delete m_thread[n];
    m_thread[n] = 0;
  }
  delete [] m_thread;
}

void
NDBT_ThreadSet::start()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.start();
  }
}

void
NDBT_ThreadSet::stop()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.stop();
  }
}

void
NDBT_ThreadSet::exit()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.exit();
  }
}

void
NDBT_ThreadSet::join()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.join();
  }
}

void
NDBT_ThreadSet::set_func(NDBT_ThreadFunc* func)
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.set_func(func);
  }
}

void
NDBT_ThreadSet::set_input(const void* input)
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.set_input(input);
  }
}

void
NDBT_ThreadSet::delete_output()
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      thr.delete_output();
    }
  }
}

int
NDBT_ThreadSet::connect(class Ndb_cluster_connection* ncc, const char* db)
{
  for (int n = 0; n < m_count; n++) {
    assert(m_thread[n] != 0);
    NDBT_Thread& thr = *m_thread[n];
    if (thr.connect(ncc, db) == -1)
      return -1;
  }
  return 0;
}

void
NDBT_ThreadSet::disconnect()
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      thr.disconnect();
    }
  }
}

int
NDBT_ThreadSet::get_err() const
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      int err = thr.get_err();
      if (err != 0)
        return err;
    }
  }
  return 0;
}
<commit_msg>NDBT_Thread.cpp:   Removed semicolon causing build syntax issues per pekka<commit_after>/* Copyright (C) 2003 MySQL AB

   This program 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; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>
#include <NDBT_Thread.hpp>
#include <NdbApi.hpp>

NDBT_Thread::NDBT_Thread()
{
  create(0, -1);
}

NDBT_Thread::NDBT_Thread(NDBT_ThreadSet* thread_set, int thread_no)
{
  create(thread_set, thread_no);
}

void
NDBT_Thread::create(NDBT_ThreadSet* thread_set, int thread_no)
{
  m_magic = NDBT_Thread::Magic;

  m_state = Wait;
  m_thread_set = thread_set;
  m_thread_no = thread_no;
  m_func = 0;
  m_input = 0;
  m_output = 0;
  m_ndb = 0;
  m_err = 0;

  m_mutex = NdbMutex_Create();
  assert(m_mutex != 0);
  m_cond = NdbCondition_Create();
  assert(m_cond != 0);

  char buf[20];
  sprintf(buf, "NDBT_%04u");
  const char* name = strdup(buf);
  assert(name != 0);

  unsigned stacksize = 512 * 1024;
  NDB_THREAD_PRIO prio = NDB_THREAD_PRIO_LOW;
  m_thread = NdbThread_Create(NDBT_Thread_run,
                              (void**)this, stacksize, name, prio);
  assert(m_thread != 0);
}

NDBT_Thread::~NDBT_Thread()
{
  if (m_thread != 0) {
    NdbThread_Destroy(&m_thread);
    m_thread = 0;
  }
  if (m_cond != 0) {
    NdbCondition_Destroy(m_cond);
    m_cond = 0;
  }
  if (m_mutex != 0) {
    NdbMutex_Destroy(m_mutex);
    m_mutex = 0;
  }
}

static void*
NDBT_Thread_run(void* arg)
{
  assert(arg != 0);
  NDBT_Thread& thr = *(NDBT_Thread*)arg;
  assert(thr.m_magic == NDBT_Thread::Magic);
  thr.run();
  return 0;
}

void
NDBT_Thread::run()
{
  while (1) {
    lock();
    while (m_state != Start && m_state != Exit) {
      wait();
    }
    if (m_state == Exit) {
      unlock();
      break;
    }
    (*m_func)(*this);
    m_state = Stop;
    signal();
    unlock();
  }
}

// methods for main process

void
NDBT_Thread::start()
{
  lock();
  m_state = Start;
  signal();
  unlock();
}

void
NDBT_Thread::stop()
{
  lock();
  while (m_state != Stop)
    wait();
  m_state = Wait;
  unlock();
}

void
NDBT_Thread::exit()
{
  lock();
  m_state = Exit;
  signal();
  unlock();
}

void
NDBT_Thread::join()
{
  NdbThread_WaitFor(m_thread, &m_status);
  m_thread = 0;
}

int
NDBT_Thread::connect(class Ndb_cluster_connection* ncc, const char* db)
{
  m_ndb = new Ndb(ncc, db);
  if (m_ndb->init() == -1 ||
      m_ndb->waitUntilReady() == -1) {
    m_err = m_ndb->getNdbError().code;
    return -1;
  }
  return 0;
}

void
NDBT_Thread::disconnect()
{
  delete m_ndb;
  m_ndb = 0;
}

// set of threads

NDBT_ThreadSet::NDBT_ThreadSet(int count)
{
  m_count = count;
  m_thread = new NDBT_Thread* [count];
  for (int n = 0; n < count; n++) {
    m_thread[n] = new NDBT_Thread(this, n);
  }
}

NDBT_ThreadSet::~NDBT_ThreadSet()
{
  delete_output();
  for (int n = 0; n < m_count; n++) {
    delete m_thread[n];
    m_thread[n] = 0;
  }
  delete [] m_thread;
}

void
NDBT_ThreadSet::start()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.start();
  }
}

void
NDBT_ThreadSet::stop()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.stop();
  }
}

void
NDBT_ThreadSet::exit()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.exit();
  }
}

void
NDBT_ThreadSet::join()
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.join();
  }
}

void
NDBT_ThreadSet::set_func(NDBT_ThreadFunc* func)
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.set_func(func);
  }
}

void
NDBT_ThreadSet::set_input(const void* input)
{
  for (int n = 0; n < m_count; n++) {
    NDBT_Thread& thr = *m_thread[n];
    thr.set_input(input);
  }
}

void
NDBT_ThreadSet::delete_output()
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      thr.delete_output();
    }
  }
}

int
NDBT_ThreadSet::connect(class Ndb_cluster_connection* ncc, const char* db)
{
  for (int n = 0; n < m_count; n++) {
    assert(m_thread[n] != 0);
    NDBT_Thread& thr = *m_thread[n];
    if (thr.connect(ncc, db) == -1)
      return -1;
  }
  return 0;
}

void
NDBT_ThreadSet::disconnect()
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      thr.disconnect();
    }
  }
}

int
NDBT_ThreadSet::get_err() const
{
  for (int n = 0; n < m_count; n++) {
    if (m_thread[n] != 0) {
      NDBT_Thread& thr = *m_thread[n];
      int err = thr.get_err();
      if (err != 0)
        return err;
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "paddle/memory/memory.h"
#include "paddle/memory/detail/buddy_allocator.h"
#include "paddle/memory/detail/system_allocator.h"

namespace paddle {
namespace memory {

detail::BuddyAllocator* GetCPUBuddyAllocator() {
  static detail::BuddyAllocator* a = nullptr;
  if (a == nullptr) {
    a = new detail::BuddyAllocator(new detail::CPUAllocator,
                                   platform::CpuMinChunkSize(),
                                   platform::CpuMaxChunkSize());
  }
  return a;
}

template <>
void* Alloc<platform::CPUPlace>(platform::CPUPlace place, size_t size) {
  return GetCPUBuddyAllocator()->Alloc(size);
}

template <>
void Free<platform::CPUPlace>(platform::CPUPlace place, void* p) {
  GetCPUBuddyAllocator()->Free(p);
}

template <>
size_t Used<platform::CPUPlace>(platform::CPUPlace place) {
  return GetCPUBuddyAllocator()->Used();
}

template <>
void Copy<platform::CPUPlace, platform::CPUPlace>(platform::CPUPlace, void* dst,
                                                  platform::CPUPlace,
                                                  const void* src, size_t num) {
  memcpy(dst, src, num);
}

#ifndef PADDLE_ONLY_CPU

detail::BuddyAllocator* GetGPUBuddyAllocator(int gpu_id) {
  static detail::BuddyAllocator** as = NULL;
  if (as == NULL) {
    int gpu_num = platform::GetDeviceCount();
    as = new detail::BuddyAllocator*[gpu_num];
    for (int gpu = 0; gpu < gpu_num; gpu++) {
      platform::SetDeviceId(gpu);
      as[gpu] = new detail::BuddyAllocator(new detail::GPUAllocator,
                                           platform::GpuMinChunkSize(),
                                           platform::GpuMaxChunkSize());
    }
  }
  return as[gpu_id];
}

template <>
void* Alloc<platform::GPUPlace>(platform::GPUPlace place, size_t size) {
  return GetGPUBuddyAllocator(place.device)->Alloc(size);
}

template <>
void Free<platform::GPUPlace>(platform::GPUPlace place, void* p) {
  GetGPUBuddyAllocator(place.device)->Free(p);
}

template <>
size_t Used<platform::GPUPlace>(platform::GPUPlace place) {
  return GetGPUBuddyAllocator(place.device)->Used();
}

template <>
void Copy<platform::CPUPlace, platform::GPUPlace>(platform::CPUPlace, void* dst,
                                                  platform::GPUPlace,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyHostToDevice, stream);
}

template <>
void Copy<platform::GPUPlace, platform::CPUPlace>(platform::GPUPlace, void* dst,
                                                  platform::CPUPlace,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyDeviceToHost, stream);
}

template <>
void Copy<platform::GPUPlace, platform::GPUPlace>(platform::GPUPlace dst_place,
                                                  void* dst,
                                                  platform::GPUPlace src_place,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  if (dst_place == src_place) {
    platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyDeviceToDevice, stream);
  } else {
    platform::GpuMemcpyPeer(dst, dst_place.device, src, src_place.device, num,
                            stream);
  }
}

#endif  // PADDLE_ONLY_CPU

}  // namespace memory
}  // namespace paddle
<commit_msg>Fix H2D and D2H order<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "paddle/memory/memory.h"
#include "paddle/memory/detail/buddy_allocator.h"
#include "paddle/memory/detail/system_allocator.h"

namespace paddle {
namespace memory {

detail::BuddyAllocator* GetCPUBuddyAllocator() {
  static detail::BuddyAllocator* a = nullptr;
  if (a == nullptr) {
    a = new detail::BuddyAllocator(new detail::CPUAllocator,
                                   platform::CpuMinChunkSize(),
                                   platform::CpuMaxChunkSize());
  }
  return a;
}

template <>
void* Alloc<platform::CPUPlace>(platform::CPUPlace place, size_t size) {
  return GetCPUBuddyAllocator()->Alloc(size);
}

template <>
void Free<platform::CPUPlace>(platform::CPUPlace place, void* p) {
  GetCPUBuddyAllocator()->Free(p);
}

template <>
size_t Used<platform::CPUPlace>(platform::CPUPlace place) {
  return GetCPUBuddyAllocator()->Used();
}

template <>
void Copy<platform::CPUPlace, platform::CPUPlace>(platform::CPUPlace, void* dst,
                                                  platform::CPUPlace,
                                                  const void* src, size_t num) {
  memcpy(dst, src, num);
}

#ifndef PADDLE_ONLY_CPU

detail::BuddyAllocator* GetGPUBuddyAllocator(int gpu_id) {
  static detail::BuddyAllocator** as = NULL;
  if (as == NULL) {
    int gpu_num = platform::GetDeviceCount();
    as = new detail::BuddyAllocator*[gpu_num];
    for (int gpu = 0; gpu < gpu_num; gpu++) {
      platform::SetDeviceId(gpu);
      as[gpu] = new detail::BuddyAllocator(new detail::GPUAllocator,
                                           platform::GpuMinChunkSize(),
                                           platform::GpuMaxChunkSize());
    }
  }
  return as[gpu_id];
}

template <>
void* Alloc<platform::GPUPlace>(platform::GPUPlace place, size_t size) {
  return GetGPUBuddyAllocator(place.device)->Alloc(size);
}

template <>
void Free<platform::GPUPlace>(platform::GPUPlace place, void* p) {
  GetGPUBuddyAllocator(place.device)->Free(p);
}

template <>
size_t Used<platform::GPUPlace>(platform::GPUPlace place) {
  return GetGPUBuddyAllocator(place.device)->Used();
}

template <>
void Copy<platform::CPUPlace, platform::GPUPlace>(platform::CPUPlace, void* dst,
                                                  platform::GPUPlace,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyDeviceToHost, stream);
}

template <>
void Copy<platform::GPUPlace, platform::CPUPlace>(platform::GPUPlace, void* dst,
                                                  platform::CPUPlace,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyHostToDevice, stream);
}

template <>
void Copy<platform::GPUPlace, platform::GPUPlace>(platform::GPUPlace dst_place,
                                                  void* dst,
                                                  platform::GPUPlace src_place,
                                                  const void* src, size_t num,
                                                  cudaStream_t stream) {
  if (dst_place == src_place) {
    platform::GpuMemcpyAsync(dst, src, num, cudaMemcpyDeviceToDevice, stream);
  } else {
    platform::GpuMemcpyPeer(dst, dst_place.device, src, src_place.device, num,
                            stream);
  }
}

#endif  // PADDLE_ONLY_CPU

}  // namespace memory
}  // namespace paddle
<|endoftext|>


<commit_before>/*
    Copyright (C) 2001 by Jorrit Tyberghein

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "spider.h"
#include "iengine/rview.h"
#include "iengine/mesh.h"
#include "iengine/engine.h"
#include "iengine/sector.h"
#include "iengine/movable.h"

IMPLEMENT_IBASE (csSpider)
  IMPLEMENTS_INTERFACE (iMeshObject)
IMPLEMENT_IBASE_END

csSpider::csSpider ()
{
  CONSTRUCT_IBASE (NULL);
  camera = NULL;
  wrap = NULL;
}

csSpider::~csSpider ()
{
  CS_ASSERT (wrap != NULL);
}

bool csSpider::DrawTest (iRenderView* rview, iMovable*)
{
  if (!camera)
  {
    camera = rview->GetCamera ();
    // @@@ Should Spider IncRef() camera to keep it alive?
  }
  return false;
}

void csSpider::WeaveWeb (iEngine* engine)
{
  if (wrap) wrap->DecRef ();
  wrap = engine->CreateMeshObject (this, "_@Spider@_");
  iMovable* movable = wrap->GetMovable ();
  int i;
  for (i = 0 ; i < engine->GetSectorCount () ; i++)
  {
    iSector* sec = engine->GetSector (i);
    movable->AddSector (sec);
  }
  movable->UpdateMove ();
}

void csSpider::UnweaveWeb (iEngine* engine)
{
  if (wrap)
  {
    wrap->DecRef ();
    wrap = NULL;
  }
}

<commit_msg>Fixed a bug in the assert of the Spider destructor.<commit_after>/*
    Copyright (C) 2001 by Jorrit Tyberghein

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "spider.h"
#include "iengine/rview.h"
#include "iengine/mesh.h"
#include "iengine/engine.h"
#include "iengine/sector.h"
#include "iengine/movable.h"

IMPLEMENT_IBASE (csSpider)
  IMPLEMENTS_INTERFACE (iMeshObject)
IMPLEMENT_IBASE_END

csSpider::csSpider ()
{
  CONSTRUCT_IBASE (NULL);
  camera = NULL;
  wrap = NULL;
}

csSpider::~csSpider ()
{
  CS_ASSERT (wrap == NULL);
}

bool csSpider::DrawTest (iRenderView* rview, iMovable*)
{
  if (!camera)
  {
    camera = rview->GetCamera ();
    // @@@ Should Spider IncRef() camera to keep it alive?
  }
  return false;
}

void csSpider::WeaveWeb (iEngine* engine)
{
  if (wrap) wrap->DecRef ();
  wrap = engine->CreateMeshObject (this, "_@Spider@_");
  iMovable* movable = wrap->GetMovable ();
  int i;
  for (i = 0 ; i < engine->GetSectorCount () ; i++)
  {
    iSector* sec = engine->GetSector (i);
    movable->AddSector (sec);
  }
  movable->UpdateMove ();
}

void csSpider::UnweaveWeb (iEngine* engine)
{
  if (wrap)
  {
    wrap->DecRef ();
    wrap = NULL;
  }
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 2000 by Michael Dale Long

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "isystem.h"
#include "iconsole.h"
#include "iconinp.h"
#include "csutil/scf.h"
#include "csutil/csstring.h"
#include "csinput/csevent.h"
#include "coninput.h"
#include "conbuffr.h"

csConsoleInput::csConsoleInput(iBase *base)
{
  CONSTRUCT_IBASE(base);
  buffer = new csConsoleBuffer(4096, 4096);
  piConsole = NULL;
  cursor = 0;
}

csConsoleInput::~csConsoleInput()
{
  //@@@ This is disabled due to a bug in some implementations of iSystem
  //if(piSystem)
  //piSystem->DecRef();
  if(piConsole)
    piConsole->DecRef();
  delete buffer;
}

bool csConsoleInput::Initialize(iSystem *system)
{
  piSystem = system;
  return true;
}

bool csConsoleInput::HandleEvent(csEvent &event)
{

  if(event.Type==csevKeyDown) {
    csString *line;
    int cx, cy;

    switch(event.Key.Code) {
    case CSKEY_ESC:
      // The ignored keys
      break;
    case CSKEY_LEFT:
	if(cursor>0) {
	  cursor--;
	  if(piConsole) {
	    piConsole->GetCursorPos(cx, cy);
	    piConsole->SetCursorPos(cx-1, cy);
	  }
	}
	break;
    case CSKEY_RIGHT:
      if(cursor<buffer->GetLine(history)->Length()) {
	cursor++;
	if(piConsole) {
	  piConsole->GetCursorPos(cx, cy);
	  piConsole->SetCursorPos(cx+1, cy);
	}
      }
      break;
    case CSKEY_UP:
      {
	//	printf("Cursor")
	int ancient_history = history;
	// If we're at the top of the list, cycle down to the bottom
	if(history==0)
	  history = buffer->GetCurLine();
	else
	  history--;
	// Update the console
	if(piConsole) {
	  const csString *consoleText = piConsole->GetText(), *bufferText = buffer->GetLine(ancient_history);
	  // Make sure neither the console line nor the buffer line is NULL
	  if(!(consoleText==NULL||bufferText==NULL)) {
	    int start = consoleText->Length() - bufferText->Length();
	    cursor -= consoleText->Length();
	    piConsole->DeleteText(start > 0 ? start : 0);
	  }
	  bufferText = buffer->GetLine(history);
	  if(bufferText&&(!bufferText->IsEmpty())) {
	    piConsole->PutText(bufferText->GetData());
	    cursor += bufferText->Length();
	  }
	}
      }
      break;
    case CSKEY_DOWN:
      {
	int ancient_history = history;
	// If we are at the bottom, cycle to the top
	if(history==0)
	  history = 0;
	else
	  history++;
	// Update the console
	if(piConsole) {
	  const csString *consoleText = piConsole->GetText(), *bufferText = buffer->GetLine(ancient_history);
	  // Make sure neither the console line nor the buffer line is NULL
	  if(!(consoleText==NULL||bufferText==NULL)) {
	    int start = consoleText->Length() - bufferText->Length();
	    cursor -= consoleText->Length();
	    piConsole->DeleteText(start > 0 ? start : 0);
	  }
	  bufferText = buffer->GetLine(history);
	  if(bufferText&&(!bufferText->IsEmpty())) {
	    piConsole->PutText(bufferText->GetData());
	    cursor += bufferText->Length();
	  }
	}
      }
      break;
    default:
      if(event.Key.Code < CSKEY_FIRST) {

	// Make sure that this isn't the current line or an unmodified newline
	if(!((history==buffer->GetCurLine())||(event.Key.Code==CSKEY_ENTER))) {
	  // Copy the line to the current line
	  buffer->DeleteLine(buffer->GetCurLine());
	  line = buffer->WriteLine();
	  line->Append(*buffer->GetLine(history));
	  history = buffer->GetCurLine();
	}

	bool echo = true;

	// Handle special cases
	switch(event.Key.Code) {
	case CSKEY_ENTER:
	  // New line
	  NewLine();
	  break;
	case CSKEY_BACKSPACE:
	  line = buffer->WriteLine();
	  // Delete the last character in the current line
	  if(cursor>1)
	    line->DeleteAt(cursor-1);
	  else if (cursor==1)
	    buffer->DeleteLine(buffer->GetCurLine());
	  else if (cursor==0) {
	    echo = false;
	    // This gets decremented to zero below
	    cursor = 1;
	  }
	  // Move the cursor back by one
	  cursor--;
	  break;
	default:
	  // Append the character to the current line
	  line = buffer->WriteLine();
	  if(cursor==line->Length())
	    line->Append((char) event.Key.Code);
#ifdef CS_DEBUG
	  else if(cursor>line->Length())
	    piSystem->Printf(MSG_FATAL_ERROR, "csConsoleInput:  Cursor past end of line!\n");
#endif
	  else
	    line->Insert(cursor, (char) event.Key.Code);
	  // Increment cursor position
	  cursor++;
	  break;
	}
	if(piConsole&&echo) {
	  csString put((char) event.Key.Code);
	  piConsole->PutText(put.GetData());
	}
      }
    }
  }
#ifdef CS_DEBUG
  else {
    piSystem->Printf(MSG_WARNING, "csConsoleInput:  Received an unknown event!\n");
  }
#endif // CS_DEBUG

  // Just in case the application adds us into the input loop
  return false;

}

const csString *csConsoleInput::GetInput(int line) const
{
  if(line<0)
    return buffer->GetLine(history);
  else
    return buffer->GetLine(line);
}

int csConsoleInput::GetCurLine() const
{
  return buffer->GetCurLine();
}

void csConsoleInput::NewLine()
{
  if(!buffer->IsLineEmpty(history)) {
    buffer->NewLine();
    cursor = 0;
  }
  history = buffer->GetCurLine();
}

int csConsoleInput::GetBufferSize() const
{
  return buffer->GetLength();
}

void csConsoleInput::SetBufferSize(int size)
{
  /* Make sure the page size is the same as the buffer length so
   * the csConsoleBuffer is always trying to keep the display space
   * update to date.
   */
  buffer->SetLength(size);
  buffer->SetPageSize(size);
}

void csConsoleInput::Clear()
{
  buffer->Clear();
  cursor = 0;
}

bool csConsoleInput::GetEcho() const
{
  return piConsole!=NULL;
}

void csConsoleInput::SetEcho(bool echo, iConsole *console)
{
  if(echo) {
    if(console) {
      // if piConsole isn't NULL, we release it
      if(piConsole)
	piConsole->DecRef();
      piConsole = console;
      piConsole->IncRef();
    } else {
      // if piConsole isn't NULL, we just use what we've got
      if(piConsole==NULL)
	piConsole = QUERY_PLUGIN(piSystem, iConsole);
    }
  } else {
    // if piConsole isn't already NULL, we release it
    if(piConsole!=NULL) {
      piConsole->DecRef();
      piConsole = NULL;
    }
  }
}

IMPLEMENT_IBASE(csConsoleInput)
  IMPLEMENTS_INTERFACE(iConsoleInput)
  IMPLEMENTS_INTERFACE(iPlugIn)
IMPLEMENT_IBASE_END

IMPLEMENT_FACTORY(csConsoleInput)
<commit_msg>small fix: when first char was typed it crashed because it was trying to appemd a NULL to a string<commit_after>/*
    Copyright (C) 2000 by Michael Dale Long

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "isystem.h"
#include "iconsole.h"
#include "iconinp.h"
#include "csutil/scf.h"
#include "csutil/csstring.h"
#include "csinput/csevent.h"
#include "coninput.h"
#include "conbuffr.h"

csConsoleInput::csConsoleInput(iBase *base)
{
  CONSTRUCT_IBASE(base);
  buffer = new csConsoleBuffer(4096, 4096);
  piConsole = NULL;
  cursor = 0;
}

csConsoleInput::~csConsoleInput()
{
  //@@@ This is disabled due to a bug in some implementations of iSystem
  //if(piSystem)
  //piSystem->DecRef();
  if(piConsole)
    piConsole->DecRef();
  delete buffer;
}

bool csConsoleInput::Initialize(iSystem *system)
{
  piSystem = system;
  return true;
}

bool csConsoleInput::HandleEvent(csEvent &event)
{

  if(event.Type==csevKeyDown) {
    csString *line;
    int cx, cy;

    switch(event.Key.Code) {
    case CSKEY_ESC:
      // The ignored keys
      break;
    case CSKEY_LEFT:
	if(cursor>0) {
	  cursor--;
	  if(piConsole) {
	    piConsole->GetCursorPos(cx, cy);
	    piConsole->SetCursorPos(cx-1, cy);
	  }
	}
	break;
    case CSKEY_RIGHT:
      if(cursor<buffer->GetLine(history)->Length()) {
	cursor++;
	if(piConsole) {
	  piConsole->GetCursorPos(cx, cy);
	  piConsole->SetCursorPos(cx+1, cy);
	}
      }
      break;
    case CSKEY_UP:
      {
	//	printf("Cursor")
	int ancient_history = history;
	// If we're at the top of the list, cycle down to the bottom
	if(history==0)
	  history = buffer->GetCurLine();
	else
	  history--;
	// Update the console
	if(piConsole) {
	  const csString *consoleText = piConsole->GetText(), *bufferText = buffer->GetLine(ancient_history);
	  // Make sure neither the console line nor the buffer line is NULL
	  if(!(consoleText==NULL||bufferText==NULL)) {
	    int start = consoleText->Length() - bufferText->Length();
	    cursor -= consoleText->Length();
	    piConsole->DeleteText(start > 0 ? start : 0);
	  }
	  bufferText = buffer->GetLine(history);
	  if(bufferText&&(!bufferText->IsEmpty())) {
	    piConsole->PutText(bufferText->GetData());
	    cursor += bufferText->Length();
	  }
	}
      }
      break;
    case CSKEY_DOWN:
      {
	int ancient_history = history;
	// If we are at the bottom, cycle to the top
	if(history==0)
	  history = 0;
	else
	  history++;
	// Update the console
	if(piConsole) {
	  const csString *consoleText = piConsole->GetText(), *bufferText = buffer->GetLine(ancient_history);
	  // Make sure neither the console line nor the buffer line is NULL
	  if(!(consoleText==NULL||bufferText==NULL)) {
	    int start = consoleText->Length() - bufferText->Length();
	    cursor -= consoleText->Length();
	    piConsole->DeleteText(start > 0 ? start : 0);
	  }
	  bufferText = buffer->GetLine(history);
	  if(bufferText&&(!bufferText->IsEmpty())) {
	    piConsole->PutText(bufferText->GetData());
	    cursor += bufferText->Length();
	  }
	}
      }
      break;
    default:
      if(event.Key.Code < CSKEY_FIRST) {

	// Make sure that this isn't the current line or an unmodified newline
	if(!((history==buffer->GetCurLine())||(event.Key.Code==CSKEY_ENTER))) {
	  // Copy the line to the current line
	  buffer->DeleteLine(buffer->GetCurLine());
	  line = buffer->WriteLine();
	  if (buffer->GetLine(history))
            line->Append(*buffer->GetLine(history));
	  history = buffer->GetCurLine();
	}

	bool echo = true;

	// Handle special cases
	switch(event.Key.Code) {
	case CSKEY_ENTER:
	  // New line
	  NewLine();
	  break;
	case CSKEY_BACKSPACE:
	  line = buffer->WriteLine();
	  // Delete the last character in the current line
	  if(cursor>1)
	    line->DeleteAt(cursor-1);
	  else if (cursor==1)
	    buffer->DeleteLine(buffer->GetCurLine());
	  else if (cursor==0) {
	    echo = false;
	    // This gets decremented to zero below
	    cursor = 1;
	  }
	  // Move the cursor back by one
	  cursor--;
	  break;
	default:
	  // Append the character to the current line
	  line = buffer->WriteLine();
	  if(cursor==line->Length())
	    line->Append((char) event.Key.Code);
#ifdef CS_DEBUG
	  else if(cursor>line->Length())
	    piSystem->Printf(MSG_FATAL_ERROR, "csConsoleInput:  Cursor past end of line!\n");
#endif
	  else
	    line->Insert(cursor, (char) event.Key.Code);
	  // Increment cursor position
	  cursor++;
	  break;
	}
	if(piConsole&&echo) {
	  csString put((char) event.Key.Code);
	  piConsole->PutText(put.GetData());
	}
      }
    }
  }
#ifdef CS_DEBUG
  else {
    piSystem->Printf(MSG_WARNING, "csConsoleInput:  Received an unknown event!\n");
  }
#endif // CS_DEBUG

  // Just in case the application adds us into the input loop
  return false;

}

const csString *csConsoleInput::GetInput(int line) const
{
  if(line<0)
    return buffer->GetLine(history);
  else
    return buffer->GetLine(line);
}

int csConsoleInput::GetCurLine() const
{
  return buffer->GetCurLine();
}

void csConsoleInput::NewLine()
{
  if(!buffer->IsLineEmpty(history)) {
    buffer->NewLine();
    cursor = 0;
  }
  history = buffer->GetCurLine();
}

int csConsoleInput::GetBufferSize() const
{
  return buffer->GetLength();
}

void csConsoleInput::SetBufferSize(int size)
{
  /* Make sure the page size is the same as the buffer length so
   * the csConsoleBuffer is always trying to keep the display space
   * update to date.
   */
  buffer->SetLength(size);
  buffer->SetPageSize(size);
}

void csConsoleInput::Clear()
{
  buffer->Clear();
  cursor = 0;
}

bool csConsoleInput::GetEcho() const
{
  return piConsole!=NULL;
}

void csConsoleInput::SetEcho(bool echo, iConsole *console)
{
  if(echo) {
    if(console) {
      // if piConsole isn't NULL, we release it
      if(piConsole)
	piConsole->DecRef();
      piConsole = console;
      piConsole->IncRef();
    } else {
      // if piConsole isn't NULL, we just use what we've got
      if(piConsole==NULL)
	piConsole = QUERY_PLUGIN(piSystem, iConsole);
    }
  } else {
    // if piConsole isn't already NULL, we release it
    if(piConsole!=NULL) {
      piConsole->DecRef();
      piConsole = NULL;
    }
  }
}

IMPLEMENT_IBASE(csConsoleInput)
  IMPLEMENTS_INTERFACE(iConsoleInput)
  IMPLEMENTS_INTERFACE(iPlugIn)
IMPLEMENT_IBASE_END

IMPLEMENT_FACTORY(csConsoleInput)
<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/pe_file.hpp"

#include <cstddef>
#include <ostream>
#include <utility>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>
#include <winnt.h>

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/pelib/section.hpp"
#include "hadesmem/pelib/section_list.hpp"

namespace hadesmem
{

struct PeFile::Impl
{
  explicit Impl(Process const& process, PVOID address, PeFileType type)
    HADESMEM_NOEXCEPT
    : process_(&process),
    base_(static_cast<PBYTE>(address)),
    type_(type)
  {
    BOOST_ASSERT(base_ != 0);
  }

  Process const* process_;
  PBYTE base_;
  PeFileType type_;
};

PeFile::PeFile(Process const& process, PVOID address, PeFileType type)
  : impl_(new Impl(process, address, type))
{ }

PeFile::PeFile(PeFile const& other)
  : impl_(new Impl(*other.impl_))
{ }

PeFile& PeFile::operator=(PeFile const& other)
{
  impl_ = std::unique_ptr<Impl>(new Impl(*other.impl_));

  return *this;
}

PeFile::PeFile(PeFile&& other) HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

PeFile& PeFile::operator=(PeFile&& other) HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

PeFile::~PeFile()
{ }

PVOID PeFile::GetBase() const HADESMEM_NOEXCEPT
{
  return impl_->base_;
}

PeFileType PeFile::GetType() const HADESMEM_NOEXCEPT
{
  return impl_->type_;
}

bool operator==(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() == rhs.GetBase();
}

bool operator!=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return !(lhs == rhs);
}

bool operator<(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() < rhs.GetBase();
}

bool operator<=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() <= rhs.GetBase();
}

bool operator>(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() > rhs.GetBase();
}

bool operator>=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() >= rhs.GetBase();
}

std::ostream& operator<<(std::ostream& lhs, PeFile const& rhs)
{
  return (lhs << rhs.GetBase());
}

std::wostream& operator<<(std::wostream& lhs, PeFile const& rhs)
{
  return (lhs << rhs.GetBase());
}

PVOID RvaToVa(Process const& process, PeFile const& pe_file, DWORD rva)
{
  PeFileType const type = pe_file.GetType();
  PBYTE base = static_cast<PBYTE>(pe_file.GetBase());

  if (type == PeFileType::Data)
  {
    if (!rva)
    {
      return nullptr;
    }

    SectionList sections(process, pe_file);
    for (auto const& section : sections)
    {
      DWORD const virtual_beg = section.GetVirtualAddress();
      DWORD const virtual_end = virtual_beg + section.GetVirtualSize();
      if (virtual_beg <= rva && rva < virtual_end)
      {
        rva -= virtual_beg;
        rva += section.GetPointerToRawData();

        return base + rva;
      }
    }

    return nullptr;
  }
  else if (type == PeFileType::Image)
  {
    return rva ? (base + rva) : nullptr;
  }
  else
  {
    HADESMEM_THROW_EXCEPTION(Error() <<
      ErrorString("Unhandled file type."));
  }
}

}
<commit_msg>* Harden RvaToVa against images with no sections.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/pe_file.hpp"

#include <cstddef>
#include <ostream>
#include <utility>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>
#include <winnt.h>

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/pelib/section.hpp"
#include "hadesmem/pelib/section_list.hpp"

namespace hadesmem
{

struct PeFile::Impl
{
  explicit Impl(Process const& process, PVOID address, PeFileType type)
    HADESMEM_NOEXCEPT
    : process_(&process),
    base_(static_cast<PBYTE>(address)),
    type_(type)
  {
    BOOST_ASSERT(base_ != 0);
  }

  Process const* process_;
  PBYTE base_;
  PeFileType type_;
};

PeFile::PeFile(Process const& process, PVOID address, PeFileType type)
  : impl_(new Impl(process, address, type))
{ }

PeFile::PeFile(PeFile const& other)
  : impl_(new Impl(*other.impl_))
{ }

PeFile& PeFile::operator=(PeFile const& other)
{
  impl_ = std::unique_ptr<Impl>(new Impl(*other.impl_));

  return *this;
}

PeFile::PeFile(PeFile&& other) HADESMEM_NOEXCEPT
  : impl_(std::move(other.impl_))
{ }

PeFile& PeFile::operator=(PeFile&& other) HADESMEM_NOEXCEPT
{
  impl_ = std::move(other.impl_);

  return *this;
}

PeFile::~PeFile()
{ }

PVOID PeFile::GetBase() const HADESMEM_NOEXCEPT
{
  return impl_->base_;
}

PeFileType PeFile::GetType() const HADESMEM_NOEXCEPT
{
  return impl_->type_;
}

bool operator==(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() == rhs.GetBase();
}

bool operator!=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return !(lhs == rhs);
}

bool operator<(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() < rhs.GetBase();
}

bool operator<=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() <= rhs.GetBase();
}

bool operator>(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() > rhs.GetBase();
}

bool operator>=(PeFile const& lhs, PeFile const& rhs) HADESMEM_NOEXCEPT
{
  return lhs.GetBase() >= rhs.GetBase();
}

std::ostream& operator<<(std::ostream& lhs, PeFile const& rhs)
{
  return (lhs << rhs.GetBase());
}

std::wostream& operator<<(std::wostream& lhs, PeFile const& rhs)
{
  return (lhs << rhs.GetBase());
}

PVOID RvaToVa(Process const& process, PeFile const& pe_file, DWORD rva)
{
  PeFileType const type = pe_file.GetType();
  PBYTE base = static_cast<PBYTE>(pe_file.GetBase());

  if (type == PeFileType::Data)
  {
    if (!rva)
    {
      return nullptr;
    }

    SectionList sections(process, pe_file);
    for (auto const& section : sections)
    {
      DWORD const virtual_beg = section.GetVirtualAddress();
      DWORD const virtual_end = virtual_beg + section.GetVirtualSize();
      if (virtual_beg <= rva && rva < virtual_end)
      {
        rva -= virtual_beg;
        rva += section.GetPointerToRawData();

        return base + rva;
      }
    }

    // For some stupid reason, Windows will load specially crafted images
    // with no sections.
    // TODO: Check whether FileAlignment and/or SectionAlignment should be
    // checked here. In the specially crafted image I'm testing this against
    // the value is '1' for both anyway, but I'd like to ensure it's not
    // possible for it to be higher, and if it is, whether it would affect
    // the RVA resolution here.
    if (std::begin(sections) == std::end(sections))
    {
      return base + rva;
    }

    return nullptr;
  }
  else if (type == PeFileType::Image)
  {
    return rva ? (base + rva) : nullptr;
  }
  else
  {
    HADESMEM_THROW_EXCEPTION(Error() <<
      ErrorString("Unhandled file type."));
  }
}

}
<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <tuple>
#include <utility>

namespace cu
{

/// Returns the size of a tuple as compile-time constant.
template <typename ...Ts>
constexpr std::size_t get_tuple_size( const std::tuple<Ts...> & )
{
  return sizeof...(Ts);
}

template <typename Tuple>
constexpr auto make_index_sequence( const Tuple & t )
{
  return std::make_index_sequence<get_tuple_size(t)>();
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ...indexes>
  void for_each_impl( Tuple && tuple,
                      F && f, std::index_sequence<indexes...> )
  {
    const auto _ = {(static_cast<void>(std::forward<F>(f)(
        std::get<indexes>(std::forward<Tuple>(tuple)) ) ),1)...};
    static_cast<void>(_);
  }

  template <typename Tuple1, typename Tuple2, typename F, std::size_t ...indexes>
  void for_each_impl( Tuple1 && tuple1,
                      Tuple2 && tuple2,
                      F && f,
                      std::index_sequence<indexes...> )
  {
    const auto _ = { (static_cast<void>( std::forward<F>(f)(
        std::get<indexes>(std::forward<Tuple1>(tuple1)),
        std::get<indexes>(std::forward<Tuple2>(tuple2)) ) ),1)... };
    static_cast<void>(_);
  }

} // namespace detail

/// Applies a functor to each element of a tuple.
///
/// The types of the elements can differ and it still works.
template <typename Tuple, typename F>
void for_each( Tuple && tuple, F && f )
{
  detail::for_each_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

/// Applies a functor to the elements of two tuples.
///
/// In effect, the following is called:
///   @code
///     f( get< 0 >(std::forward<Tuple1>(tuple1)),
///        get< 0 >(std::forward<Tuple2>(tuple2)) );
///         .
///         .
///         .
///     f( get<N-1>(std::forward<Tuple1>(tuple1)),
///        get<N-1>(std::forward<Tuple2>(tuple2)) );
///   @endcode
/// where @c N ist the size of both tuples. Note also, that proper forwarding
/// is applied to the elements of the tuples.
template <typename Tuple1, typename Tuple2, typename F>
void for_each( Tuple1 && tuple1,
               Tuple2 && tuple2,
               F && f )
{
  static_assert( get_tuple_size(tuple1) ==
                 get_tuple_size(tuple2),
                 "Tuples must have the same length." );
  detail::for_each_impl(
        std::forward<Tuple1>(tuple1),
        std::forward<Tuple2>(tuple2),
        std::forward<F>(f),
        make_index_sequence(tuple1) );
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ...indexes>
  decltype(auto) transform_impl( Tuple && tuple,
                                 F && f,
                                 std::index_sequence<indexes...> )
  {
    return std::make_tuple( f( std::get<indexes>( std::forward<Tuple>(tuple) ) )... );
  }

} // namespace detail

/// A functor is applied to every element of a tuple and the returned values
/// are returned in a tuple.
template <typename Tuple, typename F>
decltype(auto) transform( Tuple && tuple,
                          F && f )
{
  return detail::transform_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename T, typename Tuple, std::size_t ...indexes>
  auto to_array_impl( Tuple && tuple, std::index_sequence<indexes...> )
  {
    return std::array<T,get_tuple_size(tuple)>{
      std::get<indexes>( std::forward<Tuple>(tuple))... };
  }

}

/// Turns a tuple into an array.
///
/// The element type is not inferred, but must be specified.
template <typename T, typename Tuple>
auto to_array( Tuple && tuple )
{
  return detail::to_array_impl<T>(
        std::forward<Tuple>(tuple),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename F>
  struct ReverseAccumulator
  {
    ReverseAccumulator( F && f_ )
      : f(std::forward<F>(f_))
    {}

    template <typename ...Ts, typename T>
    decltype(auto) operator()( T && arg, Ts &&...args ) const
    {
      return f( std::move(*this)( std::forward<Ts>(args)... ),
                std::forward<T>(arg) );
    }

    template <typename T>
    T && operator()( T && arg ) const
    {
      return std::forward<T>(arg);
    }

  private:
    F && f;
  };

  template <typename Tuple, typename F, std::size_t ...indexes>
  decltype(auto) accumulate_impl( Tuple && tuple,
                        F && f,
                        std::index_sequence<indexes...> )
  {
    // The reverse accumulator is used for left to right associativity.
    // It must be reverse because elements of an argument pack must be
    // removed from the front while inferring parameters. In other words,
    // a template of the form
    //   @code
    //     template <typename ...Ts, typename T>
    //     void f( Ts &&...args, T && arg );
    //   @endcode
    // is ill-formed code, while
    //   @code
    //     template <typename ...Ts, typename T>
    //     void f( T && arg, Ts &&...args );
    //   @endcode
    // is perfectly valid.
    return ReverseAccumulator<F>(std::forward<F>(f))(
          std::get<get_tuple_size(tuple)-indexes-1>(std::forward<Tuple>(tuple))... );
  }

} // namespace detail

/// Accumulates the elements of a tuple given a specific functor.
///
/// If the elements of the tuple shall be added together, then the functor
/// parameter should be something like this:
///   @code
///     []( auto && rhs, auto && lhs ) { return rhs + lhs; }
///   @endcode
/// Note that the operation will be performed left to right associative
/// independent of the type of functor used.
template <typename Tuple, typename F>
decltype(auto) accumulate( Tuple && tuple,
                 F && f )
{
  return detail::accumulate_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ... indexes>
  bool any_of_impl( Tuple && tuple,
                    F && f,
                    std::index_sequence<indexes...> )
  {
    const std::array<bool,sizeof...(indexes)> values =
    { f( std::get<indexes>(tuple) )... };
    for ( bool value : values )
      if ( value )
        return true;
    return false;
  }

} // namespace detail

/// Returns @c true, iff any of the @c tuple elements evaluates to @true.
template <typename Tuple, typename F>
bool any_of( Tuple && tuple,
             F && f )
{
  return detail::any_of_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

/// This is a helper class which enables the prioritization of overloads.
///
/// If there are two overloads of a function that only differ in one argument
/// type, which are @c Rank<N> and @c Rang<M>, and the function is called
/// given an argument of type @c Rank<K> where @c K>=N and @K>=M, then
/// the overload with the larger @c Rank number will be selected by the
/// compiler.
///
/// This is helpful, when an overload shall be prioritized over another and
/// the prioritized overload may be excluded from overload resolution because
/// of SFINAE (Substitution Failure Is Not An Error).
template <std::size_t N>
class Rank;

template <>
class Rank<0> {};

template <std::size_t N>
class Rank : public Rank<N-1> {};

} // namespace cu
<commit_msg>Added the macro CU_FWD().<commit_after>#pragma once

#include <array>
#include <tuple>
#include <utility>

#define CU_FWD(arg) ::std::forward<decltype(arg)>(arg)

namespace cu
{

/// Returns the size of a tuple as compile-time constant.
template <typename ...Ts>
constexpr std::size_t get_tuple_size( const std::tuple<Ts...> & )
{
  return sizeof...(Ts);
}

template <typename Tuple>
constexpr auto make_index_sequence( const Tuple & t )
{
  return std::make_index_sequence<get_tuple_size(t)>();
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ...indexes>
  void for_each_impl( Tuple && tuple,
                      F && f, std::index_sequence<indexes...> )
  {
    const auto _ = {(static_cast<void>(std::forward<F>(f)(
        std::get<indexes>(std::forward<Tuple>(tuple)) ) ),1)...};
    static_cast<void>(_);
  }

  template <typename Tuple1, typename Tuple2, typename F, std::size_t ...indexes>
  void for_each_impl( Tuple1 && tuple1,
                      Tuple2 && tuple2,
                      F && f,
                      std::index_sequence<indexes...> )
  {
    const auto _ = { (static_cast<void>( std::forward<F>(f)(
        std::get<indexes>(std::forward<Tuple1>(tuple1)),
        std::get<indexes>(std::forward<Tuple2>(tuple2)) ) ),1)... };
    static_cast<void>(_);
  }

} // namespace detail

/// Applies a functor to each element of a tuple.
///
/// The types of the elements can differ and it still works.
template <typename Tuple, typename F>
void for_each( Tuple && tuple, F && f )
{
  detail::for_each_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

/// Applies a functor to the elements of two tuples.
///
/// In effect, the following is called:
///   @code
///     f( get< 0 >(std::forward<Tuple1>(tuple1)),
///        get< 0 >(std::forward<Tuple2>(tuple2)) );
///         .
///         .
///         .
///     f( get<N-1>(std::forward<Tuple1>(tuple1)),
///        get<N-1>(std::forward<Tuple2>(tuple2)) );
///   @endcode
/// where @c N ist the size of both tuples. Note also, that proper forwarding
/// is applied to the elements of the tuples.
template <typename Tuple1, typename Tuple2, typename F>
void for_each( Tuple1 && tuple1,
               Tuple2 && tuple2,
               F && f )
{
  static_assert( get_tuple_size(tuple1) ==
                 get_tuple_size(tuple2),
                 "Tuples must have the same length." );
  detail::for_each_impl(
        std::forward<Tuple1>(tuple1),
        std::forward<Tuple2>(tuple2),
        std::forward<F>(f),
        make_index_sequence(tuple1) );
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ...indexes>
  decltype(auto) transform_impl( Tuple && tuple,
                                 F && f,
                                 std::index_sequence<indexes...> )
  {
    return std::make_tuple( f( std::get<indexes>( std::forward<Tuple>(tuple) ) )... );
  }

} // namespace detail

/// A functor is applied to every element of a tuple and the returned values
/// are returned in a tuple.
template <typename Tuple, typename F>
decltype(auto) transform( Tuple && tuple,
                          F && f )
{
  return detail::transform_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename T, typename Tuple, std::size_t ...indexes>
  auto to_array_impl( Tuple && tuple, std::index_sequence<indexes...> )
  {
    return std::array<T,get_tuple_size(tuple)>{
      std::get<indexes>( std::forward<Tuple>(tuple))... };
  }

}

/// Turns a tuple into an array.
///
/// The element type is not inferred, but must be specified.
template <typename T, typename Tuple>
auto to_array( Tuple && tuple )
{
  return detail::to_array_impl<T>(
        std::forward<Tuple>(tuple),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename F>
  struct ReverseAccumulator
  {
    ReverseAccumulator( F && f_ )
      : f(std::forward<F>(f_))
    {}

    template <typename ...Ts, typename T>
    decltype(auto) operator()( T && arg, Ts &&...args ) const
    {
      return f( std::move(*this)( std::forward<Ts>(args)... ),
                std::forward<T>(arg) );
    }

    template <typename T>
    T && operator()( T && arg ) const
    {
      return std::forward<T>(arg);
    }

  private:
    F && f;
  };

  template <typename Tuple, typename F, std::size_t ...indexes>
  decltype(auto) accumulate_impl( Tuple && tuple,
                        F && f,
                        std::index_sequence<indexes...> )
  {
    // The reverse accumulator is used for left to right associativity.
    // It must be reverse because elements of an argument pack must be
    // removed from the front while inferring parameters. In other words,
    // a template of the form
    //   @code
    //     template <typename ...Ts, typename T>
    //     void f( Ts &&...args, T && arg );
    //   @endcode
    // is ill-formed code, while
    //   @code
    //     template <typename ...Ts, typename T>
    //     void f( T && arg, Ts &&...args );
    //   @endcode
    // is perfectly valid.
    return ReverseAccumulator<F>(std::forward<F>(f))(
          std::get<get_tuple_size(tuple)-indexes-1>(std::forward<Tuple>(tuple))... );
  }

} // namespace detail

/// Accumulates the elements of a tuple given a specific functor.
///
/// If the elements of the tuple shall be added together, then the functor
/// parameter should be something like this:
///   @code
///     []( auto && rhs, auto && lhs ) { return rhs + lhs; }
///   @endcode
/// Note that the operation will be performed left to right associative
/// independent of the type of functor used.
template <typename Tuple, typename F>
decltype(auto) accumulate( Tuple && tuple,
                 F && f )
{
  return detail::accumulate_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

namespace detail
{

  template <typename Tuple, typename F, std::size_t ... indexes>
  bool any_of_impl( Tuple && tuple,
                    F && f,
                    std::index_sequence<indexes...> )
  {
    const std::array<bool,sizeof...(indexes)> values =
    { f( std::get<indexes>(tuple) )... };
    for ( bool value : values )
      if ( value )
        return true;
    return false;
  }

} // namespace detail

/// Returns @c true, iff any of the @c tuple elements evaluates to @true.
template <typename Tuple, typename F>
bool any_of( Tuple && tuple,
             F && f )
{
  return detail::any_of_impl(
        std::forward<Tuple>(tuple),
        std::forward<F>(f),
        make_index_sequence(tuple) );
}

/// This is a helper class which enables the prioritization of overloads.
///
/// If there are two overloads of a function that only differ in one argument
/// type, which are @c Rank<N> and @c Rang<M>, and the function is called
/// given an argument of type @c Rank<K> where @c K>=N and @K>=M, then
/// the overload with the larger @c Rank number will be selected by the
/// compiler.
///
/// This is helpful, when an overload shall be prioritized over another and
/// the prioritized overload may be excluded from overload resolution because
/// of SFINAE (Substitution Failure Is Not An Error).
template <std::size_t N>
class Rank;

template <>
class Rank<0> {};

template <std::size_t N>
class Rank : public Rank<N-1> {};

} // namespace cu
<|endoftext|>


<commit_before>/**
 * @author : xiaozhuai
 * @date   : 17/3/20
 */

#include "AccessRule.h"

AccessRule AccessRule::instance;

void AccessRule::loadAccessRule() {

    string ruleFileName = SERV_ENV.getConfig(KEY_ACCESS_RULE, DEFAULT_ACCESS_RULE);

    /**
     * denied .efserv_access and .efserv_config by default
     */

    rules.push_back(Rule(false, ".efserv_config"));
    rules.push_back(Rule(false, ruleFileName));

    string rulePath = SERV_ENV.getAbsoluteWebRoot() + "/" + ruleFileName;
    FileHandler ruleFile(rulePath);
    string ruleText = ruleFile.readAsText();

    /**
     * first split by "\n"
     */
    vector<string> lines = StringUtils::split(ruleText, "\n");

    /**
     * parse each line
     */
    for(int i=0; i<lines.size(); i++){
        string line = lines[i];

        /**
         * trim line
         */
        trim(line, " ");

        /**
         * skip empty line
         */
        if(line.size()==0) continue;

        /**
         * skip comment line
         */
        if(line[0]=='#') continue;

        /**
         * split by '#' to avoid in-line comment
         */
        vector<string> tmp = StringUtils::split(line, "#", 2);
        string ruleBody = tmp[0];
        trim(ruleBody, " ");

        if(ruleBody.size()<3){
            LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
            continue;
        }
        bool permitted;
        switch (ruleBody[0]){
            case '+':
                permitted = true;
                break;
            case '-':
                permitted = false;
                break;
            default:
                LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
                continue;
        }
        if(ruleBody[1]==' '){
            string pattern = ruleBody.substr(2);
            rules.push_back(Rule(permitted, pattern));
            LOGD("Access rule recognized, permitted: %s, pattern: %s", permitted?"yes":"no", pattern);
        }else{
            LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
        }
    }
}

bool AccessRule::permissible(string url) {
    bool permitted = true;
    /**
     * go through all rules, the last matched rule will be effective
     */
    for(int i=0; i<rules.size(); i++){
        regex r(rules[i].pattern);
        if(regex_match(url, r))
            permitted = rules[i].permitted;
    }
    return permitted;
}<commit_msg>fix bug in AccessRule.cpp<commit_after>/**
 * @author : xiaozhuai
 * @date   : 17/3/20
 */

#include "AccessRule.h"

AccessRule AccessRule::instance;

void AccessRule::loadAccessRule() {

    string ruleFileName = SERV_ENV.getConfig(KEY_ACCESS_RULE, DEFAULT_ACCESS_RULE);

    /**
     * denied .efserv_access and .efserv_config by default
     */

    rules.push_back(Rule(false, "/.efserv_config"));
    rules.push_back(Rule(false, "/"+ruleFileName));

    string rulePath = SERV_ENV.getAbsoluteWebRoot() + "/" + ruleFileName;
    FileHandler ruleFile(rulePath);
    string ruleText = ruleFile.readAsText();

    /**
     * first split by "\n"
     */
    vector<string> lines = StringUtils::split(ruleText, "\n");

    /**
     * parse each line
     */
    for(int i=0; i<lines.size(); i++){
        string line = lines[i];

        /**
         * trim line
         */
        trim(line, " ");

        /**
         * skip empty line
         */
        if(line.size()==0) continue;

        /**
         * skip comment line
         */
        if(line[0]=='#') continue;

        /**
         * split by '#' to avoid in-line comment
         */
        vector<string> tmp = StringUtils::split(line, "#", 2);
        string ruleBody = tmp[0];
        trim(ruleBody, " ");

        if(ruleBody.size()<3){
            LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
            continue;
        }
        bool permitted;
        switch (ruleBody[0]){
            case '+':
                permitted = true;
                break;
            case '-':
                permitted = false;
                break;
            default:
                LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
                continue;
        }
        if(ruleBody[1]==' '){
            string pattern = ruleBody.substr(2);
            rules.push_back(Rule(permitted, pattern));
            LOGD("Access rule recognized, permitted: %s, pattern: %s", permitted?"yes":"no", pattern);
        }else{
            LOGW("Access rule not recognized, file: %s, line: %d, %s", rulePath, (i+1), ruleBody);
        }
    }
}

bool AccessRule::permissible(string url) {
    bool permitted = true;
    /**
     * go through all rules, the last matched rule will be effective
     */
    for(int i=0; i<rules.size(); i++){
        regex r(rules[i].pattern);
        if(regex_match(url, r))
            permitted = rules[i].permitted;
    }
    return permitted;
}<|endoftext|>


<commit_before><commit_msg>fdo#42151 fix RTF import of vertically merged table cells<commit_after><|endoftext|>