<commit_before>/****************************************************************************
**
** Copyright (C) 2014-2015 Jolla Ltd.
** Contact: slava.monich@jolla.com
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
****************************************************************************/

#include "qofonoobject.h"
#include "qofonoutils_p.h"

class QOfonoObject::Private
{
public:
    QOfonoObject::ExtData *ext;
    QDBusAbstractInterface *interface;
    bool initialized;
    bool fixedPath;
    QString objectPath;
    QVariantMap properties;

    Private(QOfonoObject::ExtData *data) : ext(data),
        interface(NULL), initialized(false), fixedPath(false) {}
    ~Private() { delete ext; }

    QDBusPendingCall setProperty(const QString &key, const QVariant &value);

    class SetPropertyWatcher : public QDBusPendingCallWatcher {
    public:
        QString property;
        SetPropertyWatcher(QDBusAbstractInterface *parent, const QString &name,
            const QDBusPendingCall &call) : QDBusPendingCallWatcher(call, parent),
            property(name) {}
    };
};

QOfonoObject::ExtData::~ExtData()
{
}

QDBusPendingCall QOfonoObject::Private::setProperty(const QString &key, const QVariant &value)
{
    // Caller checks interface for NULL
    QVariantList args;
    args << QVariant(key) << QVariant::fromValue(QDBusVariant(value));
    return interface->asyncCallWithArgumentList("SetProperty", args);
}

QOfonoObject::QOfonoObject(QObject *parent) :
    QObject(parent),
    d_ptr(new QOfonoObject::Private(NULL))
{
}

QOfonoObject::QOfonoObject(QOfonoObject::ExtData *ext, QObject *parent) :
    QObject(parent),
    d_ptr(new QOfonoObject::Private(ext))
{
}

QOfonoObject::~QOfonoObject()
{
    delete d_ptr;
}

QOfonoObject::ExtData* QOfonoObject::extData() const
{
    return d_ptr->ext;
}

QString QOfonoObject::objectPath() const
{
    return d_ptr->objectPath;
}

void QOfonoObject::setObjectPath(const QString &path, const QVariantMap *properties)
{
    if (d_ptr->fixedPath) {
        if (d_ptr->objectPath != path) {
            qWarning() << "Attempt to change a fixed path";
        }
    } else if (d_ptr->objectPath != path) {
        d_ptr->objectPath = path;
        objectPathChanged(path, properties);
    }
}

void QOfonoObject::fixObjectPath(const QString &path)
{
    if (d_ptr->fixedPath) {
        qWarning() << "Attempt to fix object path more than once";
    } else if (d_ptr->objectPath != path) {
        d_ptr->objectPath = path;
        d_ptr->fixedPath = true;
        objectPathChanged(path, NULL);
    }
}

void QOfonoObject::objectPathChanged(const QString &, const QVariantMap *properties)
{
    resetDbusInterface(properties);
}

bool QOfonoObject::isValid() const
{
    return d_ptr->interface && d_ptr->interface->isValid() && d_ptr->initialized;
}

QDBusAbstractInterface *QOfonoObject::dbusInterface() const
{
    return d_ptr->interface;
}

void QOfonoObject::resetDbusInterface(const QVariantMap *properties)
{
    setDbusInterface(d_ptr->objectPath.isEmpty() ? NULL :
        createDbusInterface(d_ptr->objectPath), properties);
}

void QOfonoObject::setDbusInterface(QDBusAbstractInterface *iface, const QVariantMap *properties)
{
    bool wasValid = isValid();
    d_ptr->initialized = false;
    if (d_ptr->interface) {
        delete d_ptr->interface;
        d_ptr->interface = NULL;
        dbusInterfaceDropped();
    }
    if (iface) {
        d_ptr->interface = iface;
        if (properties) {
            d_ptr->initialized = true;
            // Ofono objects have fixed sets of properties, there's no need to check
            // for disappearance or reappearance of individual properties.
            for (QVariantMap::ConstIterator it = properties->constBegin();
                it != properties->constEnd(); ++it) {
                updateProperty(it.key(), it.value());
            }
        } else {
            d_ptr->initialized = false;
            connect(new QDBusPendingCallWatcher(
                iface->asyncCall("GetProperties"), iface),
                SIGNAL(finished(QDBusPendingCallWatcher*)),
                SLOT(onGetPropertiesFinished(QDBusPendingCallWatcher*)));
        }
        connect(iface,
            SIGNAL(PropertyChanged(QString,QDBusVariant)),
            SLOT(onPropertyChanged(QString,QDBusVariant)));
    }
    bool valid = isValid();
    if (valid != wasValid) {
        Q_EMIT validChanged(valid);
    }
}

void QOfonoObject::dbusInterfaceDropped()
{
    if (!d_ptr->properties.isEmpty()) {
        const QStringList keys = d_ptr->properties.keys();
        for (int i=0; i<keys.size(); i++) {
            updateProperty(keys.at(i), QVariant());
        }
    }
}

void QOfonoObject::onGetPropertiesFinished(QDBusPendingCallWatcher *watch)
{
    watch->deleteLater();
    QDBusPendingReply<QVariantMap> reply(*watch);
    if (!reply.isError()) {
        getPropertiesFinished(reply.value(), NULL);
    } else {
        QDBusError error = reply.error();
        getPropertiesFinished(QVariantMap(), &error);
    }
}

void QOfonoObject::getPropertiesFinished(const QVariantMap &properties, const QDBusError *error)
{
    if (!error) {
        for (QVariantMap::ConstIterator it = properties.constBegin();
             it != properties.constEnd(); ++it) {
            updateProperty(it.key(), it.value());
        }
        d_ptr->initialized = true;
        if (isValid()) {
            Q_EMIT validChanged(true);
        }
    } else {
        qDebug() << *error;
        Q_EMIT reportError(error->message());
    }
}

void QOfonoObject::removeProperty(const QString &key)
{
    if (d_ptr->properties.remove(key) > 0) {
        propertyChanged(key, QVariant());
    }
}

QVariantMap QOfonoObject::getProperties() const
{
    return d_ptr->properties;
}

QVariant QOfonoObject::getProperty(const QString &key) const
{
    return d_ptr->properties.value(key);
}

QVariant QOfonoObject::convertProperty(const QString &key, const QVariant &value)
{
    return value;
}

void QOfonoObject::propertyChanged(const QString &key, const QVariant &value)
{
}

void QOfonoObject::updateProperty(const QString &key, const QVariant &value)
{
    QVariant oldValue = getProperty(key);
    QVariant newValue;
    if (value.isValid()) {
        newValue = convertProperty(key, value);
    }
    if (!qofono::safeVariantEq(oldValue, newValue)) {
        if (newValue.isValid()) {
            d_ptr->properties.insert(key, newValue);
        } else {
            d_ptr->properties.remove(key);
        }
        propertyChanged(key, newValue);
    }
}

void QOfonoObject::onPropertyChanged(const QString &key, const QDBusVariant &value)
{
    updateProperty(key, value.variant());
}

bool QOfonoObject::setPropertySync(const QString &key, const QVariant &value)
{
    if (d_ptr->interface) {
        QDBusPendingReply<> reply = d_ptr->setProperty(key, value);
        reply.waitForFinished();
        return reply.isValid() && !reply.isError();
    } else {
        return false;
    }
}

void QOfonoObject::setProperty(const QString &key, const QVariant &value)
{
    if (d_ptr->interface) {
        connect(new Private::SetPropertyWatcher(d_ptr->interface,
            key, d_ptr->setProperty(key, value)),
            SIGNAL(finished(QDBusPendingCallWatcher*)),
            SLOT(onSetPropertyFinished(QDBusPendingCallWatcher*)));
    }
}

void QOfonoObject::onSetPropertyFinished(QDBusPendingCallWatcher *watch)
{
    watch->deleteLater();
    QDBusPendingReply<> reply(*watch);
    QDBusError dbusError;
    const QDBusError *error;
    if (!reply.isError()) {
        error = NULL;
    } else {
        dbusError = reply.error();
        error = &dbusError;
    }
    setPropertyFinished(((Private::SetPropertyWatcher*)watch)->property, error);
}

void QOfonoObject::setPropertyFinished(const QString &property, const QDBusError *error)
{
    if (error) {
        qDebug() << qPrintable(property) << ": " << *error;
        Q_EMIT reportError(error->message());
    }
    Q_EMIT setPropertyFinished();
}
<commit_msg>[libqofono] Make sure property updates populate the property map. Fixes JB#30220<commit_after>/****************************************************************************
**
** Copyright (C) 2014-2015 Jolla Ltd.
** Contact: slava.monich@jolla.com
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
****************************************************************************/

#include "qofonoobject.h"
#include "qofonoutils_p.h"

class QOfonoObject::Private
{
public:
    QOfonoObject::ExtData *ext;
    QDBusAbstractInterface *interface;
    bool initialized;
    bool fixedPath;
    QString objectPath;
    QVariantMap properties;

    Private(QOfonoObject::ExtData *data) : ext(data),
        interface(NULL), initialized(false), fixedPath(false) {}
    ~Private() { delete ext; }

    QDBusPendingCall setProperty(const QString &key, const QVariant &value);

    class SetPropertyWatcher : public QDBusPendingCallWatcher {
    public:
        QString property;
        SetPropertyWatcher(QDBusAbstractInterface *parent, const QString &name,
            const QDBusPendingCall &call) : QDBusPendingCallWatcher(call, parent),
            property(name) {}
    };
};

QOfonoObject::ExtData::~ExtData()
{
}

QDBusPendingCall QOfonoObject::Private::setProperty(const QString &key, const QVariant &value)
{
    // Caller checks interface for NULL
    QVariantList args;
    args << QVariant(key) << QVariant::fromValue(QDBusVariant(value));
    return interface->asyncCallWithArgumentList("SetProperty", args);
}

QOfonoObject::QOfonoObject(QObject *parent) :
    QObject(parent),
    d_ptr(new QOfonoObject::Private(NULL))
{
}

QOfonoObject::QOfonoObject(QOfonoObject::ExtData *ext, QObject *parent) :
    QObject(parent),
    d_ptr(new QOfonoObject::Private(ext))
{
}

QOfonoObject::~QOfonoObject()
{
    delete d_ptr;
}

QOfonoObject::ExtData* QOfonoObject::extData() const
{
    return d_ptr->ext;
}

QString QOfonoObject::objectPath() const
{
    return d_ptr->objectPath;
}

void QOfonoObject::setObjectPath(const QString &path, const QVariantMap *properties)
{
    if (d_ptr->fixedPath) {
        if (d_ptr->objectPath != path) {
            qWarning() << "Attempt to change a fixed path";
        }
    } else if (d_ptr->objectPath != path) {
        d_ptr->objectPath = path;
        objectPathChanged(path, properties);
    }
}

void QOfonoObject::fixObjectPath(const QString &path)
{
    if (d_ptr->fixedPath) {
        qWarning() << "Attempt to fix object path more than once";
    } else if (d_ptr->objectPath != path) {
        d_ptr->objectPath = path;
        d_ptr->fixedPath = true;
        objectPathChanged(path, NULL);
    }
}

void QOfonoObject::objectPathChanged(const QString &, const QVariantMap *properties)
{
    resetDbusInterface(properties);
}

bool QOfonoObject::isValid() const
{
    return d_ptr->interface && d_ptr->interface->isValid() && d_ptr->initialized;
}

QDBusAbstractInterface *QOfonoObject::dbusInterface() const
{
    return d_ptr->interface;
}

void QOfonoObject::resetDbusInterface(const QVariantMap *properties)
{
    setDbusInterface(d_ptr->objectPath.isEmpty() ? NULL :
        createDbusInterface(d_ptr->objectPath), properties);
}

void QOfonoObject::setDbusInterface(QDBusAbstractInterface *iface, const QVariantMap *properties)
{
    bool wasValid = isValid();
    d_ptr->initialized = false;
    if (d_ptr->interface) {
        delete d_ptr->interface;
        d_ptr->interface = NULL;
        dbusInterfaceDropped();
    }
    if (iface) {
        d_ptr->interface = iface;
        if (properties) {
            d_ptr->initialized = true;
            // Ofono objects have fixed sets of properties, there's no need to check
            // for disappearance or reappearance of individual properties.
            for (QVariantMap::ConstIterator it = properties->constBegin();
                it != properties->constEnd(); ++it) {
                updateProperty(it.key(), it.value());
            }
        } else {
            d_ptr->initialized = false;
            connect(new QDBusPendingCallWatcher(
                iface->asyncCall("GetProperties"), iface),
                SIGNAL(finished(QDBusPendingCallWatcher*)),
                SLOT(onGetPropertiesFinished(QDBusPendingCallWatcher*)));
        }
        connect(iface,
            SIGNAL(PropertyChanged(QString,QDBusVariant)),
            SLOT(onPropertyChanged(QString,QDBusVariant)));
    }
    bool valid = isValid();
    if (valid != wasValid) {
        Q_EMIT validChanged(valid);
    }
}

void QOfonoObject::dbusInterfaceDropped()
{
    if (!d_ptr->properties.isEmpty()) {
        const QStringList keys = d_ptr->properties.keys();
        for (int i=0; i<keys.size(); i++) {
            updateProperty(keys.at(i), QVariant());
        }
    }
}

void QOfonoObject::onGetPropertiesFinished(QDBusPendingCallWatcher *watch)
{
    watch->deleteLater();
    QDBusPendingReply<QVariantMap> reply(*watch);
    if (!reply.isError()) {
        getPropertiesFinished(reply.value(), NULL);
    } else {
        QDBusError error = reply.error();
        getPropertiesFinished(QVariantMap(), &error);
    }
}

void QOfonoObject::getPropertiesFinished(const QVariantMap &properties, const QDBusError *error)
{
    if (!error) {
        for (QVariantMap::ConstIterator it = properties.constBegin();
             it != properties.constEnd(); ++it) {
            updateProperty(it.key(), it.value());
        }
        d_ptr->initialized = true;
        if (isValid()) {
            Q_EMIT validChanged(true);
        }
    } else {
        qDebug() << *error;
        Q_EMIT reportError(error->message());
    }
}

void QOfonoObject::removeProperty(const QString &key)
{
    if (d_ptr->properties.remove(key) > 0) {
        propertyChanged(key, QVariant());
    }
}

QVariantMap QOfonoObject::getProperties() const
{
    return d_ptr->properties;
}

QVariant QOfonoObject::getProperty(const QString &key) const
{
    return d_ptr->properties.value(key);
}

QVariant QOfonoObject::convertProperty(const QString &key, const QVariant &value)
{
    return value;
}

void QOfonoObject::propertyChanged(const QString &key, const QVariant &value)
{
}

void QOfonoObject::updateProperty(const QString &key, const QVariant &value)
{
    QVariant oldValue = getProperty(key);
    QVariant newValue;
    if (value.isValid()) {
        newValue = convertProperty(key, value);
    }
    if (!qofono::safeVariantEq(oldValue, newValue)) {
        if (newValue.isValid()) {
            d_ptr->properties.insert(key, newValue);
        } else {
            d_ptr->properties.remove(key);
        }
        propertyChanged(key, newValue);
    } else if (!oldValue.isValid() && newValue.isValid()) {
        // Not a change, but we need to insert the new value to make isReady() work.
        d_ptr->properties.insert(key, newValue);
    }
}

void QOfonoObject::onPropertyChanged(const QString &key, const QDBusVariant &value)
{
    updateProperty(key, value.variant());
}

bool QOfonoObject::setPropertySync(const QString &key, const QVariant &value)
{
    if (d_ptr->interface) {
        QDBusPendingReply<> reply = d_ptr->setProperty(key, value);
        reply.waitForFinished();
        return reply.isValid() && !reply.isError();
    } else {
        return false;
    }
}

void QOfonoObject::setProperty(const QString &key, const QVariant &value)
{
    if (d_ptr->interface) {
        connect(new Private::SetPropertyWatcher(d_ptr->interface,
            key, d_ptr->setProperty(key, value)),
            SIGNAL(finished(QDBusPendingCallWatcher*)),
            SLOT(onSetPropertyFinished(QDBusPendingCallWatcher*)));
    }
}

void QOfonoObject::onSetPropertyFinished(QDBusPendingCallWatcher *watch)
{
    watch->deleteLater();
    QDBusPendingReply<> reply(*watch);
    QDBusError dbusError;
    const QDBusError *error;
    if (!reply.isError()) {
        error = NULL;
    } else {
        dbusError = reply.error();
        error = &dbusError;
    }
    setPropertyFinished(((Private::SetPropertyWatcher*)watch)->property, error);
}

void QOfonoObject::setPropertyFinished(const QString &property, const QDBusError *error)
{
    if (error) {
        qDebug() << qPrintable(property) << ": " << *error;
        Q_EMIT reportError(error->message());
    }
    Q_EMIT setPropertyFinished();
}
<|endoftext|>


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

#include "app/keyboard_codes.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/views/chrome_views_delegate.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "views/view.h"
#include "views/accessibility/view_accessibility.h"
#include "views/widget/widget.h"
#include "views/window/window.h"

namespace {

class BrowserKeyboardAccessibility : public InProcessBrowserTest,
                                     public ChromeViewsDelegate {
 public:
  BrowserKeyboardAccessibility()
      : is_waiting_(false),
        current_view_(NULL),
        current_event_type_(AccessibilityTypes::EVENT_FOCUS) {
    // Set ourselves as the currently active ViewsDelegate.
    ViewsDelegate::views_delegate = this;
  }

  ~BrowserKeyboardAccessibility() {}

  // Overridden from ChromeViewsDelegate.
  // Save the last notification sent by views::View::NotifyAccessibilityEvent.
  virtual void NotifyAccessibilityEvent(
      views::View* view, AccessibilityTypes::Event event_type) {
    current_view_  = view;
    current_event_type_ = event_type;

    // Are we within a message loop waiting for a particular event?
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Got notification; is_waiting_ is "
               << (is_waiting_ ? "true" : "false");
    if (is_waiting_) {
      is_waiting_ = false;
      MessageLoop::current()->Quit();
    }
  }

  // Helper that performs tabbing until it cycles back to the original focus.
  void TabCyclerForwardAndBack(gfx::NativeWindow hwnd);
  void TabCycler(gfx::NativeWindow hwnd, bool forward_tab);

  views::View* current_view() const { return current_view_; }

  gfx::NativeWindow current_view_native_window() const {
    return current_view()->GetWidget()->GetNativeView();
  }

  AccessibilityTypes::Event current_event() const {
    return current_event_type_;
  }

  void set_waiting(bool value) { is_waiting_ = value; }

 private:
  // Are we waiting for an event?
  bool is_waiting_;

  // View of interest (i.e. for testing or one we are waiting to gain focus).
  views::View* current_view_;

  // Event type of interest.
  AccessibilityTypes::Event current_event_type_;
};

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInAboutChromeDialog) {
  views::Window* about_chrome_window =
      BrowserView::GetBrowserViewForNativeWindow(
          browser()->window()->GetNativeHandle())->ShowAboutChromeDialog();

  TabCyclerForwardAndBack(about_chrome_window->GetNativeWindow());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInClearBrowsingDataDialog) {
  browser()->OpenClearBrowsingDataDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInImportSettingsDialog) {
  browser()->OpenImportSettingsDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInKeywordEditor) {
  browser()->OpenKeywordEditor();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInOptionsDialog) {
  browser()->OpenOptionsDialog();

  // Tab through each of the three tabs.
  for (int i = 0; i < 3; ++i) {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Iteration no. " << i;

    TabCyclerForwardAndBack(current_view_native_window());

    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Sending TAB key event...";
    ui_controls::SendKeyPressNotifyWhenDone(current_view_native_window(),
                                            app::VKEY_TAB,
                                            true, false, false, false,
                                            new MessageLoop::QuitTask());
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
  }
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInPasswordManager) {
  browser()->OpenPasswordManager();
  TabCyclerForwardAndBack(current_view_native_window());
}

// TODO(dtseng): http://www.crbug.com/50402
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       FAILS_TabInSyncMyBookmarksDialog) {
  browser()->OpenSyncMyBookmarksDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInTaskManager) {
  browser()->OpenTaskManager();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInToolbar) {
  gfx::NativeWindow native_window = browser()->window()->GetNativeHandle();
  ui_controls::SendKeyPressNotifyWhenDone(native_window,
                                          app::VKEY_T,
                                          false, true, true, false,
                                          new MessageLoop::QuitTask());
  set_waiting(true);
  ui_test_utils::RunMessageLoop();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInUpdateChromeDialog) {
  browser()->OpenUpdateChromeDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

void BrowserKeyboardAccessibility::TabCyclerForwardAndBack(
    gfx::NativeWindow hwnd) {
  TabCycler(hwnd, true);
  TabCycler(hwnd, false);
}

void BrowserKeyboardAccessibility::TabCycler(gfx::NativeWindow hwnd,
                                             bool forward_tab) {
  // Wait for a focus event on the provided native window.
  while (current_event() != AccessibilityTypes::EVENT_FOCUS ||
         current_view_native_window() != hwnd) {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Runnig message loop...";
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
  }
  // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
  LOG(ERROR) << "After the loop.";

  views::View* first_focused_item = current_view();

  ASSERT_TRUE(first_focused_item != NULL);

  views::View* next_focused_item = first_focused_item;

  // Keep tabbing until we reach the originally focused view.
  do {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Sending TAB key event.";
    ui_controls::SendKeyPressNotifyWhenDone(hwnd, app::VKEY_TAB,
        false, !forward_tab, false, false, new MessageLoop::QuitTask());
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
    next_focused_item = current_view();
  } while (first_focused_item != next_focused_item);
  // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
  LOG(ERROR) << "After second loop.";
}

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

#include "app/keyboard_codes.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/views/chrome_views_delegate.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "views/view.h"
#include "views/accessibility/view_accessibility.h"
#include "views/widget/widget.h"
#include "views/window/window.h"

namespace {

class BrowserKeyboardAccessibility : public InProcessBrowserTest,
                                     public ChromeViewsDelegate {
 public:
  BrowserKeyboardAccessibility()
      : is_waiting_(false),
        current_view_(NULL),
        current_event_type_(AccessibilityTypes::EVENT_FOCUS) {
    // Set ourselves as the currently active ViewsDelegate.
    ViewsDelegate::views_delegate = this;
  }

  ~BrowserKeyboardAccessibility() {}

  // Overridden from ChromeViewsDelegate.
  // Save the last notification sent by views::View::NotifyAccessibilityEvent.
  virtual void NotifyAccessibilityEvent(
      views::View* view, AccessibilityTypes::Event event_type) {
    current_view_  = view;
    current_event_type_ = event_type;

    // Are we within a message loop waiting for a particular event?
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Got notification; is_waiting_ is "
               << (is_waiting_ ? "true" : "false");
    if (is_waiting_) {
      is_waiting_ = false;
      MessageLoop::current()->Quit();
    }
  }

  // Helper that performs tabbing until it cycles back to the original focus.
  void TabCyclerForwardAndBack(gfx::NativeWindow hwnd);
  void TabCycler(gfx::NativeWindow hwnd, bool forward_tab);

  views::View* current_view() const { return current_view_; }

  gfx::NativeWindow current_view_native_window() const {
    return current_view()->GetWidget()->GetNativeView();
  }

  AccessibilityTypes::Event current_event() const {
    return current_event_type_;
  }

  void set_waiting(bool value) { is_waiting_ = value; }

 private:
  // Are we waiting for an event?
  bool is_waiting_;

  // View of interest (i.e. for testing or one we are waiting to gain focus).
  views::View* current_view_;

  // Event type of interest.
  AccessibilityTypes::Event current_event_type_;
};

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInAboutChromeDialog) {
  views::Window* about_chrome_window =
      BrowserView::GetBrowserViewForNativeWindow(
          browser()->window()->GetNativeHandle())->ShowAboutChromeDialog();

  TabCyclerForwardAndBack(about_chrome_window->GetNativeWindow());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInClearBrowsingDataDialog) {
  browser()->OpenClearBrowsingDataDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInImportSettingsDialog) {
  browser()->OpenImportSettingsDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInKeywordEditor) {
  browser()->OpenKeywordEditor();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInOptionsDialog) {
  browser()->OpenOptionsDialog();

  // Tab through each of the three tabs.
  for (int i = 0; i < 3; ++i) {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Iteration no. " << i;

    TabCyclerForwardAndBack(current_view_native_window());

    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Sending TAB key event...";
    ui_controls::SendKeyPressNotifyWhenDone(current_view_native_window(),
                                            app::VKEY_TAB,
                                            true, false, false, false,
                                            new MessageLoop::QuitTask());
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
  }
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInPasswordManager) {
  browser()->OpenPasswordManager();
  TabCyclerForwardAndBack(current_view_native_window());
}

// TODO(dtseng): http://www.crbug.com/50402
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInSyncMyBookmarksDialog) {
  browser()->OpenSyncMyBookmarksDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInTaskManager) {
  browser()->OpenTaskManager();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInToolbar) {
  gfx::NativeWindow native_window = browser()->window()->GetNativeHandle();
  ui_controls::SendKeyPressNotifyWhenDone(native_window,
                                          app::VKEY_T,
                                          false, true, true, false,
                                          new MessageLoop::QuitTask());
  set_waiting(true);
  ui_test_utils::RunMessageLoop();
  TabCyclerForwardAndBack(current_view_native_window());
}

// This test is disabled, see bug 50864.
IN_PROC_BROWSER_TEST_F(BrowserKeyboardAccessibility,
                       DISABLED_TabInUpdateChromeDialog) {
  browser()->OpenUpdateChromeDialog();
  TabCyclerForwardAndBack(current_view_native_window());
}

void BrowserKeyboardAccessibility::TabCyclerForwardAndBack(
    gfx::NativeWindow hwnd) {
  TabCycler(hwnd, true);
  TabCycler(hwnd, false);
}

void BrowserKeyboardAccessibility::TabCycler(gfx::NativeWindow hwnd,
                                             bool forward_tab) {
  // Wait for a focus event on the provided native window.
  while (current_event() != AccessibilityTypes::EVENT_FOCUS ||
         current_view_native_window() != hwnd) {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Runnig message loop...";
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
  }
  // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
  LOG(ERROR) << "After the loop.";

  views::View* first_focused_item = current_view();

  ASSERT_TRUE(first_focused_item != NULL);

  views::View* next_focused_item = first_focused_item;

  // Keep tabbing until we reach the originally focused view.
  do {
    // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
    LOG(ERROR) << "Sending TAB key event.";
    ui_controls::SendKeyPressNotifyWhenDone(hwnd, app::VKEY_TAB,
        false, !forward_tab, false, false, new MessageLoop::QuitTask());
    set_waiting(true);
    ui_test_utils::RunMessageLoop();
    next_focused_item = current_view();
  } while (first_focused_item != next_focused_item);
  // TODO(phajdan.jr): remove logging after fixing http://crbug.com/50663.
  LOG(ERROR) << "After second loop.";
}

}  // namespace
<|endoftext|>


<commit_before>/*
 *   Copyright (c) 2012 - 2015 Kulykov Oleh <info@resident.name>
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#include "../include/REMutex.h"

#if defined(HAVE_RECORE_CONFIG_H)
#include "recore_config.h"
#endif

#if defined(HAVE_ASSERT_H)
#include <assert.h>
#endif

#if !defined(__RE_HAVE_THREADS__) && defined(__RE_OS_WINDOWS__)
#include <Windows.h>
#define __RE_THREADING_WINDOWS__ 1
#define __RE_HAVE_THREADS__ 1
#endif

#if !defined(__RE_HAVE_THREADS__) && defined(HAVE_PTHREAD_H)
#include <pthread.h>
#define __RE_THREADING_PTHREAD__ 1
#define __RE_HAVE_THREADS__ 1
#endif

bool REMutex::lock() const
{
#if defined(__RE_THREADING_PTHREAD__)
	if (_m)
	{
		pthread_mutex_t * m = const_cast<pthread_mutex_t *>(static_cast<const pthread_mutex_t *>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const bool r = (pthread_mutex_lock(m) == 0);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return r;
	}
	return false;
#elif defined(__RE_THREADING_WINDOWS__)
	if (_m)
	{
		LPCRITICAL_SECTION m = const_cast<LPCRITICAL_SECTION>(static_cast<const LPCRITICAL_SECTION>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const BOOL r = TryEnterCriticalSection(m);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return r;
	}
#else
	return false;
#endif
}

bool REMutex::unlock() const
{
#if defined(__RE_THREADING_PTHREAD__)
	if (_m)
	{
		pthread_mutex_t * m = const_cast<pthread_mutex_t *>(static_cast<const pthread_mutex_t *>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const bool r = (pthread_mutex_unlock(m) == 0);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return r;
	}
	return false;
#elif defined(__RE_THREADING_WINDOWS__)
	if (_m)
	{
		LPCRITICAL_SECTION m = const_cast<LPCRITICAL_SECTION>(static_cast<const LPCRITICAL_SECTION>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		LeaveCriticalSection(m);
		return true;
	}
#else
	return false;
#endif
}

#if defined(__RE_THREADING_PTHREAD__)
bool remutex_init_recursive_private(pthread_mutex_t * m)
{
	bool isInit = false;
	pthread_mutexattr_t attr;
	if (pthread_mutexattr_init(&attr) == 0)
	{
		if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0)
			isInit = (pthread_mutex_init(m, &attr) == 0);
		pthread_mutexattr_destroy(&attr);
	}
#if defined(HAVE_ASSERT_H)
	assert(isInit);
#endif
	return isInit;
}
#endif

REMutex::REMutex() : _m(NULL)
{
#if defined(__RE_THREADING_PTHREAD__)
	void * m = malloc(sizeof(pthread_mutex_t));
#if defined(HAVE_ASSERT_H)
	assert(m);
#endif
	if (m)
	{
		if (remutex_init_recursive_private((pthread_mutex_t *)m)) _m = m;
		else free(m);
	}
#elif defined(__RE_THREADING_WINDOWS__)
	_m = malloc(sizeof(CRITICAL_SECTION));
#if defined(HAVE_ASSERT_H)
	assert(_m);
#endif
	if (_m) InitializeCriticalSection((LPCRITICAL_SECTION)_m);
#endif
}

REMutex::~REMutex()
{
	if (_m)
	{
#if defined(__RE_THREADING_PTHREAD__)
		pthread_mutex_destroy((pthread_mutex_t *)_m);
#elif defined(__RE_THREADING_WINDOWS__)
		DeleteCriticalSection((LPCRITICAL_SECTION)_m);
#endif
		free(_m);
	}
}

<commit_msg>Mutex cast BOOL to bool<commit_after>/*
 *   Copyright (c) 2012 - 2015 Kulykov Oleh <info@resident.name>
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#include "../include/REMutex.h"

#if defined(HAVE_RECORE_CONFIG_H)
#include "recore_config.h"
#endif

#if defined(HAVE_ASSERT_H)
#include <assert.h>
#endif

#if !defined(__RE_HAVE_THREADS__) && defined(__RE_OS_WINDOWS__)
#include <Windows.h>
#define __RE_THREADING_WINDOWS__ 1
#define __RE_HAVE_THREADS__ 1
#endif

#if !defined(__RE_HAVE_THREADS__) && defined(HAVE_PTHREAD_H)
#include <pthread.h>
#define __RE_THREADING_PTHREAD__ 1
#define __RE_HAVE_THREADS__ 1
#endif

bool REMutex::lock() const
{
#if defined(__RE_THREADING_PTHREAD__)
	if (_m)
	{
		pthread_mutex_t * m = const_cast<pthread_mutex_t *>(static_cast<const pthread_mutex_t *>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const bool r = (pthread_mutex_lock(m) == 0);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return r;
	}
	return false;
#elif defined(__RE_THREADING_WINDOWS__)
	if (_m)
	{
		LPCRITICAL_SECTION m = const_cast<LPCRITICAL_SECTION>(static_cast<const LPCRITICAL_SECTION>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const BOOL r = TryEnterCriticalSection(m);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return (bool)r;
	}
#else
	return false;
#endif
}

bool REMutex::unlock() const
{
#if defined(__RE_THREADING_PTHREAD__)
	if (_m)
	{
		pthread_mutex_t * m = const_cast<pthread_mutex_t *>(static_cast<const pthread_mutex_t *>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		const bool r = (pthread_mutex_unlock(m) == 0);
#if defined(HAVE_ASSERT_H)
		assert(r);
#endif
		return r;
	}
	return false;
#elif defined(__RE_THREADING_WINDOWS__)
	if (_m)
	{
		LPCRITICAL_SECTION m = const_cast<LPCRITICAL_SECTION>(static_cast<const LPCRITICAL_SECTION>(_m));
#if defined(HAVE_ASSERT_H)
		assert(m);
#endif
		LeaveCriticalSection(m);
		return true;
	}
#else
	return false;
#endif
}

#if defined(__RE_THREADING_PTHREAD__)
bool remutex_init_recursive_private(pthread_mutex_t * m)
{
	bool isInit = false;
	pthread_mutexattr_t attr;
	if (pthread_mutexattr_init(&attr) == 0)
	{
		if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0)
			isInit = (pthread_mutex_init(m, &attr) == 0);
		pthread_mutexattr_destroy(&attr);
	}
#if defined(HAVE_ASSERT_H)
	assert(isInit);
#endif
	return isInit;
}
#endif

REMutex::REMutex() : _m(NULL)
{
#if defined(__RE_THREADING_PTHREAD__)
	void * m = malloc(sizeof(pthread_mutex_t));
#if defined(HAVE_ASSERT_H)
	assert(m);
#endif
	if (m)
	{
		if (remutex_init_recursive_private((pthread_mutex_t *)m)) _m = m;
		else free(m);
	}
#elif defined(__RE_THREADING_WINDOWS__)
	_m = malloc(sizeof(CRITICAL_SECTION));
#if defined(HAVE_ASSERT_H)
	assert(_m);
#endif
	if (_m) InitializeCriticalSection((LPCRITICAL_SECTION)_m);
#endif
}

REMutex::~REMutex()
{
	if (_m)
	{
#if defined(__RE_THREADING_PTHREAD__)
		pthread_mutex_destroy((pthread_mutex_t *)_m);
#elif defined(__RE_THREADING_WINDOWS__)
		DeleteCriticalSection((LPCRITICAL_SECTION)_m);
#endif
		free(_m);
	}
}

<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <fstream>

#include <string>
#include <map>
#include "ClassFile.h"

using namespace std;

map<string, string> classRemap;
map<string, string> fieldRemap;
map<string, string> methodRemap;

namespace
{
string getString(ClassFile const& class_, int index)
{
  return class_.const_pool[index].utf8;
}

void replaceAll(std::string& str, const std::string& from, const std::string& to)
{
  if(from.empty())
    return;

  size_t i = 0;

  while((i = str.find(from, i)) != std::string::npos)
  {
    str.replace(i, from.length(), to);
    i += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
  }
}

void remapDescriptorQuickAndDirty(ConstPoolInfo& desc)
{
  assert(desc.tag == CONSTANT::Utf8);

  for(auto& remapping : classRemap)
  {
    auto const from = "L" + remapping.first + ";";
    auto const to = "L" + remapping.second + ";";
    replaceAll(desc.utf8, from, to);
  }
}

void remapFieldDescriptor(ConstPoolInfo& desc)
{
  assert(desc.tag == CONSTANT::Utf8);

  if(desc.utf8[0] == 'L')
  {
    assert(desc.utf8.back() == ';');

    auto const origClassName = desc.utf8.substr(1, desc.utf8.size() - 2);
    auto i_newName = classRemap.find(origClassName);

    if(i_newName != classRemap.end())
      desc.utf8 = "L" + i_newName->second + ";";
  }
}

int addUtf8(ClassFile& class_, string text)
{
  auto const idx = (int)class_.const_pool.size();
  class_.const_pool_count++;
  class_.const_pool.push_back({ CONSTANT::Utf8, {}, text });
  return idx;
}

void renameClasses(ClassFile& class_)
{
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Class)
    {
      auto& classNameEntry = class_.const_pool[constant.name_index];

      auto const& origClassName = classNameEntry.utf8;
      auto i_newName = classRemap.find(origClassName);

      if(i_newName != classRemap.end())
        constant.name_index = addUtf8(class_, i_newName->second);
    }
    else if(constant.tag == CONSTANT::NameAndType)
    {
      auto& typeNameEntry = class_.const_pool[constant.descriptor_index];
      remapDescriptorQuickAndDirty(typeNameEntry);
    }
  }

  for(auto& field : class_.fields)
  {
    auto& desc = class_.const_pool[field.descriptor_index];
    remapFieldDescriptor(desc);
  }

  // rename class names in method signatures
  for(auto& method : class_.methods)
  {
    auto& desc = class_.const_pool[method.descriptor_index];
    remapDescriptorQuickAndDirty(desc);
  }
}

void renameFields(ClassFile& class_)
{
  // the fields I'm referring to as a class file
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Fieldref)
    {
      auto const& className = getString(class_, class_.const_pool[constant.class_index].name_index);
      auto& nameAndType = class_.const_pool[constant.name_and_type_index];
      auto const& fieldOrigName = getString(class_, nameAndType.name_index);

      auto i_newName = fieldRemap.find(className + "::" + fieldOrigName);

      if(i_newName != fieldRemap.end())
        nameAndType.name_index = addUtf8(class_, i_newName->second);
    }
  }

  // the fields I'm declaring as a class file
  for(auto& field : class_.fields)
  {
    auto const& className = getString(class_, class_.const_pool[class_.this_class].name_index);
    auto const& fieldOrigName = getString(class_, field.name_index);

    auto i_newName = fieldRemap.find(className + "::" + fieldOrigName);

    if(i_newName != fieldRemap.end())
      field.name_index = addUtf8(class_, i_newName->second);
  }
}

void renameMethods(ClassFile& class_)
{
  // the methods I'm referring to as a class file
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Methodref)
    {
      auto const& className = getString(class_, class_.const_pool[constant.class_index].name_index);
      auto& nameAndType = class_.const_pool[constant.name_and_type_index];
      auto const& origName = getString(class_, nameAndType.name_index);

      auto i_newName = methodRemap.find(className + "::" + origName);

      if(i_newName != methodRemap.end())
        nameAndType.name_index = addUtf8(class_, i_newName->second);
    }
  }

  // the methods I'm declaring as a class file
  for(auto& method : class_.methods)
  {
    auto const& className = getString(class_, class_.const_pool[class_.this_class].name_index);
    auto const& fieldOrigName = getString(class_, method.name_index);

    auto i_newName = methodRemap.find(className + "::" + fieldOrigName);

    if(i_newName != methodRemap.end())
      method.name_index = addUtf8(class_, i_newName->second);
  }
}
}

void doRenamings(ClassFile& class_)
{
  // HACK: avoid array re-allocation when adding new utf8 descriptors
  class_.const_pool.reserve(class_.const_pool.size() * 4);

  renameClasses(class_);
  renameFields(class_);
  renameMethods(class_);

  class_.const_pool.shrink_to_fit();
}

<commit_msg>Avoid global variable access<commit_after>#include <cassert>
#include <iostream>
#include <fstream>

#include <string>
#include <map>
#include "ClassFile.h"

using namespace std;

map<string, string> classRemap;
map<string, string> fieldRemap;
map<string, string> methodRemap;

namespace
{
string getString(ClassFile const& class_, int index)
{
  return class_.const_pool[index].utf8;
}

void replaceAll(std::string& str, const std::string& from, const std::string& to)
{
  if(from.empty())
    return;

  size_t i = 0;

  while((i = str.find(from, i)) != std::string::npos)
  {
    str.replace(i, from.length(), to);
    i += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
  }
}

void remapDescriptorQuickAndDirty(ConstPoolInfo& desc)
{
  assert(desc.tag == CONSTANT::Utf8);

  for(auto& remapping : classRemap)
  {
    auto const from = "L" + remapping.first + ";";
    auto const to = "L" + remapping.second + ";";
    replaceAll(desc.utf8, from, to);
  }
}

void remapFieldDescriptor(ConstPoolInfo& desc)
{
  assert(desc.tag == CONSTANT::Utf8);

  if(desc.utf8[0] == 'L')
  {
    assert(desc.utf8.back() == ';');

    auto const origClassName = desc.utf8.substr(1, desc.utf8.size() - 2);
    auto i_newName = classRemap.find(origClassName);

    if(i_newName != classRemap.end())
      desc.utf8 = "L" + i_newName->second + ";";
  }
}

int addUtf8(ClassFile& class_, string text)
{
  auto const idx = (int)class_.const_pool.size();
  class_.const_pool_count++;
  class_.const_pool.push_back({ CONSTANT::Utf8, {}, text });
  return idx;
}

void renameClasses(ClassFile& class_)
{
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Class)
    {
      auto& classNameEntry = class_.const_pool[constant.name_index];

      auto const& origClassName = classNameEntry.utf8;
      auto i_newName = classRemap.find(origClassName);

      if(i_newName != classRemap.end())
        constant.name_index = addUtf8(class_, i_newName->second);
    }
    else if(constant.tag == CONSTANT::NameAndType)
    {
      auto& typeNameEntry = class_.const_pool[constant.descriptor_index];
      remapDescriptorQuickAndDirty(typeNameEntry);
    }
  }

  for(auto& field : class_.fields)
  {
    auto& desc = class_.const_pool[field.descriptor_index];
    remapFieldDescriptor(desc);
  }

  // rename class names in method signatures
  for(auto& method : class_.methods)
  {
    auto& desc = class_.const_pool[method.descriptor_index];
    remapDescriptorQuickAndDirty(desc);
  }
}

void renameFields(ClassFile& class_, map<string, string> const& remap)
{
  // the fields I'm referring to as a class file
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Fieldref)
    {
      auto const& className = getString(class_, class_.const_pool[constant.class_index].name_index);
      auto& nameAndType = class_.const_pool[constant.name_and_type_index];
      auto const& origName = getString(class_, nameAndType.name_index);

      auto i_newName = remap.find(className + "::" + origName);

      if(i_newName != remap.end())
        nameAndType.name_index = addUtf8(class_, i_newName->second);
    }
  }

  // the fields I'm declaring as a class file
  for(auto& field : class_.fields)
  {
    auto const& className = getString(class_, class_.const_pool[class_.this_class].name_index);
    auto const& origName = getString(class_, field.name_index);

    auto i_newName = remap.find(className + "::" + origName);

    if(i_newName != remap.end())
      field.name_index = addUtf8(class_, i_newName->second);
  }
}

void renameMethods(ClassFile& class_, map<string, string> const& remap)
{
  // the methods I'm referring to as a class file
  for(auto& constant : class_.const_pool)
  {
    if(constant.tag == CONSTANT::Methodref)
    {
      auto const& className = getString(class_, class_.const_pool[constant.class_index].name_index);
      auto& nameAndType = class_.const_pool[constant.name_and_type_index];
      auto const& origName = getString(class_, nameAndType.name_index);

      auto i_newName = remap.find(className + "::" + origName);

      if(i_newName != remap.end())
        nameAndType.name_index = addUtf8(class_, i_newName->second);
    }
  }

  // the methods I'm declaring as a class file
  for(auto& method : class_.methods)
  {
    auto const& className = getString(class_, class_.const_pool[class_.this_class].name_index);
    auto const& fieldOrigName = getString(class_, method.name_index);

    auto i_newName = remap.find(className + "::" + fieldOrigName);

    if(i_newName != remap.end())
      method.name_index = addUtf8(class_, i_newName->second);
  }
}
}

void doRenamings(ClassFile& class_)
{
  // HACK: avoid array re-allocation when adding new utf8 descriptors
  class_.const_pool.reserve(class_.const_pool.size() * 4);

  renameClasses(class_);
  renameFields(class_, fieldRemap);
  renameMethods(class_, methodRemap);

  class_.const_pool.shrink_to_fit();
}

<|endoftext|>


<commit_before>/****************************************************************************
**   ncw is the nodecast worker, client of the nodecast server
**   Copyright (C) 2010-2011  Frédéric Logier <frederic@logier.org>
**
**   https://github.com/nodecast/ncw
**
**   This program is free software: you can redistribute it and/or modify
**   it under the terms of the GNU Affero General Public License as
**   published by the Free Software Foundation, either version 3 of the
**   License, or (at your option) any later version.
**
**   This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**   GNU Affero General Public License for more details.
**
**   You should have received a copy of the GNU Affero General Public License
**   along with this program.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

#include "stats_memory.h"

Stats_memory::Stats_memory(Nosql& a, QString memcached_keycache) : Stats(a)
{
    cache_path.append(memcached_keycache).append(":views/report/memory/");
}

Stats_memory::~Stats_memory()
{}

void Stats_memory::s_job_receive(bson::bo payload) {

    bo bo_memory_statistics;
    bob bob_memory_statistics;
    bo bo_stats_memory;
    bob bob_stats_memory;

    qDebug() << "Stats_memory::s_job_receive";
    std::cout << "RECEIVE MESSAGE" << std::endl;

    be created_at = payload["headers"]["created_at"];
    std::cout << created_at.jsonString(TenGen) << std::endl;

    be uuid = payload["headers"]["uuid"];

    bo host = nosql_.Find("hosts", uuid.wrap());
    be host_id = host.getField("_id");

    if (host.nFields() == 0)
    {
        std::cout << "Stats_memory::s_job_receive, HOST NOT FOUND" << std::endl;
        return;
    }

    std::cout << "Stats_memory::s_job_receive, _id : " << host.getField("_id") << std::endl;

     //std::cout << "loadavg0 : " << r_hash msg.getField("loadavg0").toString() << std::endl;

    //std::cout << "loadavg0 : " << uuid.toString() << std::endl;

    bob_memory_statistics << mongo::GENOID;
    bob_memory_statistics << "host_id" << host_id;
    bob_memory_statistics.append(created_at);
    bob_memory_statistics << "mem_used" << QString::fromStdString(payload["memory"]["mem_used"].valuestr()).toDouble()
                       << "mem_free" << QString::fromStdString(payload["memory"]["mem_free"].valuestr()).toDouble()
                       << "mem_actual_free" << QString::fromStdString(payload["memory"]["mem_actual_free"].valuestr()).toDouble()
                       << "mem_actual_used" << QString::fromStdString(payload["memory"]["mem_actual_used"].valuestr()).toDouble()
                       << "mem_actual_free_percent" << QString::fromStdString(payload["memory"]["mem_actual_free_percent"].valuestr()).toDouble()
                       << "mem_actual_used_percent" << QString::fromStdString(payload["memory"]["mem_actual_used_percent"].valuestr()).toDouble()
                       << "swap_total" << QString::fromStdString(payload["memory"]["swap_total"].valuestr()).toDouble()
                       << "swap_used" << QString::fromStdString(payload["memory"]["swap_used"].valuestr()).toDouble()
                       << "swap_free" << QString::fromStdString(payload["memory"]["swap_free"].valuestr()).toDouble()
                       << "swap_page_in" << QString::fromStdString(payload["memory"]["swap_page_in"].valuestr()).toDouble()
                       << "swap_page_out" << QString::fromStdString(payload["memory"]["swap_page_out"].valuestr()).toDouble();
    bo_memory_statistics = bob_memory_statistics.obj();

    nosql_.Insert("memory_statistics", bo_memory_statistics);

    qDebug() << "memory stats inserted";

    std::cout << "stats_memory? : " << host.hasField("stats_memory") << std::endl;

    //std::cout << "stats_cpu.number : " << host.getFieldDotted("stats_cpu.number").Int() + 1 << std::endl;

    long long counter = host.hasField("stats_memory") ? host.getFieldDotted("stats_memory.counter").numberLong() + 1 : 1;
    double mem_used = QString::fromStdString(payload["memory"]["mem_used"].valuestr()).toDouble();

    double max_mem_used = (host.hasField("stats_memory") && mem_used < host.getFieldDotted("stats_memory.max_mem_used").Double()) ? host.getFieldDotted("stats_memory.max_mem_used").Double() : mem_used;
    double all_mem_used = (host.hasField("stats_memory")) ? host.getFieldDotted("stats_memory.all_mem_used").Double() + mem_used : mem_used;

    //if (!host.hasField("stats_memory")) bob_stats_memory.append(msg.getField("created_at"));
    if (!host.hasField("stats_memory")) bob_stats_memory << "stats_memory.created_at" << created_at;
    bob_stats_memory << "stats_memory.updated_at" << created_at;
    bob_stats_memory << "stats_memory.counter" << counter;
    bob_stats_memory << "stats_memory.mem_used" << mem_used;
    bob_stats_memory << "stats_memory.all_mem_used" << all_mem_used;
    bob_stats_memory << "stats_memory.average_mem_used" << all_mem_used / counter;
    bob_stats_memory << "stats_memory.max_mem_used" << max_mem_used;
    bob_stats_memory << "stats_memory.swap_total" << payload["memory"]["swap_total"].Double();

    //bo_stats_memory = BSONObjBuilder().append("stats_memory", bob_stats_memory.obj()).obj();
    bo_stats_memory = bob_stats_memory.obj();
    nosql_.Update("hosts", host_id.wrap(), bo_stats_memory);

    std::cout << "bo_stats_memory : " << bo_stats_memory.toString() << std::endl;

    std::cout << "cache path : " << cache_path.toStdString() << std::endl;
    emit delete_cache(cache_path + uuid.String().data());

/*if (endCondition(message)) {
       subscriptions.cancel(message.getDestination());
    }*/

}
<commit_msg>fixed bson payload<commit_after>/****************************************************************************
**   ncw is the nodecast worker, client of the nodecast server
**   Copyright (C) 2010-2011  Frédéric Logier <frederic@logier.org>
**
**   https://github.com/nodecast/ncw
**
**   This program is free software: you can redistribute it and/or modify
**   it under the terms of the GNU Affero General Public License as
**   published by the Free Software Foundation, either version 3 of the
**   License, or (at your option) any later version.
**
**   This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**   GNU Affero General Public License for more details.
**
**   You should have received a copy of the GNU Affero General Public License
**   along with this program.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

#include "stats_memory.h"

Stats_memory::Stats_memory(Nosql& a, QString memcached_keycache) : Stats(a)
{
    cache_path.append(memcached_keycache).append(":views/report/memory/");
}

Stats_memory::~Stats_memory()
{}

void Stats_memory::s_job_receive(bson::bo payload) {

    bo bo_memory_statistics;
    bob bob_memory_statistics;
    bo bo_stats_memory;
    bob bob_stats_memory;

    qDebug() << "Stats_memory::s_job_receive";
    std::cout << "RECEIVE MESSAGE" << std::endl;

    be created_at = payload["headers"]["created_at"];
    std::cout << created_at.jsonString(TenGen) << std::endl;

    be uuid = payload["headers"]["uuid"];

    bo host = nosql_.Find("hosts", uuid.wrap());
    be host_id = host.getField("_id");

    if (host.nFields() == 0)
    {
        std::cout << "Stats_memory::s_job_receive, HOST NOT FOUND" << std::endl;
        return;
    }

    std::cout << "Stats_memory::s_job_receive, _id : " << host.getField("_id") << std::endl;

     //std::cout << "loadavg0 : " << r_hash msg.getField("loadavg0").toString() << std::endl;

    //std::cout << "loadavg0 : " << uuid.toString() << std::endl;

    bob_memory_statistics << mongo::GENOID;
    bob_memory_statistics << "host_id" << host_id;
    bob_memory_statistics.append(created_at);
    bob_memory_statistics << "mem_used" << QString::fromStdString(payload["memory"]["mem_used"].valuestr()).toDouble()
                       << "mem_free" << QString::fromStdString(payload["memory"]["mem_free"].valuestr()).toDouble()
                       << "mem_actual_free" << QString::fromStdString(payload["memory"]["mem_actual_free"].valuestr()).toDouble()
                       << "mem_actual_used" << QString::fromStdString(payload["memory"]["mem_actual_used"].valuestr()).toDouble()
                       << "mem_actual_free_percent" << QString::fromStdString(payload["memory"]["mem_actual_free_percent"].valuestr()).toDouble()
                       << "mem_actual_used_percent" << QString::fromStdString(payload["memory"]["mem_actual_used_percent"].valuestr()).toDouble()
                       << "swap_total" << QString::fromStdString(payload["memory"]["swap_total"].valuestr()).toDouble()
                       << "swap_used" << QString::fromStdString(payload["memory"]["swap_used"].valuestr()).toDouble()
                       << "swap_free" << QString::fromStdString(payload["memory"]["swap_free"].valuestr()).toDouble()
                       << "swap_page_in" << QString::fromStdString(payload["memory"]["swap_page_in"].valuestr()).toDouble()
                       << "swap_page_out" << QString::fromStdString(payload["memory"]["swap_page_out"].valuestr()).toDouble();
    bo_memory_statistics = bob_memory_statistics.obj();

    nosql_.Insert("memory_statistics", bo_memory_statistics);

    qDebug() << "memory stats inserted";

    std::cout << "stats_memory? : " << host.hasField("stats_memory") << std::endl;

    //std::cout << "stats_cpu.number : " << host.getFieldDotted("stats_cpu.number").Int() + 1 << std::endl;

    long long counter = host.hasField("stats_memory") ? host.getFieldDotted("stats_memory.counter").numberLong() + 1 : 1;
    double mem_used = QString::fromStdString(payload["memory"]["mem_used"].valuestr()).toDouble();

    double max_mem_used = (host.hasField("stats_memory") && mem_used < host.getFieldDotted("stats_memory.max_mem_used").Double()) ? host.getFieldDotted("stats_memory.max_mem_used").Double() : mem_used;
    double all_mem_used = (host.hasField("stats_memory")) ? host.getFieldDotted("stats_memory.all_mem_used").Double() + mem_used : mem_used;

    //if (!host.hasField("stats_memory")) bob_stats_memory.append(msg.getField("created_at"));
    if (!host.hasField("stats_memory")) bob_stats_memory << "stats_memory.created_at" << created_at;
    bob_stats_memory << "stats_memory.updated_at" << created_at;
    bob_stats_memory << "stats_memory.counter" << counter;
    bob_stats_memory << "stats_memory.mem_used" << mem_used;
    bob_stats_memory << "stats_memory.all_mem_used" << all_mem_used;
    bob_stats_memory << "stats_memory.average_mem_used" << all_mem_used / counter;
    bob_stats_memory << "stats_memory.max_mem_used" << max_mem_used;
    bob_stats_memory << "stats_memory.swap_total" << QString::fromStdString(payload["memory"]["swap_total"].valuestr()).toDouble();

    //bo_stats_memory = BSONObjBuilder().append("stats_memory", bob_stats_memory.obj()).obj();
    bo_stats_memory = bob_stats_memory.obj();
    nosql_.Update("hosts", host_id.wrap(), bo_stats_memory);

    std::cout << "bo_stats_memory : " << bo_stats_memory.toString() << std::endl;

    std::cout << "cache path : " << cache_path.toStdString() << std::endl;
    emit delete_cache(cache_path + uuid.String().data());

/*if (endCondition(message)) {
       subscriptions.cancel(message.getDestination());
    }*/

}
<|endoftext|>


<commit_before>#include <cstring>
#include <utility>

#include "abort/abort.h"
#include "chess_util4.h"
#include "eval.h"
#include "MoveGen4.h"
#include "Search4.h"

namespace Chess
{
    Search4::Statistics::Statistics()
        : lnode_count(0),
          node_count(0),
          qnode_count(0)
    {
    }

    void Search4::Statistics::clear()
    {
        lnode_count = 0;
        node_count  = 0;
        qnode_count = 0;
    }

    Search4::Search4()
        : _aborted(false),
          _is_init(false),
          _max_depth(1),
          _next_node_check(0),
          _position(),
          _start_time(),
          _stop_time()
    {
    }

    Search4::~Search4()
    {
    }

    MoveList Search4::get_pv()
    {
        MoveList list; list.init(_pv[0], 0);

        for (size_t i = 0;
             _pv[0][i] && i < max_ply; i++ )
            list.size++;

        return list;
    }

    auto Search4::get_stats() const -> Statistics
    {
        return _stats;
    }

    bool Search4::init(Handle<Position> pos)
    {
        _is_init = false;

        AbortIfNot(pos, false);

        _position = pos;

        _aborted = false;
        _next_node_check = 0;

        _stats.clear();

        const auto size = sizeof( _pv[0][0] )
            * max_ply * max_ply;

        std::memset(_pv, 0, size);

        _is_init = true;
        return true;
    }

    int16 Search4::quiesce(uint32 depth, int16 alpha, int16 beta)
    {
        Position& pos = *_position;

        const player_t to_move = pos.get_turn();
        const bool in_check    = pos.in_check(to_move);
        const auto& tables     = DataTables::get();

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);
        }

        /*
         * Get an initial score for this position:
         */
        const int16 score =
            tables.sign[ pos.get_turn() ] * evaluate(pos);

        if (alpha < score) alpha = score;

        /*
         * Return the heuristic value of this position if
         * no captures are left:
         */
        if (n_moves == 0 || max_ply <= depth)
        {
            _save_pv(depth, 0);

            _stats.lnode_count++;
            return score;
        }

        /*
         * Check if we can fail-high; not sure if this is
         * correct for zugzwang positions...
         */
        if (score >= beta)
        {
            _stats.lnode_count++;
            return beta;
        }

        int32 best_move = 0;

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++; _stats.qnode_count++;

            const int32 move = moves[i];

            pos.make_move(move);

            const int16 score
                = -quiesce(depth + 1, -beta, -alpha );

            pos.unmake_move(move);

            if (score >= beta)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::run(uint32 depth, duration_t timeout)
    {
        AbortIfNot(_is_init , false);
        AbortIfNot(depth > 0, false);

        _start_time  =  std::chrono::steady_clock::now();
        _stop_time   =  _start_time + timeout;

        int16 score = -king_value;

        for (_max_depth =  1; _max_depth <= depth;
             _max_depth++)
        {
            const int16 tmp_score = search_root();

            if ( _aborted ) break;
            score = tmp_score;

            // Display the principal variation
            // TODO Dump this to a stream configured
            // for UCI or human-readable format

            MoveList list = get_pv();
            int32 move = 0;

            std::printf("[%2u]: %hd --> ", _max_depth, score);
            while (list.next(move))
            {
                std::printf("%s ",
                    format_san(move, "").c_str());
            }
            std::printf("\n");
            std::fflush(stdout);
        }

        _is_init = false;
        return score;
    }

    int16 Search4::search(uint32 depth, int16 alpha, int16 beta)
    {
        if (_next_node_check <= _stats.node_count
            && _check_timeout())
        {
            _aborted = true; _stats.lnode_count++;
            return beta;
        }

        Position& pos = *_position;

        const player_t side = pos.get_turn();

        const bool in_check =
            pos.in_check( side );

        /*
         * Don't quiece() if we're in check:
         */
        if (_max_depth <= depth && !in_check)
            return quiesce( depth, alpha, beta );

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                return 0;
            }
        }

        int32 best_move = 0;
        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = -search(depth+1, -beta, -alpha);

            pos.unmake_move(move);

            if (beta <= score)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        if (best_move)
            _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::search_root()
    {
        AbortIfNot( _position, false );

        Position& pos = *_position;

        const bool in_check =
            pos.in_check(pos.get_turn());

        BUFFER(int32, moves, max_moves );
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _save_pv(0, 0); return -king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);
        }

        auto best = std::make_pair<int32,int16>(
            0, king_value+1);

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = search(1, -king_value,
                king_value);

            pos.unmake_move(move);

            if (score < best.second)
            {
                _save_pv(0, move);
                best.first = move; best.second
                    = score;
            }
        }

        return -best.second;
    }

    bool Search4::_check_timeout()
    {
        const auto now = std::chrono::steady_clock::now();
        const auto dur = now - _start_time;

        if (_stop_time <= now)
            return true;

        // Check for timeouts once per second

        const auto nps =
            _stats.node_count * decltype(dur)::period::den /
                dur.count();

        _next_node_check =
            _stats.node_count + nps;

        return false;
    }

    void Search4::_save_pv(uint32 depth, int32 move)
    {
        if (depth < max_ply)
        {
            _pv[depth][depth] = move;

            // Null move signals the end of a variation:
            if (move == 0) return;
        }

        for  (uint32 i = depth + 1; i < max_ply; i += 1)
        {
            if ((_pv[depth][i] = _pv[depth+1][i])
                == 0) break;
        }
    }
}
<commit_msg>Fixed array bounds warning<commit_after>#include <cstring>
#include <utility>

#include "abort/abort.h"
#include "chess_util4.h"
#include "eval.h"
#include "MoveGen4.h"
#include "Search4.h"

namespace Chess
{
    Search4::Statistics::Statistics()
        : lnode_count(0),
          node_count(0),
          qnode_count(0)
    {
    }

    void Search4::Statistics::clear()
    {
        lnode_count = 0;
        node_count  = 0;
        qnode_count = 0;
    }

    Search4::Search4()
        : _aborted(false),
          _is_init(false),
          _max_depth(1),
          _next_node_check(0),
          _position(),
          _start_time(),
          _stop_time()
    {
    }

    Search4::~Search4()
    {
    }

    MoveList Search4::get_pv()
    {
        MoveList list; list.init(_pv[0], 0);

        for (size_t i = 0;
             _pv[0][i] && i < max_ply; i++ )
            list.size++;

        return list;
    }

    auto Search4::get_stats() const -> Statistics
    {
        return _stats;
    }

    bool Search4::init(Handle<Position> pos)
    {
        _is_init = false;

        AbortIfNot(pos, false);

        _position = pos;

        _aborted = false;
        _next_node_check = 0;

        _stats.clear();

        const auto size = sizeof( _pv[0][0] )
            * max_ply * max_ply;

        std::memset(_pv, 0, size);

        _is_init = true;
        return true;
    }

    int16 Search4::quiesce(uint32 depth, int16 alpha, int16 beta)
    {
        Position& pos = *_position;

        const player_t to_move = pos.get_turn();
        const bool in_check    = pos.in_check(to_move);
        const auto& tables     = DataTables::get();

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);
        }

        /*
         * Get an initial score for this position:
         */
        const int16 score =
            tables.sign[ pos.get_turn() ] * evaluate(pos);

        if (alpha < score) alpha = score;

        /*
         * Return the heuristic value of this position if
         * no captures are left:
         */
        if (n_moves == 0 || max_ply <= depth)
        {
            _save_pv(depth, 0);

            _stats.lnode_count++;
            return score;
        }

        /*
         * Check if we can fail-high; not sure if this is
         * correct for zugzwang positions...
         */
        if (score >= beta)
        {
            _stats.lnode_count++;
            return beta;
        }

        int32 best_move = 0;

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++; _stats.qnode_count++;

            const int32 move = moves[i];

            pos.make_move(move);

            const int16 score
                = -quiesce(depth + 1, -beta, -alpha );

            pos.unmake_move(move);

            if (score >= beta)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::run(uint32 depth, duration_t timeout)
    {
        AbortIfNot(_is_init , false);
        AbortIfNot(depth > 0, false);

        _start_time  =  std::chrono::steady_clock::now();
        _stop_time   =  _start_time + timeout;

        int16 score = -king_value;

        for (_max_depth =  1; _max_depth <= depth;
             _max_depth++)
        {
            const int16 tmp_score = search_root();

            if ( _aborted ) break;
            score = tmp_score;

            // Display the principal variation
            // TODO Dump this to a stream configured
            // for UCI or human-readable format

            MoveList list = get_pv();
            int32 move = 0;

            std::printf("[%2u]: %hd --> ", _max_depth, score);
            while (list.next(move))
            {
                std::printf("%s ",
                    format_san(move, "").c_str());
            }
            std::printf("\n");
            std::fflush(stdout);
        }

        _is_init = false;
        return score;
    }

    int16 Search4::search(uint32 depth, int16 alpha, int16 beta)
    {
        if (_next_node_check <= _stats.node_count
            && _check_timeout())
        {
            _aborted = true; _stats.lnode_count++;
            return beta;
        }

        Position& pos = *_position;

        const player_t side = pos.get_turn();

        const bool in_check =
            pos.in_check( side );

        /*
         * Don't quiece() if we're in check:
         */
        if (_max_depth <= depth && !in_check)
            return quiesce( depth, alpha, beta );

        BUFFER(int32, moves, max_moves);
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                /*
                 * Add a small penalty to the mate score to encourage
                 * mates closer to the root:
                 */
                return depth - king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);

            if (n_moves == 0)
            {
                _stats.lnode_count++;

                /*
                 * Mark the end of this variation:
                 */
                _save_pv(depth, 0);

                return 0;
            }
        }

        int32 best_move = 0;
        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = -search(depth+1, -beta, -alpha);

            pos.unmake_move(move);

            if (beta <= score)
                return beta;

            if ( score > alpha )
            {
                best_move = move;
                alpha = score;
            }
        }

        if (best_move)
            _save_pv(depth, best_move);

        return alpha;
    }

    int16 Search4::search_root()
    {
        AbortIfNot( _position, false );

        Position& pos = *_position;

        const bool in_check =
            pos.in_check(pos.get_turn());

        BUFFER(int32, moves, max_moves );
        size_t n_moves;

        if (in_check)
        {
            n_moves = MoveGen::generate_check_evasions(
                pos, moves);

            if (n_moves == 0)
            {
                _save_pv(0, 0); return -king_value;
            }
        }
        else
        {
            n_moves = MoveGen::generate_captures(
                pos, moves);

            n_moves += MoveGen::generate_noncaptures(
                pos, &moves[n_moves]);
        }

        auto best = std::make_pair<int32,int16>(
            0, king_value+1);

        for (size_t i = 0; i < n_moves; i++)
        {
            _stats.node_count++;

            const int32 move = moves[i];

            pos.make_move( move );

            const int16 score = search(1, -king_value,
                king_value);

            pos.unmake_move(move);

            if (score < best.second)
            {
                _save_pv(0, move);
                best.first = move; best.second
                    = score;
            }
        }

        return -best.second;
    }

    bool Search4::_check_timeout()
    {
        const auto now = std::chrono::steady_clock::now();
        const auto dur = now - _start_time;

        if (_stop_time <= now)
            return true;

        // Check for timeouts once per second

        const auto nps =
            _stats.node_count * decltype(dur)::period::den /
                dur.count();

        _next_node_check =
            _stats.node_count + nps;

        return false;
    }

    void Search4::_save_pv(uint32 depth, int32 move)
    {
        if (depth < max_ply)
        {
            _pv[depth][depth] = move;

            // Null move signals the end of a variation:
            if (move == 0) return;

            for  (uint32 i = depth + 1; i < max_ply; i += 1)
            {
                if ((_pv[depth][i] = _pv[depth+1][i])
                    == 0) break;
            }
        }
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
    Copyright (C) 2002-2015 Argentum Online & Dakara Online Developers

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include <iostream>
#include <signal.h>

#include "Sockets.h"
#include "allheaders.h"

#define DAKARA_MAX_INPUT_BUFFER_SIZE 75000

void DakaraBeginCloseSocket(dakara::Socket* sctx);
void DakaraRealCloseSocket(dakara::Socket* sctx);

class DakaraSocketEvents : public dakara::SocketEvents {
public:
	virtual void onSocketNew(dakara::Socket* s) override;
	virtual void onSocketRead(dakara::Socket* s, const char* data, size_t data_len) override;
	virtual void onSocketWrite(dakara::Socket* s) override;
	virtual void onSocketClose(dakara::Socket* s) override;
};

class EchoServerSocketEvents : public dakara::SocketEvents {
public:
	virtual void onSocketNew(dakara::Socket* s) override;
	virtual void onSocketRead(dakara::Socket* s, const char* data, size_t data_len) override;
	virtual void onSocketWrite(dakara::Socket* s) override;
	virtual void onSocketClose(dakara::Socket* s) override;
};

void EchoServerSocketEvents::onSocketNew(dakara::Socket* s) {
	std::cout << "echo onSocketNew " << s->getIP() << std::endl;
}

void EchoServerSocketEvents::onSocketRead(dakara::Socket* s, const char* data, size_t data_len) {
	std::cout << "echo onSocketRead " << s->getIP() << " len: " << data_len << std::endl;
	s->write(data, data_len);
}

void EchoServerSocketEvents::onSocketWrite(dakara::Socket* s) {
	std::cout << "echo onSocketWrite " << s->getIP() << std::endl;
}

void EchoServerSocketEvents::onSocketClose(dakara::Socket* s) {
	std::cout << "echo onSocketClose " << s->getIP() << std::endl;
}

void DakaraSocketEvents::onSocketRead(dakara::Socket* s, const char* data, size_t data_len) {
	int UserIndex = s->userData;
	clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	//clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	try {
		incomingData->WriteBlock(data, data_len);

		if (incomingData->length() > DAKARA_MAX_INPUT_BUFFER_SIZE) {
			LogApiSock("WsApiEnviar MAX_INPUT_BUFFER_SIZE UserIndex=" + vb6::CStr(UserIndex));
			DakaraBeginCloseSocket(s);
			return;
		}

		UserList[UserIndex].IncomingDataAvailable = true;

		if (!UserList[UserIndex].ConnIgnoreIncomingData)
		{
			HandleIncomingData(UserIndex);
		}
	} catch (std::exception& ex) {
		std::cerr << "Unhandled error on HandleIncomingData: " << ex.what() << std::endl;
		LogApiSock("Unhandled error on HandleIncomingData, " + std::string(ex.what()));
		CloseSocket(s);
	} catch (...) {
		std::cerr << "UNKNOWN error on HandleIncomingData!" << std::endl;
		LogApiSock("UNKNOWN error on HandleIncomingData!");
		CloseSocket(s);
	}
}

void DakaraSocketEvents::onSocketWrite(dakara::Socket* s) {
	(void)s;
}

void DakaraSocketEvents::onSocketNew(dakara::Socket* s) {

	try {
		int UserIndex = NextOpenUser();

		if (UserIndex > MaxUsers || UserIndexSocketValido(UserIndex)) {
			s->close(true);
			return;
		}

		if (UserIndex > LastUser) {
			LastUser = UserIndex;
		}

		s->userData = UserIndex;

		std::string ip(s->getIP());

		if (BanIpBuscar(ip)) {
			s->close(true);
			return;
		}

		if (!IpSecurityAceptarNuevaConexion(ip)) {
			s->close(true);
			return;
		}

		if (IPSecuritySuperaLimiteConexiones(ip)) {
			IpRestarConexion(ip);
			s->close(true);
			return;
		}

		UserList[UserIndex].incomingData.reset(new clsByteQueue());
		UserList[UserIndex].outgoingData.reset(new clsByteQueue());
		UserList[UserIndex].sockctx = s;
		UserList[UserIndex].ConnID = 100;
		UserList[UserIndex].ConnIDValida = true;
		UserList[UserIndex].ConnIgnoreIncomingData = false;
		UserList[UserIndex].IncomingDataAvailable = false;

	} catch (std::exception& ex) {
		s->close(true);
		std::cerr << "Unhandled error on do_accept: " << ex.what() << std::endl;
		LogApiSock("Unhandled error on do_accept, " + std::string(ex.what()));
	} catch (...) {
		s->close(true);
		std::cerr << "UNKNOWN error on do_accept!" << std::endl;
		LogApiSock("UNKNOWN error on do_accept!");
	}
}

void DakaraSocketEvents::onSocketClose(dakara::Socket* s) {
	CloseSocket(s);
}

std::unique_ptr<dakara::SocketServer> DakaraSocketServer;

DakaraSocketEvents sev;
EchoServerSocketEvents echosev;

void break_signal_handler(short event, void* arg) {
	(void)event;
	(void)arg;

	std::string msg = "Control-C, terminando.";

	LogApiSock(msg);
	std::cout << msg << std::endl << std::flush;

	DakaraSocketServer->stop();
}

void signal_handler(short event, void* arg) {
	(void)event;
	(void)arg;

	std::string msg = "signal handler: SIGPIPE";

	LogApiSock(msg);
	std::cout << msg << std::endl << std::flush;
}

void IniciaWsApi() {
	LogApiSock("IniciaWsApi");

#ifdef WIN32
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD( 2, 2 ), &WSAData) != 0) {
		perror("WSAStartup");
		LogApiSock("error en WSAStartup");
		return;
	} else {
		std::string msg = ("Iniciado Winsock v " + std::to_string(LOBYTE( WSAData.wVersion )) + "." + std::to_string(HIBYTE( WSAData.wVersion )));
		LogApiSock(msg);
		std::cerr << msg << std::endl;
	}
#endif

	DakaraSocketServer = dakara::BuildSocketServer("libevent");

#ifndef WIN32
	DakaraSocketServer->addSignalHandler(SIGINT, break_signal_handler, 0);
	DakaraSocketServer->addSignalHandler(SIGPIPE, signal_handler, 0);
#endif

	DakaraSocketServer->addListener("0.0.0.0", Puerto, &sev);

#if 0
	DakaraSocketServer->addListener("127.0.0.1", Puerto + 1, &echosev);
#endif
}

void ServerLoop() {

	DakaraSocketServer->loop();

}

void LimpiaWsApi() {

	DakaraSocketServer.release();

}

void FlushBuffer(dakara::Socket* s) {
	int UserIndex = s->userData;

	//clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	if (outgoingData->length() == 0) {
			return;
	}

#if 1
	std::vector<std::int8_t> sndData;
	outgoingData->swapAndCleanRawBuffer(sndData);
#else
	std::string sndData = outgoingData->ReadBinaryFixed(outgoingData->length());
#endif

	WsApiEnviar(s, sndData);
}

void CloseSocket(dakara::Socket* s) {
	DakaraBeginCloseSocket(s);
}

void WsApiEnviar(int UserIndex, const char* str, std::size_t str_len) {
	if (!UserList[UserIndex].ConnIDValida) {
		throw std::runtime_error("WsApiEnviar: ConnIDValida = False, UserIndex = " + std::to_string(UserIndex));
	}

	WsApiEnviar(UserList[UserIndex].sockctx, str, str_len);
}

void WsApiEnviar(dakara::Socket* s, const char* str, std::size_t str_len) {
	int UserIndex = s->userData;
	//clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	if (outgoingData->length() > 0) {
		FlushBuffer(s);
	}

	s->write(str, str_len);

	/* FIXME */
	/*
	if (evbuffer_get_length(output) > MAX_OUTPUT_BUFFER_SIZE) {
        LogApiSock("WsApiEnviar MAX_OUTPUT_BUFFER_SIZE UserIndex=" + vb6::CStr(sctx->UserIndex()));
		std::cerr << "WsApiEnviar MAX_OUTPUT_BUFFER_SIZE" << std::endl;
		return 1;
	}
*/
}

void WSApiReiniciarSockets() {
	throw std::runtime_error("WSApiReiniciarSockets not implemented");
}

bool UserIndexSocketValido(int UserIndex) {
	return UserIndex >= 1 && UserIndex <= MaxUsers && UserList[UserIndex].ConnID != -1 && UserList[UserIndex].ConnIDValida && UserList[UserIndex].sockctx != nullptr;
}

void DakaraBeginCloseSocket(dakara::Socket* s) {
	int UserIndex = s->userData;

    if (UserIndex > 0) {
	    IpRestarConexion (UserList[UserIndex].ip);

		UserList[UserIndex].ConnID = -1;
		UserList[UserIndex].ConnIDValida = false;
		UserList[UserIndex].sockctx = nullptr;
    }

    s->close(false);
}

void DakaraRealCloseSocket(dakara::Socket* s) {
	s->close(false);
}

void WSApiCloseSocket(int UserIndex) {
	if (!UserList[UserIndex].ConnIDValida) {
		throw std::runtime_error("WSApiCloseSocket: ConnIDValida = False, UserIndex = " + std::to_string(UserIndex));
	}

	dakara::Socket* sctx = UserList[UserIndex].sockctx;

	DakaraBeginCloseSocket(sctx);
}

<commit_msg>Windows build error<commit_after>/******************************************************************************
    Copyright (C) 2002-2015 Argentum Online & Dakara Online Developers

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include <iostream>
#include <signal.h>

#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#endif

#include "Sockets.h"
#include "allheaders.h"

#define DAKARA_MAX_INPUT_BUFFER_SIZE 75000

void DakaraBeginCloseSocket(dakara::Socket* sctx);
void DakaraRealCloseSocket(dakara::Socket* sctx);

class DakaraSocketEvents : public dakara::SocketEvents {
public:
	virtual void onSocketNew(dakara::Socket* s) override;
	virtual void onSocketRead(dakara::Socket* s, const char* data, size_t data_len) override;
	virtual void onSocketWrite(dakara::Socket* s) override;
	virtual void onSocketClose(dakara::Socket* s) override;
};

class EchoServerSocketEvents : public dakara::SocketEvents {
public:
	virtual void onSocketNew(dakara::Socket* s) override;
	virtual void onSocketRead(dakara::Socket* s, const char* data, size_t data_len) override;
	virtual void onSocketWrite(dakara::Socket* s) override;
	virtual void onSocketClose(dakara::Socket* s) override;
};

void EchoServerSocketEvents::onSocketNew(dakara::Socket* s) {
	std::cout << "echo onSocketNew " << s->getIP() << std::endl;
}

void EchoServerSocketEvents::onSocketRead(dakara::Socket* s, const char* data, size_t data_len) {
	std::cout << "echo onSocketRead " << s->getIP() << " len: " << data_len << std::endl;
	s->write(data, data_len);
}

void EchoServerSocketEvents::onSocketWrite(dakara::Socket* s) {
	std::cout << "echo onSocketWrite " << s->getIP() << std::endl;
}

void EchoServerSocketEvents::onSocketClose(dakara::Socket* s) {
	std::cout << "echo onSocketClose " << s->getIP() << std::endl;
}

void DakaraSocketEvents::onSocketRead(dakara::Socket* s, const char* data, size_t data_len) {
	int UserIndex = s->userData;
	clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	//clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	try {
		incomingData->WriteBlock(data, data_len);

		if (incomingData->length() > DAKARA_MAX_INPUT_BUFFER_SIZE) {
			LogApiSock("WsApiEnviar MAX_INPUT_BUFFER_SIZE UserIndex=" + vb6::CStr(UserIndex));
			DakaraBeginCloseSocket(s);
			return;
		}

		UserList[UserIndex].IncomingDataAvailable = true;

		if (!UserList[UserIndex].ConnIgnoreIncomingData)
		{
			HandleIncomingData(UserIndex);
		}
	} catch (std::exception& ex) {
		std::cerr << "Unhandled error on HandleIncomingData: " << ex.what() << std::endl;
		LogApiSock("Unhandled error on HandleIncomingData, " + std::string(ex.what()));
		CloseSocket(s);
	} catch (...) {
		std::cerr << "UNKNOWN error on HandleIncomingData!" << std::endl;
		LogApiSock("UNKNOWN error on HandleIncomingData!");
		CloseSocket(s);
	}
}

void DakaraSocketEvents::onSocketWrite(dakara::Socket* s) {
	(void)s;
}

void DakaraSocketEvents::onSocketNew(dakara::Socket* s) {

	try {
		int UserIndex = NextOpenUser();

		if (UserIndex > MaxUsers || UserIndexSocketValido(UserIndex)) {
			s->close(true);
			return;
		}

		if (UserIndex > LastUser) {
			LastUser = UserIndex;
		}

		s->userData = UserIndex;

		std::string ip(s->getIP());

		if (BanIpBuscar(ip)) {
			s->close(true);
			return;
		}

		if (!IpSecurityAceptarNuevaConexion(ip)) {
			s->close(true);
			return;
		}

		if (IPSecuritySuperaLimiteConexiones(ip)) {
			IpRestarConexion(ip);
			s->close(true);
			return;
		}

		UserList[UserIndex].incomingData.reset(new clsByteQueue());
		UserList[UserIndex].outgoingData.reset(new clsByteQueue());
		UserList[UserIndex].sockctx = s;
		UserList[UserIndex].ConnID = 100;
		UserList[UserIndex].ConnIDValida = true;
		UserList[UserIndex].ConnIgnoreIncomingData = false;
		UserList[UserIndex].IncomingDataAvailable = false;

	} catch (std::exception& ex) {
		s->close(true);
		std::cerr << "Unhandled error on do_accept: " << ex.what() << std::endl;
		LogApiSock("Unhandled error on do_accept, " + std::string(ex.what()));
	} catch (...) {
		s->close(true);
		std::cerr << "UNKNOWN error on do_accept!" << std::endl;
		LogApiSock("UNKNOWN error on do_accept!");
	}
}

void DakaraSocketEvents::onSocketClose(dakara::Socket* s) {
	CloseSocket(s);
}

std::unique_ptr<dakara::SocketServer> DakaraSocketServer;

DakaraSocketEvents sev;
EchoServerSocketEvents echosev;

void break_signal_handler(short event, void* arg) {
	(void)event;
	(void)arg;

	std::string msg = "Control-C, terminando.";

	LogApiSock(msg);
	std::cout << msg << std::endl << std::flush;

	DakaraSocketServer->stop();
}

void signal_handler(short event, void* arg) {
	(void)event;
	(void)arg;

	std::string msg = "signal handler: SIGPIPE";

	LogApiSock(msg);
	std::cout << msg << std::endl << std::flush;
}

void IniciaWsApi() {
	LogApiSock("IniciaWsApi");

#ifdef WIN32
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD( 2, 2 ), &WSAData) != 0) {
		perror("WSAStartup");
		LogApiSock("error en WSAStartup");
		return;
	} else {
		std::string msg = ("Iniciado Winsock v " + std::to_string(LOBYTE( WSAData.wVersion )) + "." + std::to_string(HIBYTE( WSAData.wVersion )));
		LogApiSock(msg);
		std::cerr << msg << std::endl;
	}
#endif

	DakaraSocketServer = dakara::BuildSocketServer("libevent");

#ifndef WIN32
	DakaraSocketServer->addSignalHandler(SIGINT, break_signal_handler, 0);
	DakaraSocketServer->addSignalHandler(SIGPIPE, signal_handler, 0);
#endif

	DakaraSocketServer->addListener("0.0.0.0", Puerto, &sev);

#if 0
	DakaraSocketServer->addListener("127.0.0.1", Puerto + 1, &echosev);
#endif
}

void ServerLoop() {

	DakaraSocketServer->loop();

}

void LimpiaWsApi() {

	DakaraSocketServer.release();

}

void FlushBuffer(dakara::Socket* s) {
	int UserIndex = s->userData;

	//clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	if (outgoingData->length() == 0) {
			return;
	}

#if 1
	std::vector<std::int8_t> sndData;
	outgoingData->swapAndCleanRawBuffer(sndData);
#else
	std::string sndData = outgoingData->ReadBinaryFixed(outgoingData->length());
#endif

	WsApiEnviar(s, sndData);
}

void CloseSocket(dakara::Socket* s) {
	DakaraBeginCloseSocket(s);
}

void WsApiEnviar(int UserIndex, const char* str, std::size_t str_len) {
	if (!UserList[UserIndex].ConnIDValida) {
		throw std::runtime_error("WsApiEnviar: ConnIDValida = False, UserIndex = " + std::to_string(UserIndex));
	}

	WsApiEnviar(UserList[UserIndex].sockctx, str, str_len);
}

void WsApiEnviar(dakara::Socket* s, const char* str, std::size_t str_len) {
	int UserIndex = s->userData;
	//clsByteQueue* incomingData = UserList[UserIndex].incomingData.get();
	clsByteQueue* outgoingData = UserList[UserIndex].outgoingData.get();

	if (outgoingData->length() > 0) {
		FlushBuffer(s);
	}

	s->write(str, str_len);

	/* FIXME */
	/*
	if (evbuffer_get_length(output) > MAX_OUTPUT_BUFFER_SIZE) {
        LogApiSock("WsApiEnviar MAX_OUTPUT_BUFFER_SIZE UserIndex=" + vb6::CStr(sctx->UserIndex()));
		std::cerr << "WsApiEnviar MAX_OUTPUT_BUFFER_SIZE" << std::endl;
		return 1;
	}
*/
}

void WSApiReiniciarSockets() {
	throw std::runtime_error("WSApiReiniciarSockets not implemented");
}

bool UserIndexSocketValido(int UserIndex) {
	return UserIndex >= 1 && UserIndex <= MaxUsers && UserList[UserIndex].ConnID != -1 && UserList[UserIndex].ConnIDValida && UserList[UserIndex].sockctx != nullptr;
}

void DakaraBeginCloseSocket(dakara::Socket* s) {
	int UserIndex = s->userData;

    if (UserIndex > 0) {
	    IpRestarConexion (UserList[UserIndex].ip);

		UserList[UserIndex].ConnID = -1;
		UserList[UserIndex].ConnIDValida = false;
		UserList[UserIndex].sockctx = nullptr;
    }

    s->close(false);
}

void DakaraRealCloseSocket(dakara::Socket* s) {
	s->close(false);
}

void WSApiCloseSocket(int UserIndex) {
	if (!UserList[UserIndex].ConnIDValida) {
		throw std::runtime_error("WSApiCloseSocket: ConnIDValida = False, UserIndex = " + std::to_string(UserIndex));
	}

	dakara::Socket* sctx = UserList[UserIndex].sockctx;

	DakaraBeginCloseSocket(sctx);
}

<|endoftext|>