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

#include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"

#include <map>
#include <string>

#include "base/json/json_writer.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h"
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/common/extensions/api/bluetooth.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_socket.h"

namespace extensions {

ExtensionBluetoothEventRouter::ExtensionBluetoothEventRouter(Profile* profile)
    : send_discovery_events_(false),
      responsible_for_discovery_(false),
      profile_(profile),
      adapter_(NULL),
      num_event_listeners_(0),
      next_socket_id_(1),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
  DCHECK(profile_);
}

ExtensionBluetoothEventRouter::~ExtensionBluetoothEventRouter() {
  CHECK(socket_map_.size() == 0);
  if (adapter_) {
    adapter_->RemoveObserver(this);
    adapter_ = NULL;
  }
}

bool ExtensionBluetoothEventRouter::IsBluetoothSupported() const {
  return adapter_ ||
         device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
}

void ExtensionBluetoothEventRouter::GetAdapter(
    const device::BluetoothAdapterFactory::AdapterCallback& callback) {
  if (adapter_) {
    callback.Run(scoped_refptr<device::BluetoothAdapter>(adapter_));
    return;
  }

  device::BluetoothAdapterFactory::GetAdapter(callback);
}

void ExtensionBluetoothEventRouter::OnListenerAdded() {
  num_event_listeners_++;
  InitializeAdapterIfNeeded();
}

void ExtensionBluetoothEventRouter::OnListenerRemoved() {
  if (num_event_listeners_ > 0)
    num_event_listeners_--;
  MaybeReleaseAdapter();
}

int ExtensionBluetoothEventRouter::RegisterSocket(
    scoped_refptr<device::BluetoothSocket> socket) {
  // If there is a socket registered with the same fd, just return it's id
  for (SocketMap::const_iterator i = socket_map_.begin();
      i != socket_map_.end(); ++i) {
    if (i->second.get() == socket.get())
      return i->first;
  }
  int return_id = next_socket_id_++;
  socket_map_[return_id] = socket;
  return return_id;
}

bool ExtensionBluetoothEventRouter::ReleaseSocket(int id) {
  SocketMap::iterator socket_entry = socket_map_.find(id);
  if (socket_entry == socket_map_.end())
    return false;
  socket_map_.erase(socket_entry);
  return true;
}

scoped_refptr<device::BluetoothSocket>
ExtensionBluetoothEventRouter::GetSocket(int id) {
  SocketMap::iterator socket_entry = socket_map_.find(id);
  if (socket_entry == socket_map_.end())
    return NULL;
  return socket_entry->second;
}

void ExtensionBluetoothEventRouter::SetResponsibleForDiscovery(
    bool responsible) {
  responsible_for_discovery_ = responsible;
}

bool ExtensionBluetoothEventRouter::IsResponsibleForDiscovery() const {
  return responsible_for_discovery_;
}

void ExtensionBluetoothEventRouter::SetSendDiscoveryEvents(bool should_send) {
  // At the transition into sending devices, also send past devices that
  // were discovered as they will not be discovered again.
  if (should_send && !send_discovery_events_) {
    for (DeviceList::const_iterator i = discovered_devices_.begin();
        i != discovered_devices_.end(); ++i) {
      DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
                          **i);
    }
  }

  send_discovery_events_ = should_send;
}

void ExtensionBluetoothEventRouter::DispatchDeviceEvent(
    const char* event_name, const extensions::api::bluetooth::Device& device) {
  scoped_ptr<ListValue> args(new ListValue());
  args->Append(device.ToValue().release());
  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
}

void ExtensionBluetoothEventRouter::AdapterPresentChanged(
    device::BluetoothAdapter* adapter, bool present) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }
  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::AdapterPoweredChanged(
    device::BluetoothAdapter* adapter, bool has_power) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }
  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::AdapterDiscoveringChanged(
    device::BluetoothAdapter* adapter, bool discovering) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }

  if (!discovering) {
    send_discovery_events_ = false;
    responsible_for_discovery_ = false;
    discovered_devices_.clear();
  }

  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::DeviceAdded(
    device::BluetoothAdapter* adapter,
    device::BluetoothDevice* device) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }

  extensions::api::bluetooth::Device* extension_device =
      new extensions::api::bluetooth::Device();
  extensions::api::bluetooth::BluetoothDeviceToApiDevice(
      *device, extension_device);
  discovered_devices_.push_back(extension_device);

  if (!send_discovery_events_)
    return;

  DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
                      *extension_device);
}

void ExtensionBluetoothEventRouter::InitializeAdapterIfNeeded() {
  if (!adapter_) {
    GetAdapter(base::Bind(&ExtensionBluetoothEventRouter::InitializeAdapter,
                          weak_ptr_factory_.GetWeakPtr()));
  }
}

void ExtensionBluetoothEventRouter::InitializeAdapter(
    scoped_refptr<device::BluetoothAdapter> adapter) {
  if (!adapter_) {
    adapter_ = adapter;
    adapter_->AddObserver(this);
  }
}

void ExtensionBluetoothEventRouter::MaybeReleaseAdapter() {
  if (adapter_ && num_event_listeners_ == 0) {
    adapter_->RemoveObserver(this);
    adapter_ = NULL;
  }
}

void ExtensionBluetoothEventRouter::DispatchAdapterStateEvent() {
  api::bluetooth::AdapterState state;
  PopulateAdapterState(*adapter_, &state);

  scoped_ptr<ListValue> args(new ListValue());
  args->Append(state.ToValue().release());
  scoped_ptr<Event> event(new Event(
      extensions::event_names::kBluetoothOnAdapterStateChanged,
      args.Pass()));
  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
}

}  // namespace extensions
<commit_msg>Remove socket_map_.size() == 0 CHECK.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"

#include <map>
#include <string>

#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h"
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/common/extensions/api/bluetooth.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_socket.h"

namespace extensions {

ExtensionBluetoothEventRouter::ExtensionBluetoothEventRouter(Profile* profile)
    : send_discovery_events_(false),
      responsible_for_discovery_(false),
      profile_(profile),
      adapter_(NULL),
      num_event_listeners_(0),
      next_socket_id_(1),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
  DCHECK(profile_);
}

ExtensionBluetoothEventRouter::~ExtensionBluetoothEventRouter() {
  if (adapter_) {
    adapter_->RemoveObserver(this);
    adapter_ = NULL;
  }
  DLOG_IF(WARNING, socket_map_.size() != 0)
      << "Bluetooth sockets are still open.";
  socket_map_.clear();
}

bool ExtensionBluetoothEventRouter::IsBluetoothSupported() const {
  return adapter_ ||
         device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
}

void ExtensionBluetoothEventRouter::GetAdapter(
    const device::BluetoothAdapterFactory::AdapterCallback& callback) {
  if (adapter_) {
    callback.Run(scoped_refptr<device::BluetoothAdapter>(adapter_));
    return;
  }

  device::BluetoothAdapterFactory::GetAdapter(callback);
}

void ExtensionBluetoothEventRouter::OnListenerAdded() {
  num_event_listeners_++;
  InitializeAdapterIfNeeded();
}

void ExtensionBluetoothEventRouter::OnListenerRemoved() {
  if (num_event_listeners_ > 0)
    num_event_listeners_--;
  MaybeReleaseAdapter();
}

int ExtensionBluetoothEventRouter::RegisterSocket(
    scoped_refptr<device::BluetoothSocket> socket) {
  // If there is a socket registered with the same fd, just return it's id
  for (SocketMap::const_iterator i = socket_map_.begin();
      i != socket_map_.end(); ++i) {
    if (i->second.get() == socket.get())
      return i->first;
  }
  int return_id = next_socket_id_++;
  socket_map_[return_id] = socket;
  return return_id;
}

bool ExtensionBluetoothEventRouter::ReleaseSocket(int id) {
  SocketMap::iterator socket_entry = socket_map_.find(id);
  if (socket_entry == socket_map_.end())
    return false;
  socket_map_.erase(socket_entry);
  return true;
}

scoped_refptr<device::BluetoothSocket>
ExtensionBluetoothEventRouter::GetSocket(int id) {
  SocketMap::iterator socket_entry = socket_map_.find(id);
  if (socket_entry == socket_map_.end())
    return NULL;
  return socket_entry->second;
}

void ExtensionBluetoothEventRouter::SetResponsibleForDiscovery(
    bool responsible) {
  responsible_for_discovery_ = responsible;
}

bool ExtensionBluetoothEventRouter::IsResponsibleForDiscovery() const {
  return responsible_for_discovery_;
}

void ExtensionBluetoothEventRouter::SetSendDiscoveryEvents(bool should_send) {
  // At the transition into sending devices, also send past devices that
  // were discovered as they will not be discovered again.
  if (should_send && !send_discovery_events_) {
    for (DeviceList::const_iterator i = discovered_devices_.begin();
        i != discovered_devices_.end(); ++i) {
      DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
                          **i);
    }
  }

  send_discovery_events_ = should_send;
}

void ExtensionBluetoothEventRouter::DispatchDeviceEvent(
    const char* event_name, const extensions::api::bluetooth::Device& device) {
  scoped_ptr<ListValue> args(new ListValue());
  args->Append(device.ToValue().release());
  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
}

void ExtensionBluetoothEventRouter::AdapterPresentChanged(
    device::BluetoothAdapter* adapter, bool present) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }
  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::AdapterPoweredChanged(
    device::BluetoothAdapter* adapter, bool has_power) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }
  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::AdapterDiscoveringChanged(
    device::BluetoothAdapter* adapter, bool discovering) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }

  if (!discovering) {
    send_discovery_events_ = false;
    responsible_for_discovery_ = false;
    discovered_devices_.clear();
  }

  DispatchAdapterStateEvent();
}

void ExtensionBluetoothEventRouter::DeviceAdded(
    device::BluetoothAdapter* adapter,
    device::BluetoothDevice* device) {
  if (adapter != adapter_) {
    DVLOG(1) << "Ignoring event for adapter " << adapter->address();
    return;
  }

  extensions::api::bluetooth::Device* extension_device =
      new extensions::api::bluetooth::Device();
  extensions::api::bluetooth::BluetoothDeviceToApiDevice(
      *device, extension_device);
  discovered_devices_.push_back(extension_device);

  if (!send_discovery_events_)
    return;

  DispatchDeviceEvent(extensions::event_names::kBluetoothOnDeviceDiscovered,
                      *extension_device);
}

void ExtensionBluetoothEventRouter::InitializeAdapterIfNeeded() {
  if (!adapter_) {
    GetAdapter(base::Bind(&ExtensionBluetoothEventRouter::InitializeAdapter,
                          weak_ptr_factory_.GetWeakPtr()));
  }
}

void ExtensionBluetoothEventRouter::InitializeAdapter(
    scoped_refptr<device::BluetoothAdapter> adapter) {
  if (!adapter_) {
    adapter_ = adapter;
    adapter_->AddObserver(this);
  }
}

void ExtensionBluetoothEventRouter::MaybeReleaseAdapter() {
  if (adapter_ && num_event_listeners_ == 0) {
    adapter_->RemoveObserver(this);
    adapter_ = NULL;
  }
}

void ExtensionBluetoothEventRouter::DispatchAdapterStateEvent() {
  api::bluetooth::AdapterState state;
  PopulateAdapterState(*adapter_, &state);

  scoped_ptr<ListValue> args(new ListValue());
  args->Append(state.ToValue().release());
  scoped_ptr<Event> event(new Event(
      extensions::event_names::kBluetoothOnAdapterStateChanged,
      args.Pass()));
  ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
}

}  // namespace extensions
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"

#include <gdk/gdkkeysyms.h>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/edit_command.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "testing/gtest/include/gtest/gtest.h"

class GtkKeyBindingsHandlerTest : public testing::Test {
 protected:
  struct EditCommand {
    const char* name;
    const char* value;
  };

  GtkKeyBindingsHandlerTest()
      : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
        handler_(NULL) {
    FilePath gtkrc;
    PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
    gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");
    gtk_rc_parse(gtkrc.value().c_str());

    GtkWidget* fixed = gtk_fixed_new();
    handler_ = new GtkKeyBindingsHandler(fixed);
    gtk_container_add(GTK_CONTAINER(window_), fixed);
    gtk_widget_show(fixed);
    gtk_widget_show(window_);
  }
  ~GtkKeyBindingsHandlerTest() {
    gtk_widget_destroy(window_);
    delete handler_;
  }

  NativeWebKeyboardEvent NewNativeWebKeyboardEvent(guint keyval, guint state) {
    GdkKeymap* keymap =
        gdk_keymap_get_for_display(gtk_widget_get_display(window_));

    GdkKeymapKey *keys = NULL;
    gint n_keys = 0;
    if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
      GdkEventKey event;
      event.type = GDK_KEY_PRESS;
      event.window = NULL;
      event.send_event = 0;
      event.time = 0;
      event.state = state;
      event.keyval = keyval;
      event.length = 0;
      event.string = NULL;
      event.hardware_keycode = keys[0].keycode;
      event.group = keys[0].group;
      event.is_modifier = 0;
      g_free(keys);
      return NativeWebKeyboardEvent(&event);
    }
    return NativeWebKeyboardEvent();
  }

  void TestKeyBinding(const NativeWebKeyboardEvent& event,
                      const EditCommand expected_result[],
                      size_t size) {
    EditCommands result;
    ASSERT_TRUE(handler_->Match(event, &result));
    ASSERT_EQ(size, result.size());
    for (size_t i = 0; i < size; ++i) {
      ASSERT_STREQ(expected_result[i].name, result[i].name.c_str());
      ASSERT_STREQ(expected_result[i].value, result[i].value.c_str());
    }
  }

 protected:
  GtkWidget* window_;
  GtkKeyBindingsHandler* handler_;
};

TEST_F(GtkKeyBindingsHandlerTest, MoveCursor) {
  static const EditCommand kEditCommands[] = {
    // "move-cursor" (logical-positions, -2, 0)
    { "MoveBackward", "" },
    { "MoveBackward", "" },
    // "move-cursor" (logical-positions, 2, 0)
    { "MoveForward", "" },
    { "MoveForward", "" },
    // "move-cursor" (visual-positions, -1, 1)
    { "MoveLeftAndModifySelection", "" },
    // "move-cursor" (visual-positions, 1, 1)
    { "MoveRightAndModifySelection", "" },
    // "move-cursor" (words, -1, 0)
    { "MoveWordBackward", "" },
    // "move-cursor" (words, 1, 0)
    { "MoveWordForward", "" },
    // "move-cursor" (display-lines, -1, 0)
    { "MoveUp", "" },
    // "move-cursor" (display-lines, 1, 0)
    { "MoveDown", "" },
    // "move-cursor" (display-line-ends, -1, 0)
    { "MoveToBeginningOfLine", "" },
    // "move-cursor" (display-line-ends, 1, 0)
    { "MoveToEndOfLine", "" },
    // "move-cursor" (paragraph-ends, -1, 0)
    { "MoveToBeginningOfParagraph", "" },
    // "move-cursor" (paragraph-ends, 1, 0)
    { "MoveToEndOfParagraph", "" },
    // "move-cursor" (pages, -1, 0)
    { "MovePageUp", "" },
    // "move-cursor" (pages, 1, 0)
    { "MovePageDown", "" },
    // "move-cursor" (buffer-ends, -1, 0)
    { "MoveToBeginningOfDocument", "" },
    // "move-cursor" (buffer-ends, 1, 0)
    { "MoveToEndOfDocument", "" }
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_1, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

TEST_F(GtkKeyBindingsHandlerTest, DeleteFromCursor) {
  static const EditCommand kEditCommands[] = {
    // "delete-from-cursor" (chars, -2)
    { "DeleteBackward", "" },
    { "DeleteBackward", "" },
    // "delete-from-cursor" (chars, 2)
    { "DeleteForward", "" },
    { "DeleteForward", "" },
    // "delete-from-cursor" (word-ends, -1)
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (word-ends, 1)
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, -1)
    { "MoveWordBackward", "" },
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, 1)
    { "MoveWordForward", "" },
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (display-lines, -1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-lines, 1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-line-ends, -1)
    { "DeleteToBeginningOfLine", "" },
    // "delete-from-cursor" (display-line-ends, 1)
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (paragraph-ends, -1)
    { "DeleteToBeginningOfParagraph", "" },
    // "delete-from-cursor" (paragraph-ends, 1)
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, -1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, 1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_2, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

TEST_F(GtkKeyBindingsHandlerTest, OtherActions) {
  static const EditCommand kBackspace[] = {
    { "DeleteBackward", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_3, GDK_CONTROL_MASK),
                 kBackspace, arraysize(kBackspace));

  static const EditCommand kCopyClipboard[] = {
    { "Copy", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_4, GDK_CONTROL_MASK),
                 kCopyClipboard, arraysize(kCopyClipboard));

  static const EditCommand kCutClipboard[] = {
    { "Cut", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_5, GDK_CONTROL_MASK),
                 kCutClipboard, arraysize(kCutClipboard));

  static const EditCommand kInsertAtCursor[] = {
    { "InsertText", "hello" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_6, GDK_CONTROL_MASK),
                 kInsertAtCursor, arraysize(kInsertAtCursor));

  static const EditCommand kPasteClipboard[] = {
    { "Paste", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_7, GDK_CONTROL_MASK),
                 kPasteClipboard, arraysize(kPasteClipboard));

  static const EditCommand kSelectAll[] = {
    { "Unselect", "" },
    { "SelectAll", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_8, GDK_CONTROL_MASK),
                 kSelectAll, arraysize(kSelectAll));

  static const EditCommand kSetAnchor[] = {
    { "SetMark", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_9, GDK_CONTROL_MASK),
                 kSetAnchor, arraysize(kSetAnchor));
}
<commit_msg>Mark the GtkKeyBindingsHandlerTest  tests as flaky since they don't work in a chroot.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"

#include <gdk/gdkkeysyms.h>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/edit_command.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "testing/gtest/include/gtest/gtest.h"

class GtkKeyBindingsHandlerTest : public testing::Test {
 protected:
  struct EditCommand {
    const char* name;
    const char* value;
  };

  GtkKeyBindingsHandlerTest()
      : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
        handler_(NULL) {
    FilePath gtkrc;
    PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
    gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");
    gtk_rc_parse(gtkrc.value().c_str());

    GtkWidget* fixed = gtk_fixed_new();
    handler_ = new GtkKeyBindingsHandler(fixed);
    gtk_container_add(GTK_CONTAINER(window_), fixed);
    gtk_widget_show(fixed);
    gtk_widget_show(window_);
  }
  ~GtkKeyBindingsHandlerTest() {
    gtk_widget_destroy(window_);
    delete handler_;
  }

  NativeWebKeyboardEvent NewNativeWebKeyboardEvent(guint keyval, guint state) {
    GdkKeymap* keymap =
        gdk_keymap_get_for_display(gtk_widget_get_display(window_));

    GdkKeymapKey *keys = NULL;
    gint n_keys = 0;
    if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
      GdkEventKey event;
      event.type = GDK_KEY_PRESS;
      event.window = NULL;
      event.send_event = 0;
      event.time = 0;
      event.state = state;
      event.keyval = keyval;
      event.length = 0;
      event.string = NULL;
      event.hardware_keycode = keys[0].keycode;
      event.group = keys[0].group;
      event.is_modifier = 0;
      g_free(keys);
      return NativeWebKeyboardEvent(&event);
    }
    return NativeWebKeyboardEvent();
  }

  void TestKeyBinding(const NativeWebKeyboardEvent& event,
                      const EditCommand expected_result[],
                      size_t size) {
    EditCommands result;
    ASSERT_TRUE(handler_->Match(event, &result));
    ASSERT_EQ(size, result.size());
    for (size_t i = 0; i < size; ++i) {
      ASSERT_STREQ(expected_result[i].name, result[i].name.c_str());
      ASSERT_STREQ(expected_result[i].value, result[i].value.c_str());
    }
  }

 protected:
  GtkWidget* window_;
  GtkKeyBindingsHandler* handler_;
};

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FLAKY_MoveCursor) {
  static const EditCommand kEditCommands[] = {
    // "move-cursor" (logical-positions, -2, 0)
    { "MoveBackward", "" },
    { "MoveBackward", "" },
    // "move-cursor" (logical-positions, 2, 0)
    { "MoveForward", "" },
    { "MoveForward", "" },
    // "move-cursor" (visual-positions, -1, 1)
    { "MoveLeftAndModifySelection", "" },
    // "move-cursor" (visual-positions, 1, 1)
    { "MoveRightAndModifySelection", "" },
    // "move-cursor" (words, -1, 0)
    { "MoveWordBackward", "" },
    // "move-cursor" (words, 1, 0)
    { "MoveWordForward", "" },
    // "move-cursor" (display-lines, -1, 0)
    { "MoveUp", "" },
    // "move-cursor" (display-lines, 1, 0)
    { "MoveDown", "" },
    // "move-cursor" (display-line-ends, -1, 0)
    { "MoveToBeginningOfLine", "" },
    // "move-cursor" (display-line-ends, 1, 0)
    { "MoveToEndOfLine", "" },
    // "move-cursor" (paragraph-ends, -1, 0)
    { "MoveToBeginningOfParagraph", "" },
    // "move-cursor" (paragraph-ends, 1, 0)
    { "MoveToEndOfParagraph", "" },
    // "move-cursor" (pages, -1, 0)
    { "MovePageUp", "" },
    // "move-cursor" (pages, 1, 0)
    { "MovePageDown", "" },
    // "move-cursor" (buffer-ends, -1, 0)
    { "MoveToBeginningOfDocument", "" },
    // "move-cursor" (buffer-ends, 1, 0)
    { "MoveToEndOfDocument", "" }
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_1, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FLAKY_DeleteFromCursor) {
  static const EditCommand kEditCommands[] = {
    // "delete-from-cursor" (chars, -2)
    { "DeleteBackward", "" },
    { "DeleteBackward", "" },
    // "delete-from-cursor" (chars, 2)
    { "DeleteForward", "" },
    { "DeleteForward", "" },
    // "delete-from-cursor" (word-ends, -1)
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (word-ends, 1)
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, -1)
    { "MoveWordBackward", "" },
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, 1)
    { "MoveWordForward", "" },
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (display-lines, -1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-lines, 1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-line-ends, -1)
    { "DeleteToBeginningOfLine", "" },
    // "delete-from-cursor" (display-line-ends, 1)
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (paragraph-ends, -1)
    { "DeleteToBeginningOfParagraph", "" },
    // "delete-from-cursor" (paragraph-ends, 1)
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, -1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, 1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_2, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FLAKY_OtherActions) {
  static const EditCommand kBackspace[] = {
    { "DeleteBackward", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_3, GDK_CONTROL_MASK),
                 kBackspace, arraysize(kBackspace));

  static const EditCommand kCopyClipboard[] = {
    { "Copy", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_4, GDK_CONTROL_MASK),
                 kCopyClipboard, arraysize(kCopyClipboard));

  static const EditCommand kCutClipboard[] = {
    { "Cut", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_5, GDK_CONTROL_MASK),
                 kCutClipboard, arraysize(kCutClipboard));

  static const EditCommand kInsertAtCursor[] = {
    { "InsertText", "hello" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_6, GDK_CONTROL_MASK),
                 kInsertAtCursor, arraysize(kInsertAtCursor));

  static const EditCommand kPasteClipboard[] = {
    { "Paste", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_7, GDK_CONTROL_MASK),
                 kPasteClipboard, arraysize(kPasteClipboard));

  static const EditCommand kSelectAll[] = {
    { "Unselect", "" },
    { "SelectAll", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_8, GDK_CONTROL_MASK),
                 kSelectAll, arraysize(kSelectAll));

  static const EditCommand kSetAnchor[] = {
    { "SetMark", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_9, GDK_CONTROL_MASK),
                 kSetAnchor, arraysize(kSetAnchor));
}
<|endoftext|>


<commit_before>#include "SalomeApp_Study.h"

#include "SalomeApp_Module.h"
#include "SalomeApp_DataModel.h"
#include "SalomeApp_RootObject.h"
#include "SalomeApp_DataObject.h"
#include "SalomeApp_Application.h"

#include <OB_Browser.h>

#include <SUIT_ResourceMgr.h>

#include "utilities.h"

SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
: CAM_Study( app )
{
}

SalomeApp_Study::~SalomeApp_Study()
{
}

int SalomeApp_Study::id() const
{
  int id = -1;
  if ( myStudyDS )
    id = studyDS()->StudyId();
  return id;
}

_PTR(Study) SalomeApp_Study::studyDS() const
{
  return myStudyDS;
}

void SalomeApp_Study::createDocument()
{
  MESSAGE( "openDocument" );

  // initialize myStudyDS, read HDF file
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( newStudyName().latin1() ) );
  if ( !study )
    return;

  setStudyDS( study );

  // create myRoot
  setRoot( new SalomeApp_RootObject( this ) );

  CAM_Study::createDocument();

  emit created( this );
}

//=======================================================================
// name    : openDocument
// Purpose : Open document
//=======================================================================
bool SalomeApp_Study::openDocument( const QString& theFileName )
{
  MESSAGE( "openDocument" );

  // initialize myStudyDS, read HDF file
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( (char*) theFileName.latin1() ) );
  if ( !study )
    return false;

  setStudyDS( study );

  // build a SUIT_DataObject-s tree under myRoot member field
  // 1. create myRoot
  setRoot( new SalomeApp_RootObject( this ) );
  // 2. iterate through all components and create corresponding sub-trees under them
  _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() );
  for ( ; it->More(); it->Next() ) {
    // don't use shared_ptr here, for Data Object will take
    // ownership of this pointer
    _PTR(SComponent) aComponent ( it->Value() );

    if ( aComponent->ComponentDataType() == "Interface Applicative" )
      continue; // skip the magic "Interface Applicative" component

    SalomeApp_DataModel::BuildTree( aComponent, root(), this );
  }

  bool res = CAM_Study::openDocument( theFileName );

  emit opened( this );

  return res;
}

//=======================================================================
// name    : loadDocument
// Purpose : Connects GUI study to SALOMEDS one already loaded into StudyManager
//=======================================================================
bool SalomeApp_Study::loadDocument( const QString& theStudyName )
{
  MESSAGE( "loadDocument" );

  // obtain myStudyDS from StudyManager
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( (char*) theStudyName.latin1() ) );
  if ( !study )
    return false;

  setStudyDS( study );

  // build a SUIT_DataObject-s tree under myRoot member field
  // 1. create myRoot
  setRoot( new SalomeApp_RootObject( this ) );
  // 2. iterate through all components and create corresponding sub-trees under them
  _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() );
  for ( ; it->More(); it->Next() ) {
    // don't use shared_ptr here, for Data Object will take
    // ownership of this pointer
    _PTR(SComponent) aComponent ( it->Value() );

    if ( aComponent->ComponentDataType() == "Interface Applicative" )
      continue; // skip the magic "Interface Applicative" component

    SalomeApp_DataModel::BuildTree( aComponent, root(), this );
  }

  // TODO: potentially unsafe call, since base study's openDocument() might try to access the file directly - to be improved
  bool res = CAM_Study::openDocument( theStudyName );

  emit opened( this );

  return res;
}

//=======================================================================
// name    : saveDocumentAs
// Purpose : Save document
//=======================================================================
bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
{
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
  for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
    aModel->saveAs( theFileName, this );

  bool res = CAM_Study::saveDocumentAs( theFileName );

  // save SALOMEDS document
  bool isMultiFile = false, isAscii = false;// TODO: This information should be taken from preferences afterwards!
  isAscii ? SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.latin1(), studyDS(), isMultiFile ) :
            SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.latin1(), studyDS(), isMultiFile );

  emit saved( this );

  return res;
}

//=======================================================================
// name    : saveDocument
// Purpose : Save document
//=======================================================================
void SalomeApp_Study::saveDocument()
{
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
  for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
    aModel->save();

  CAM_Study::saveDocument();

  // save SALOMEDS document
  bool isMultiFile = false, isAscii = false;// TODO: This information should be taken from preferences afterwards!
  isAscii ? SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
            SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile );

  emit saved( this );
}

//================================================================
// Function : closeDocument
// Purpose  :
//================================================================
void SalomeApp_Study::closeDocument()
{
  // Inform everybody that this study is going to close when it's most safe to,
  // i.e. in the very beginning
  emit closed( this );

  // close SALOMEDS document
  _PTR(Study) studyPtr = studyDS();
  if ( studyPtr.get() )
  {
    SalomeApp_Application::studyMgr()->Close( studyPtr );
    SALOMEDSClient_Study* aStudy = 0;
    setStudyDS( _PTR(Study)(aStudy) );
  }

  CAM_Study::closeDocument();
}

//================================================================
// Function : isModified
// Purpose  :
//================================================================
bool SalomeApp_Study::isModified() const
{
  bool isAnyChanged = studyDS() && studyDS()->IsModified();
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = 0;
  for ( QPtrListIterator<CAM_DataModel> it( list ); it.current() && !isAnyChanged; ++it ){
    aModel = dynamic_cast<SalomeApp_DataModel*>( it.current() );
    if ( aModel )
      isAnyChanged = aModel->isModified();
  }
  return isAnyChanged;
}

//================================================================
// Function : isSaved
// Purpose  :
//================================================================
bool SalomeApp_Study::isSaved() const
{
  bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = 0;
  for ( QPtrListIterator<CAM_DataModel> it( list ); it.current() && isAllSaved; ++it ){
    aModel = dynamic_cast<SalomeApp_DataModel*>( it.current() );
    if ( aModel )
      isAllSaved = aModel->isSaved();
  }
  return isAllSaved;
}

void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
{
  myStudyDS = s;
}

void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
{
  MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name());

  CAM_Study::dataModelInserted(dm);

  // Create SComponent for module, using default engine (CORBAless)
  SalomeApp_Module* aModule = (SalomeApp_Module*)(dm->module());
  if (aModule) {
    QString anEngineIOR = aModule->engineIOR();
    if (anEngineIOR.isEmpty()) { // CORBAless module
      // Check SComponent existance
      _PTR(SComponent) aComp = studyDS()->FindComponent(dm->module()->name());
      if (!aComp) {
        // Create SComponent
        _PTR(StudyBuilder) aBuilder = studyDS()->NewBuilder();
        aComp = aBuilder->NewComponent(dm->module()->name());

        // Set default engine IOR
        aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().latin1());
      }
    }
  }
}

bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
{
  if (!dm)
    return false;

  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
  if (aDM && aDM->open(studyName, this)) {
    // Something has been read -> create data model tree
    aDM->update(NULL, this);
    return true;
  }

  return false;
}

void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
{
  CAM_Study::updateModelRoot( dm );
  ((SalomeApp_Application*)application())->objectBrowser()->updateTree();
}

QString SalomeApp_Study::newStudyName() const
{
  std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
  QString prefix( "Study%1" ), newName, curName;
  int i = 1, j, n = studies.size();
  while ( newName.isEmpty() ){
    curName = prefix.arg( i );
    for ( j = 0 ; j < n; j++ ){
      if ( !strcmp( studies[j].c_str(), curName.latin1() ) )
	break;
    }
    if ( j == n )
      newName = curName;
    else
      i++;
  }
  return newName;
}
<commit_msg>setStudyName() called from createDocument() to avoid creating unnamed documents<commit_after>#include "SalomeApp_Study.h"

#include "SalomeApp_Module.h"
#include "SalomeApp_DataModel.h"
#include "SalomeApp_RootObject.h"
#include "SalomeApp_DataObject.h"
#include "SalomeApp_Application.h"

#include <OB_Browser.h>

#include <SUIT_ResourceMgr.h>

#include "utilities.h"

SalomeApp_Study::SalomeApp_Study( SUIT_Application* app )
: CAM_Study( app )
{
}

SalomeApp_Study::~SalomeApp_Study()
{
}

int SalomeApp_Study::id() const
{
  int id = -1;
  if ( myStudyDS )
    id = studyDS()->StudyId();
  return id;
}

_PTR(Study) SalomeApp_Study::studyDS() const
{
  return myStudyDS;
}

void SalomeApp_Study::createDocument()
{
  MESSAGE( "openDocument" );

  // initialize myStudyDS, read HDF file
  QString aName = newStudyName();
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->NewStudy( aName.latin1() ) );
  if ( !study )
    return;

  setStudyDS( study );
  setStudyName( aName );

  // create myRoot
  setRoot( new SalomeApp_RootObject( this ) );

  CAM_Study::createDocument();

  emit created( this );
}

//=======================================================================
// name    : openDocument
// Purpose : Open document
//=======================================================================
bool SalomeApp_Study::openDocument( const QString& theFileName )
{
  MESSAGE( "openDocument" );

  // initialize myStudyDS, read HDF file
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->Open( (char*) theFileName.latin1() ) );
  if ( !study )
    return false;

  setStudyDS( study );

  // build a SUIT_DataObject-s tree under myRoot member field
  // 1. create myRoot
  setRoot( new SalomeApp_RootObject( this ) );
  // 2. iterate through all components and create corresponding sub-trees under them
  _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() );
  for ( ; it->More(); it->Next() ) {
    // don't use shared_ptr here, for Data Object will take
    // ownership of this pointer
    _PTR(SComponent) aComponent ( it->Value() );

    if ( aComponent->ComponentDataType() == "Interface Applicative" )
      continue; // skip the magic "Interface Applicative" component

    SalomeApp_DataModel::BuildTree( aComponent, root(), this );
  }

  bool res = CAM_Study::openDocument( theFileName );

  emit opened( this );

  return res;
}

//=======================================================================
// name    : loadDocument
// Purpose : Connects GUI study to SALOMEDS one already loaded into StudyManager
//=======================================================================
bool SalomeApp_Study::loadDocument( const QString& theStudyName )
{
  MESSAGE( "loadDocument" );

  // obtain myStudyDS from StudyManager
  _PTR(Study) study ( SalomeApp_Application::studyMgr()->GetStudyByName( (char*) theStudyName.latin1() ) );
  if ( !study )
    return false;

  setStudyDS( study );

  // build a SUIT_DataObject-s tree under myRoot member field
  // 1. create myRoot
  setRoot( new SalomeApp_RootObject( this ) );
  // 2. iterate through all components and create corresponding sub-trees under them
  _PTR(SComponentIterator) it ( studyDS()->NewComponentIterator() );
  for ( ; it->More(); it->Next() ) {
    // don't use shared_ptr here, for Data Object will take
    // ownership of this pointer
    _PTR(SComponent) aComponent ( it->Value() );

    if ( aComponent->ComponentDataType() == "Interface Applicative" )
      continue; // skip the magic "Interface Applicative" component

    SalomeApp_DataModel::BuildTree( aComponent, root(), this );
  }

  // TODO: potentially unsafe call, since base study's openDocument() might try to access the file directly - to be improved
  bool res = CAM_Study::openDocument( theStudyName );

  emit opened( this );

  return res;
}

//=======================================================================
// name    : saveDocumentAs
// Purpose : Save document
//=======================================================================
bool SalomeApp_Study::saveDocumentAs( const QString& theFileName )
{
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
  for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
    aModel->saveAs( theFileName, this );

  bool res = CAM_Study::saveDocumentAs( theFileName );

  // save SALOMEDS document
  bool isMultiFile = false, isAscii = false;// TODO: This information should be taken from preferences afterwards!
  isAscii ? SalomeApp_Application::studyMgr()->SaveAsASCII( theFileName.latin1(), studyDS(), isMultiFile ) :
            SalomeApp_Application::studyMgr()->SaveAs     ( theFileName.latin1(), studyDS(), isMultiFile );

  emit saved( this );

  return res;
}

//=======================================================================
// name    : saveDocument
// Purpose : Save document
//=======================================================================
void SalomeApp_Study::saveDocument()
{
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)list.first();
  for ( ; aModel; aModel = (SalomeApp_DataModel*)list.next() )
    aModel->save();

  CAM_Study::saveDocument();

  // save SALOMEDS document
  bool isMultiFile = false, isAscii = false;// TODO: This information should be taken from preferences afterwards!
  isAscii ? SalomeApp_Application::studyMgr()->SaveASCII( studyDS(), isMultiFile ) :
            SalomeApp_Application::studyMgr()->Save     ( studyDS(), isMultiFile );

  emit saved( this );
}

//================================================================
// Function : closeDocument
// Purpose  :
//================================================================
void SalomeApp_Study::closeDocument()
{
  // Inform everybody that this study is going to close when it's most safe to,
  // i.e. in the very beginning
  emit closed( this );

  // close SALOMEDS document
  _PTR(Study) studyPtr = studyDS();
  if ( studyPtr )
  {
    SalomeApp_Application::studyMgr()->Close( studyPtr );
    SALOMEDSClient_Study* aStudy = 0;
    setStudyDS( _PTR(Study)(aStudy) );
  }

  CAM_Study::closeDocument();
}

//================================================================
// Function : isModified
// Purpose  :
//================================================================
bool SalomeApp_Study::isModified() const
{
  bool isAnyChanged = studyDS() && studyDS()->IsModified();
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = 0;
  for ( QPtrListIterator<CAM_DataModel> it( list ); it.current() && !isAnyChanged; ++it ){
    aModel = dynamic_cast<SalomeApp_DataModel*>( it.current() );
    if ( aModel )
      isAnyChanged = aModel->isModified();
  }
  return isAnyChanged;
}

//================================================================
// Function : isSaved
// Purpose  :
//================================================================
bool SalomeApp_Study::isSaved() const
{
  bool isAllSaved = studyDS() && studyDS()->GetPersistentReference().size();
  ModelList list; dataModels( list );

  SalomeApp_DataModel* aModel = 0;
  for ( QPtrListIterator<CAM_DataModel> it( list ); it.current() && isAllSaved; ++it ){
    aModel = dynamic_cast<SalomeApp_DataModel*>( it.current() );
    if ( aModel )
      isAllSaved = aModel->isSaved();
  }
  return isAllSaved;
}

void SalomeApp_Study::setStudyDS( const _PTR(Study)& s )
{
  myStudyDS = s;
}

void SalomeApp_Study::dataModelInserted (const CAM_DataModel* dm)
{
  MESSAGE("SalomeApp_Study::dataModelInserted() : module name() = " << dm->module()->name());

  CAM_Study::dataModelInserted(dm);

  // Create SComponent for module, using default engine (CORBAless)
  SalomeApp_Module* aModule = (SalomeApp_Module*)(dm->module());
  if (aModule) {
    QString anEngineIOR = aModule->engineIOR();
    if (anEngineIOR.isEmpty()) { // CORBAless module
      // Check SComponent existance
      _PTR(SComponent) aComp = studyDS()->FindComponent(dm->module()->name());
      if (!aComp) {
        // Create SComponent
        _PTR(StudyBuilder) aBuilder = studyDS()->NewBuilder();
        aComp = aBuilder->NewComponent(dm->module()->name());

        // Set default engine IOR
        aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().latin1());
      }
    }
  }
}

bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm )
{
  if (!dm)
    return false;

  SalomeApp_DataModel* aDM = (SalomeApp_DataModel*)(dm);
  if (aDM && aDM->open(studyName, this)) {
    // Something has been read -> create data model tree
    aDM->update(NULL, this);
    return true;
  }

  return false;
}

void SalomeApp_Study::updateModelRoot( const CAM_DataModel* dm )
{
  CAM_Study::updateModelRoot( dm );
  ((SalomeApp_Application*)application())->objectBrowser()->updateTree();
}

QString SalomeApp_Study::newStudyName() const
{
  std::vector<std::string> studies = SalomeApp_Application::studyMgr()->GetOpenStudies();
  QString prefix( "Study%1" ), newName, curName;
  int i = 1, j, n = studies.size();
  while ( newName.isEmpty() ){
    curName = prefix.arg( i );
    for ( j = 0 ; j < n; j++ ){
      if ( !strcmp( studies[j].c_str(), curName.latin1() ) )
	break;
    }
    if ( j == n )
      newName = curName;
    else
      i++;
  }
  return newName;
}
<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_WebSocketHandshakeParser.h"

namespace jnc {
namespace io {

//..............................................................................

bool
findInCsvStringIgnoreCase(
	const sl::StringRef& string0,
	const sl::StringRef& value,
	char c = ','
	)
{
	sl::StringRef string = string0;

	for (size_t i = 0;; i++)
	{
		size_t delim = string.find(c);
		if (delim == -1)
			return string.cmpIgnoreCase(value) == 0 ? i : -1;

		if (string.getLeftSubString(delim).getRightTimmedString().cmpIgnoreCase(value) == 0)
			return i;

		string = string.getSubString(i + 1).getLeftTrimmedString();
	}
}

//..............................................................................

WebSocketHandshakeParser::WebSocketHandshakeParser(
	WebSocketHandshake* handshake,
	const sl::StringRef& key
	)
{
	handshake->clear();
	m_handshake = handshake;
	m_key = key;
	m_state = key.isEmpty() ? State_RequestLine : State_ResponseLine;
}

size_t
WebSocketHandshakeParser::bufferLine(
	const char* p,
	size_t size
	)
{
	char* lf = (char*)memchr(p, '\n', size);
	if (lf)
		size = lf - p + 1;

	if (m_line.getLength() + size > MaxLineLength)
		return err::fail<size_t>(-1, "HTTP request line length limit exceeded");

	m_line.append(p, size);
	return size;
}

size_t
WebSocketHandshakeParser::parse(
	const void* p0,
	size_t size
	)
{
	const char* p = (char*)p0;
	const char* end = p + size;

	while (p < end && m_state != State_Completed)
	{
		size_t result = bufferLine(p, end - p);
		if (result == -1)
			return -1;

		p += result;

		if (!m_line.isSuffix('\n')) // incomplete line
			break;

		m_line.trim();

		switch (m_state)
		{
		case State_RequestLine:
			result = parseRequestLine();
			break;

		case State_ResponseLine:
			result = parseResponseLine();
			break;

		case State_HeaderLine:
			result = parseHeaderLine();
			break;

		default:
			ASSERT(false);
		}

		if (!result)
			return -1;

		m_line.clear();
	}

	size_t length = p - (char*)p0;
	m_handshake->m_rawData = m_handshake->m_rawData.m_string + sl::StringRef((char*)p0, length);
	return length;
}

bool
WebSocketHandshakeParser::parseRequestLine()
{
	size_t delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP request line: missing resource");

	sl::StringRef verb = m_line.getLeftSubString(delim);
	if (verb != "GET")
		return err::fail("invalid HTTP request: unexpected verb");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP request line: missing version");

	m_handshake->m_resource = m_line.getLeftSubString(delim);

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	if (!m_line.isPrefix("HTTP/"))
		return err::fail("invalid HTTP request line: unexpected version prefix");

	m_line.remove(0, lengthof("HTTP/"));
	m_handshake->m_httpVersion = strtoul(m_line, NULL, 10) << 8;

	delim = m_line.find('.');
	if (delim != -1)
	{
		m_line.remove(0, delim + 1);
		m_handshake->m_httpVersion |= strtoul(m_line, NULL, 10);
	}

	m_state = State_HeaderLine;
	return true;
}

bool
WebSocketHandshakeParser::parseResponseLine()
{
	if (!m_line.isPrefix("HTTP/"))
		return err::fail("invalid HTTP response line: unexpected version prefix");

	m_line.remove(0, lengthof("HTTP/"));
	m_handshake->m_httpVersion = strtoul(m_line, NULL, 10) << 8;

	size_t delim = m_line.find('.');
	if (delim != -1)
	{
		m_line.remove(0, delim + 1);
		m_handshake->m_httpVersion |= strtoul(m_line, NULL, 10);
	}

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP response line: missing status code");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	m_handshake->m_statusCode = strtoul(m_line, NULL, 10);

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP response line: missing reason phrase");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();
	m_handshake->m_reasonPhrase = m_line;
	m_state = State_HeaderLine;
	return true;
}

bool
WebSocketHandshakeParser::parseHeaderLine()
{
	if (m_line.isEmpty())
		return finalize();

	size_t delim = m_line.find(':');
	if (delim == -1)
		return err::fail("invalid HTTP header line");

	sl::StringRef key = m_line.getLeftSubString(delim).getRightTimmedString();
	sl::StringRef value = m_line.getSubString(delim + 1).getLeftTrimmedString();
	m_handshake->m_headers->addImpl(key, value);
	return true;
}

bool
WebSocketHandshakeParser::finalize()
{
	if (m_handshake->m_httpVersion < 0x0101) // HTTP/1.1
		return err::fail("unsupported HTTP version");

	const WebSocketHandshakeHeader* const* stdHeaderTable = m_handshake->m_headers->getStdHeaderTable();

	bool hasMissingFields = !m_key.isEmpty() ?
		!stdHeaderTable[WebSocketHandshakeStdHeader_Connection] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketAccept]
		:
		!stdHeaderTable[WebSocketHandshakeStdHeader_Host] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Connection] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketVersion] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketKey];

	if (hasMissingFields)
		return err::fail("invalid handshake: missing one or more required HTTP headers");

	size_t i = findInCsvStringIgnoreCase(stdHeaderTable[WebSocketHandshakeStdHeader_Connection]->m_firstValue, "upgrade");
	if (i == -1)
		return err::fail("invalid handshake: missing 'Upgrade' in HTTP 'Connection' header");

	if (stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade]->m_firstValue.m_string.cmpIgnoreCase("websocket") != 0)
		return err::fail("invalid handshake: unexpected value of HTTP 'Upgrade' header");

	if (!m_key.isEmpty() && !verifyAccept())
		return false;

	m_state = State_Completed;
	return true;
}

bool
WebSocketHandshakeParser::verifyAccept()
{
	const WebSocketHandshakeHeader* accept = m_handshake->m_headers->getStdHeader(WebSocketHandshakeStdHeader_WebSocketAccept);
	ASSERT(!m_key.isEmpty() && accept);

	if (m_handshake->m_statusCode != 101)
	{
		err::setFormatStringError(
			"failure to switch HTTP protocol: %d %s",
			m_handshake->m_statusCode,
			m_handshake->m_reasonPhrase.sz()
			);

		return false;
	}

	char buffer[256];
	sl::Array<char> acceptHash(rc::BufKind_Stack, buffer, sizeof(buffer));
	enc::Base64Encoding::decode(&acceptHash, accept->m_firstValue);
	if (acceptHash.getCount() != SHA_DIGEST_LENGTH)
		return err::fail("invalid handshake: bad 'Sec-WebSocket-Accept' format");

	uchar_t keyHash[SHA_DIGEST_LENGTH];
	calcWebSocketHandshakeKeyHash(keyHash, m_key);
	if (memcmp(acceptHash, keyHash, SHA_DIGEST_LENGTH) != 0)
		return err::fail("invalid handshake: 'Sec-WebSocket-Accept' doesn't match 'Sec-WebSocket-Key'");

	return true;
}

//..............................................................................

} // namespace io
} // namespace jnc
<commit_msg>[jnc_io_websocket] typo fix: bool -> size_t; potential errors during handshake header parsing (non-critical)<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_WebSocketHandshakeParser.h"

namespace jnc {
namespace io {

//..............................................................................

size_t
findInCsvStringIgnoreCase(
	const sl::StringRef& string0,
	const sl::StringRef& value,
	char c = ','
	)
{
	sl::StringRef string = string0;

	for (size_t i = 0;; i++)
	{
		size_t delim = string.find(c);
		if (delim == -1)
			return string.cmpIgnoreCase(value) == 0 ? i : -1;

		if (string.getLeftSubString(delim).getRightTimmedString().cmpIgnoreCase(value) == 0)
			return i;

		string = string.getSubString(i + 1).getLeftTrimmedString();
	}
}

//..............................................................................

WebSocketHandshakeParser::WebSocketHandshakeParser(
	WebSocketHandshake* handshake,
	const sl::StringRef& key
	)
{
	handshake->clear();
	m_handshake = handshake;
	m_key = key;
	m_state = key.isEmpty() ? State_RequestLine : State_ResponseLine;
}

size_t
WebSocketHandshakeParser::bufferLine(
	const char* p,
	size_t size
	)
{
	char* lf = (char*)memchr(p, '\n', size);
	if (lf)
		size = lf - p + 1;

	if (m_line.getLength() + size > MaxLineLength)
		return err::fail<size_t>(-1, "HTTP request line length limit exceeded");

	m_line.append(p, size);
	return size;
}

size_t
WebSocketHandshakeParser::parse(
	const void* p0,
	size_t size
	)
{
	const char* p = (char*)p0;
	const char* end = p + size;

	while (p < end && m_state != State_Completed)
	{
		size_t result = bufferLine(p, end - p);
		if (result == -1)
			return -1;

		p += result;

		if (!m_line.isSuffix('\n')) // incomplete line
			break;

		m_line.trim();

		switch (m_state)
		{
		case State_RequestLine:
			result = parseRequestLine();
			break;

		case State_ResponseLine:
			result = parseResponseLine();
			break;

		case State_HeaderLine:
			result = parseHeaderLine();
			break;

		default:
			ASSERT(false);
		}

		if (!result)
			return -1;

		m_line.clear();
	}

	size_t length = p - (char*)p0;
	m_handshake->m_rawData = m_handshake->m_rawData.m_string + sl::StringRef((char*)p0, length);
	return length;
}

bool
WebSocketHandshakeParser::parseRequestLine()
{
	size_t delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP request line: missing resource");

	sl::StringRef verb = m_line.getLeftSubString(delim);
	if (verb != "GET")
		return err::fail("invalid HTTP request: unexpected verb");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP request line: missing version");

	m_handshake->m_resource = m_line.getLeftSubString(delim);

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	if (!m_line.isPrefix("HTTP/"))
		return err::fail("invalid HTTP request line: unexpected version prefix");

	m_line.remove(0, lengthof("HTTP/"));
	m_handshake->m_httpVersion = strtoul(m_line, NULL, 10) << 8;

	delim = m_line.find('.');
	if (delim != -1)
	{
		m_line.remove(0, delim + 1);
		m_handshake->m_httpVersion |= strtoul(m_line, NULL, 10);
	}

	m_state = State_HeaderLine;
	return true;
}

bool
WebSocketHandshakeParser::parseResponseLine()
{
	if (!m_line.isPrefix("HTTP/"))
		return err::fail("invalid HTTP response line: unexpected version prefix");

	m_line.remove(0, lengthof("HTTP/"));
	m_handshake->m_httpVersion = strtoul(m_line, NULL, 10) << 8;

	size_t delim = m_line.find('.');
	if (delim != -1)
	{
		m_line.remove(0, delim + 1);
		m_handshake->m_httpVersion |= strtoul(m_line, NULL, 10);
	}

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP response line: missing status code");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();

	m_handshake->m_statusCode = strtoul(m_line, NULL, 10);

	delim = m_line.find(' ');
	if (delim == -1)
		return err::fail("invalid HTTP response line: missing reason phrase");

	m_line.remove(0, delim + 1);
	m_line.trimLeft();
	m_handshake->m_reasonPhrase = m_line;
	m_state = State_HeaderLine;
	return true;
}

bool
WebSocketHandshakeParser::parseHeaderLine()
{
	if (m_line.isEmpty())
		return finalize();

	size_t delim = m_line.find(':');
	if (delim == -1)
		return err::fail("invalid HTTP header line");

	sl::StringRef key = m_line.getLeftSubString(delim).getRightTimmedString();
	sl::StringRef value = m_line.getSubString(delim + 1).getLeftTrimmedString();
	m_handshake->m_headers->addImpl(key, value);
	return true;
}

bool
WebSocketHandshakeParser::finalize()
{
	if (m_handshake->m_httpVersion < 0x0101) // HTTP/1.1
		return err::fail("unsupported HTTP version");

	const WebSocketHandshakeHeader* const* stdHeaderTable = m_handshake->m_headers->getStdHeaderTable();

	bool hasMissingFields = !m_key.isEmpty() ?
		!stdHeaderTable[WebSocketHandshakeStdHeader_Connection] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketAccept]
		:
		!stdHeaderTable[WebSocketHandshakeStdHeader_Host] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Connection] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketVersion] ||
		!stdHeaderTable[WebSocketHandshakeStdHeader_WebSocketKey];

	if (hasMissingFields)
		return err::fail("invalid handshake: missing one or more required HTTP headers");

	size_t i = findInCsvStringIgnoreCase(stdHeaderTable[WebSocketHandshakeStdHeader_Connection]->m_firstValue, "upgrade");
	if (i == -1)
		return err::fail("invalid handshake: missing 'Upgrade' in HTTP 'Connection' header");

	if (stdHeaderTable[WebSocketHandshakeStdHeader_Upgrade]->m_firstValue.m_string.cmpIgnoreCase("websocket") != 0)
		return err::fail("invalid handshake: unexpected value of HTTP 'Upgrade' header");

	if (!m_key.isEmpty() && !verifyAccept())
		return false;

	m_state = State_Completed;
	return true;
}

bool
WebSocketHandshakeParser::verifyAccept()
{
	const WebSocketHandshakeHeader* accept = m_handshake->m_headers->getStdHeader(WebSocketHandshakeStdHeader_WebSocketAccept);
	ASSERT(!m_key.isEmpty() && accept);

	if (m_handshake->m_statusCode != 101)
	{
		err::setFormatStringError(
			"failure to switch HTTP protocol: %d %s",
			m_handshake->m_statusCode,
			m_handshake->m_reasonPhrase.sz()
			);

		return false;
	}

	char buffer[256];
	sl::Array<char> acceptHash(rc::BufKind_Stack, buffer, sizeof(buffer));
	enc::Base64Encoding::decode(&acceptHash, accept->m_firstValue);
	if (acceptHash.getCount() != SHA_DIGEST_LENGTH)
		return err::fail("invalid handshake: bad 'Sec-WebSocket-Accept' format");

	uchar_t keyHash[SHA_DIGEST_LENGTH];
	calcWebSocketHandshakeKeyHash(keyHash, m_key);
	if (memcmp(acceptHash, keyHash, SHA_DIGEST_LENGTH) != 0)
		return err::fail("invalid handshake: 'Sec-WebSocket-Accept' doesn't match 'Sec-WebSocket-Key'");

	return true;
}

//..............................................................................

} // namespace io
} // namespace jnc
<|endoftext|>


<commit_before>#ifdef __APPLE__
    // We can't set _POSIX_C_SOURCE on OS X because it hides the non-POSIX dladdr() with no way to get it back.
    // But we do need level 200809L features generally (for example, for EOWNERDEAD and ENOTRECOVERABLE on OS X).
    // So we do it the Apple Way.
    #define __DARWIN_C_LEVEL __DARWIN_C_FULL
#else
    // Needed for siginfo_t to be defined.
    #define _POSIX_C_SOURCE 200809L
#endif

// We need this for ucontext.h to give us useful context stuff...
#define _XOPEN_SOURCE 1

#include "crash.hpp"

// iostream wants this on Travis on Mac
#include <pthread.h>
#include <errno.h>

// Needed for automatic name demangling, but not all that portable
#include <cxxabi.h>
#include <execinfo.h>

// Needed to hack contexts for signal traces
 #include <ucontext.h>

// Needed to generate stacktraces ourselves
#include <dlfcn.h>

// We need strcmp
#include <cstring>

#include <cstdlib>
#include <unistd.h>
#include <string>
#include <iostream>
#include <fstream>
#include <signal.h>

#ifndef __APPLE__
    // Pull in backward-cpp and use libdw from elfutils.
    // In theory backward-cpp can build and even backtrace on mac
    // In practice the mac port doesn't work on my machine and breaks the build on Travis.
    #define BACKWARD_HAS_DW 1
    #include <backward.hpp>
#endif

namespace vg {

// env var for getting full stack trace on cerr instead of a file path
const char* var = "VG_FULL_TRACEBACK";
// fullTrace = true means env var was set
// fullTrace = false means env var was not set
bool fullTrace = false;

/// Emit a stack trace when something bad happens. Add as a signal handler with sigaction.
void emit_stacktrace(int signalNumber, siginfo_t *signalInfo, void *signalContext) {
    ofstream tempStream;
    string dirName;
    ostream* out;

    if (fullTrace == true) {
        out = &cerr;
    } else {
        char temp[] = "/tmp/vg_crash_XXXXXX";
        char* tempDir = mkdtemp(temp);
        dirName = tempDir;
        tempStream.open(dirName+ "/stacktrace.txt");
        out = &tempStream;
    }

    static backward::StackTrace stack_trace;
    stack_trace.load_here(32);
    static backward::Printer p;
    p.color_mode = backward::ColorMode::automatic;
    p.address = true;
    p.object = true;
    p.print(stack_trace, *out);

    if (fullTrace == false) {
        cerr << "ERROR: Signal "<< signalNumber << " occurred. VG has crashed. Run 'vg bugs --new' to report a bug." << endl;
        // Print path for stack trace file
        cerr << "Stack trace path: "<< dirName << "/stacktrace.txt" << endl;
    }
    // Make sure to exit with the right code
    exit(signalNumber + 128);
}

void enable_crash_handling() {
    // Set up stack trace support
        if (getenv(var) != nullptr) {
            if (strcmp(getenv(var), "1") == 0) {
                // if VG_FULL_TRACEBACK env var is set
                fullTrace = true;
            }
        }
        else {
            // if VG_FULL_TRACEBACK env var is not set
            fullTrace = false;
        }
        // backtrace() doesn't work in our Mac builds, and backward-cpp uses backtrace().
        // Do this the old-fashioned way.

        // We do it the cleverer sigaction way to try and make OS X backtrace not just tell us that the signal handler is being called.
        struct sigaction sig_config;
        sig_config.sa_flags = SA_SIGINFO; // Use the new API and not the old signal() API for the handler.
        sig_config.sa_sigaction = emit_stacktrace;
        sigemptyset(&sig_config.sa_mask);

        sigaction(SIGABRT, &sig_config, nullptr);
        sigaction(SIGSEGV, &sig_config, nullptr);
        sigaction(SIGBUS, &sig_config, nullptr);
        sigaction(SIGILL, &sig_config, nullptr);

    // We don't set_terminate for aborts because we still want the standard
    // library's message about what the exception was.
}

}
<commit_msg>Added stacktrace functionality to Mac and Linux systems<commit_after>#ifdef __APPLE__
    // We can't set _POSIX_C_SOURCE on OS X because it hides the non-POSIX dladdr() with no way to get it back.
    // But we do need level 200809L features generally (for example, for EOWNERDEAD and ENOTRECOVERABLE on OS X).
    // So we do it the Apple Way.
    #define __DARWIN_C_LEVEL __DARWIN_C_FULL
#else
    // Needed for siginfo_t to be defined.
    #define _POSIX_C_SOURCE 200809L
#endif

// We need this for ucontext.h to give us useful context stuff...
#define _XOPEN_SOURCE 1

#include "crash.hpp"

// iostream wants this on Travis on Mac
#include <pthread.h>
#include <errno.h>

// Needed for automatic name demangling, but not all that portable
#include <cxxabi.h>
#include <execinfo.h>

// Needed to hack contexts for signal traces
 #include <ucontext.h>

// Needed to generate stacktraces ourselves
#include <dlfcn.h>

// We need strcmp
#include <cstring>

#include <cstdlib>
#include <unistd.h>
#include <string>
#include <iostream>
#include <fstream>
#include <signal.h>

#ifndef __APPLE__
    // Pull in backward-cpp and use libdw from elfutils.
    // In theory backward-cpp can build and even backtrace on mac
    // In practice the mac port doesn't work on my machine and breaks the build on Travis.
    #define BACKWARD_HAS_DW 1
    #include <backward.hpp>
#endif

namespace vg {

// env var for getting full stack trace on cerr instead of a file path
const char* var = "VG_FULL_TRACEBACK";
// fullTrace = true means env var was set
// fullTrace = false means env var was not set
bool fullTrace = false;

void stacktrace_manually(ostream& out, int signalNumber, void* ip, void** bp) {
    // Now we compute our own stack trace, because backtrace() isn't so good on OS X.
    // We operate on the same principles as <https://stackoverflow.com/a/5426269>

    // Unfortunately this *only* seems to work even a little well on OS X; on Linux we get ip
    // wandering off relatively quickly.

    // Allocate a place to keep the dynamic library info for the address the stack is executing at
    Dl_info address_library;

    out << endl;
    out << "Next ip: " << ip << " Next bp: " << bp << endl;
    while (true) {
        // Work out where the ip is.
        if (!dladdr(ip, &address_library)) {
            // This address doesn't belong to anything!
            out << "Stack leaves code at ip=" << ip << endl;
            break;
        }

        if (address_library.dli_sname != nullptr) {
            // Make a place for the demangling function to save its status
            int status;

            // Do the demangling
            char* demangledName = abi::__cxa_demangle(address_library.dli_sname, NULL, NULL, &status);

            if(status == 0) {
                // Successfully demangled
                out << "Address " << ip << " in demangled symbol " << demangledName
                    << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                    << ", in library " << address_library.dli_fname
                    << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
                free(demangledName);
            } else {
                // Leave mangled
                out << "Address " << ip << " in mangled symbol " << address_library.dli_sname
                    << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                    << ", in library " << address_library.dli_fname
                    << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
            }

            #ifdef __APPLE__
                #ifdef VG_DO_ATOS
                    // Try running atos to print a line number. This can be slow so we don't do it by default.
                    stringstream command;

                    command << "atos -o " << address_library.dli_fname << " -l " << address_library.dli_fbase << " " << ip;
                    out << "Running " << command.str() << "..." << endl;
                    system(command.str().c_str());
                #endif
            #endif

        } else {
            out << "Address " << ip << " out of symbol in library " << address_library.dli_fname << endl;
        }

        if(address_library.dli_sname != nullptr && !strcmp(address_library.dli_sname, "main")) {
            out << "Stack hit main" << endl;
            break;
        }

        if (bp != nullptr) {
            // Simulate a return
            ip = bp[1];
            bp = (void**) bp[0];
        } else {
            break;
        }

        out << endl;
        out << "Next ip: " << ip << " Next bp: " << bp << endl;
    }

    out << "Stack trace complete" << endl;
    out << endl;

}

/// Emit a stack trace when something bad happens. Add as a signal handler with sigaction.
void emit_stacktrace(int signalNumber, siginfo_t *signalInfo, void *signalContext) {
    ofstream tempStream;
    string dirName;
    ostream* out;

    if (fullTrace == true) {
        out = &cerr;
    } else {
        char temp[] = "/tmp/vg_crash_XXXXXX";
        char* tempDir = mkdtemp(temp);
        dirName = tempDir;
        tempStream.open(dirName+ "/stacktrace.txt");
        out = &tempStream;
    }

    #ifdef __APPLE__
        // OS X 64 bit does it this way
        // This holds the context that the signal came from, including registers and stuff
        ucontext_t* context = (ucontext_t*) signalContext;

        // TODO: This assumes x86
        // Fetch out the registers
        // We model IP as a pointer to void (i.e. into code)
        void* ip;
        // We model BP as an array of two things: previous BP, and previous IP.
        void** bp;
        ip = (void*)context->uc_mcontext->__ss.__rip;
        bp = (void**)context->uc_mcontext->__ss.__rbp;
        *out << "Caught signal " << signalNumber << " raised at address " << ip << endl;
        // Do our own tracing because backtrace doesn't really work on all platforms.
        stacktrace_manually(*out,signalNumber, ip, bp);
    #else
        // Linux 64 bit does it this way
        static backward::StackTrace stack_trace;
        stack_trace.load_here(32);
        static backward::Printer p;
        p.color_mode = backward::ColorMode::automatic;
        p.address = true;
        p.object = true;
        p.print(stack_trace, *out);
        tempStream.close();
    #endif

    if (fullTrace == false) {
        cerr << "ERROR: Signal "<< signalNumber << " occurred. VG has crashed. Run 'vg bugs --new' to report a bug." << endl;
        // Print path for stack trace file
        cerr << "Stack trace path: "<< dirName << "/stacktrace.txt" << endl;
    }
    // Make sure to exit with the right code
    exit(signalNumber + 128);
}

void enable_crash_handling() {
    // Set up stack trace support
        if (getenv(var) != nullptr) {
            if (strcmp(getenv(var), "1") == 0) {
                // if VG_FULL_TRACEBACK env var is set
                fullTrace = true;
            }
        }
        else {
            // if VG_FULL_TRACEBACK env var is not set
            fullTrace = false;
        }
        // backtrace() doesn't work in our Mac builds, and backward-cpp uses backtrace().
        // Do this the old-fashioned way.

        // We do it the cleverer sigaction way to try and make OS X backtrace not just tell us that the signal handler is being called.
        struct sigaction sig_config;
        sig_config.sa_flags = SA_SIGINFO; // Use the new API and not the old signal() API for the handler.
        sig_config.sa_sigaction = emit_stacktrace;
        sigemptyset(&sig_config.sa_mask);

        sigaction(SIGABRT, &sig_config, nullptr);
        sigaction(SIGSEGV, &sig_config, nullptr);
        sigaction(SIGBUS, &sig_config, nullptr);
        sigaction(SIGILL, &sig_config, nullptr);

    // We don't set_terminate for aborts because we still want the standard
    // library's message about what the exception was.
}

}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/color.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/config_error.hpp>

// agg
#include "agg_color_rgba.h"

// boost
#include <boost/spirit/include/karma.hpp>
// stl
#include <sstream>

namespace mapnik {

color::color(std::string const& str)
{
    *this = parse_color(str);
}

std::string color::to_string() const
{
    std::stringstream ss;
    if (alpha_ == 255)
    {
        ss << "rgb("
           << static_cast<unsigned>(red())   << ","
           << static_cast<unsigned>(green()) << ","
           << static_cast<unsigned>(blue())  << ")";
    }
    else
    {
        ss << "rgba("
           << static_cast<unsigned>(red())   << ","
           << static_cast<unsigned>(green()) << ","
           << static_cast<unsigned>(blue()) << ","
           << alpha() / 255.0 << ")";
    }
    return ss.str();
}

std::string color::to_hex_string() const
{
    namespace karma = boost::spirit::karma;
    using boost::spirit::karma::_1;
    using boost::spirit::karma::hex;
    using boost::spirit::karma::eps;
    using boost::spirit::karma::right_align;
    std::string str;
    std::back_insert_iterator<std::string> sink(str);
    karma::generate(sink,
                    // begin grammar
                    '#'
                    << right_align(2,'0')[hex[_1 = red()]]
                    << right_align(2,'0')[hex[_1 = green()]]
                    << right_align(2,'0')[hex[_1 = blue()]]
                    << eps(alpha() < 255) <<  right_align(2,'0')[hex [_1 = alpha()]]
                    // end grammar
        );
    return str;
}

void color::premultiply()
{
    agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_);
    pre_c.premultiply();
    red_ = pre_c.r;
    green_ = pre_c.g;
    blue_ = pre_c.b;
}

void color::demultiply()
{
    // note: this darkens too much: https://github.com/mapnik/mapnik/issues/1519
    agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_);
    pre_c.demultiply();
    red_ = pre_c.r;
    green_ = pre_c.g;
    blue_ = pre_c.b;
}

}
<commit_msg>+ to_string based on spirit::karma for completeness.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/color.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/config_error.hpp>

// agg
#include "agg_color_rgba.h"

// boost
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
// stl
#include <sstream>

namespace mapnik {

color::color(std::string const& str)
{
    *this = parse_color(str);
}

std::string color::to_string() const
{
    namespace karma = boost::spirit::karma;
    using boost::spirit::karma::_1;
    using boost::spirit::karma::eps;
    using boost::spirit::karma::double_;
    using boost::spirit::karma::string;
    boost::spirit::karma::uint_generator<uint8_t,10> color_generator;
    std::string str;
    std::back_insert_iterator<std::string> sink(str);
    karma::generate(sink,
                    // begin grammar
                    string[ phoenix::if_(alpha()==255) [_1="rgb("].else_[_1="rgba("]]
                    << color_generator[_1 = red()] << ','
                    << color_generator[_1 = green()] << ','
                    << color_generator[_1 = blue()]
                    << string[ phoenix::if_(alpha()==255) [_1 = ')'].else_[_1 =',']]
                    << eps(alpha()<255) << ',' << double_ [_1 = alpha()/255.0]
                    << ')'
                    // end grammar
        );
    return str;
}

std::string color::to_hex_string() const
{
    namespace karma = boost::spirit::karma;
    using boost::spirit::karma::_1;
    using boost::spirit::karma::hex;
    using boost::spirit::karma::eps;
    using boost::spirit::karma::right_align;
    std::string str;
    std::back_insert_iterator<std::string> sink(str);
    karma::generate(sink,
                    // begin grammar
                    '#'
                    << right_align(2,'0')[hex[_1 = red()]]
                    << right_align(2,'0')[hex[_1 = green()]]
                    << right_align(2,'0')[hex[_1 = blue()]]
                    << eps(alpha() < 255) <<  right_align(2,'0')[hex [_1 = alpha()]]
                    // end grammar
        );
    return str;
}

void color::premultiply()
{
    agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_);
    pre_c.premultiply();
    red_ = pre_c.r;
    green_ = pre_c.g;
    blue_ = pre_c.b;
}

void color::demultiply()
{
    // note: this darkens too much: https://github.com/mapnik/mapnik/issues/1519
    agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_);
    pre_c.demultiply();
    red_ = pre_c.r;
    green_ = pre_c.g;
    blue_ = pre_c.b;
}

}
<|endoftext|>


<commit_before>/**
   @file crema.cpp
   @brief Main cremacc file and main() function
   @copyright 2014 Assured Information Security, Inc.
   @author Jacob Torrey <torreyj@ainfosec.com>

   A main function to read in an input. It will parse and perform semantic
   analysis on the input and either exit(0) if it passes both, -1 otherwise.
 */
#include <iostream>
#include "ast.h"
#include "codegen.h"

extern NBlock *rootBlock;
extern int yyparse();

int main(int argc, char **argv)
{
    yyparse();
    if (rootBlock)
      {
	std::cout << *rootBlock << std::endl;
	if (rootBlock->semanticAnalysis(&rootCtx))
	  {
	    std::cout << "Passed semantic analysis!" << std::endl;
	  }
	else
	  {
	    std::cout << "Failed semantic analysis!" << std::endl;
	    return -1;
	  }
      }

    std::cout << "Generating LLVM IR bytecode" << std::endl;
    rootCodeGenCtx.codeGen(rootBlock);

    std::cout << "Dumping generated LLVM bytecode" << std::endl;
    rootCodeGenCtx.dump();

/*
    std::cout << "Running program:" << std::endl;
    rootCodeGenCtx.runProgram();
    std::cout << "Program run successfully!" << std::endl;
*/
    return 0;
}
<commit_msg>cremacc now executes the IR if it was successfully generated<commit_after>/**
   @file crema.cpp
   @brief Main cremacc file and main() function
   @copyright 2014 Assured Information Security, Inc.
   @author Jacob Torrey <torreyj@ainfosec.com>

   A main function to read in an input. It will parse and perform semantic
   analysis on the input and either exit(0) if it passes both, -1 otherwise.
 */
#include <iostream>
#include "ast.h"
#include "codegen.h"

extern NBlock *rootBlock;
extern int yyparse();

int main(int argc, char **argv)
{
    yyparse();
    if (rootBlock)
      {
	std::cout << *rootBlock << std::endl;
	if (rootBlock->semanticAnalysis(&rootCtx))
	  {
	    std::cout << "Passed semantic analysis!" << std::endl;
	  }
	else
	  {
	    std::cout << "Failed semantic analysis!" << std::endl;
	    return -1;
	  }
      }

    std::cout << "Generating LLVM IR bytecode" << std::endl;
    rootCodeGenCtx.codeGen(rootBlock);

    std::cout << "Dumping generated LLVM bytecode" << std::endl;
    rootCodeGenCtx.dump();

    std::cout << "Running program:" << std::endl;
    std::cout << "Return value: " << rootCodeGenCtx.runProgram().IntVal.toString(10, true) << std::endl;
    std::cout << "Program run successfully!" << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2008 by Jeff Weisberg
  Author: Jeff Weisberg <jaw @ tcp4me.com>
  Created: 2008-Dec-28 11:05 (EST)
  Function: daemonize

  $Id$

*/

#define CURRENT_SUBSYSTEM	'd'

#include "defs.h"
#include "diag.h"
#include "hrtime.h"
#include "runmode.h"

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>

static int i_am_parent = 1;
static int childpid = 0;
static char pidfile[64];

static void
finish(void){
    int status;
    int i;

    DEBUG("finishing");

    if( childpid > 1 ){
	DEBUG("killing child");
	kill(childpid, 15);
        while(1){
            i = wait(&status);
            if( i == -1 && errno == EINTR ) continue;
            break;
        }
    }
    if( i_am_parent ){
        unlink(pidfile);
    }
}

static void
sigexit(int sig){
    VERBOSE("caught signal %d - exiting", sig);

    if( !i_am_parent && sig == 15 ){
	// in child. exit
        runmode.shutdown();
	return;
    }

    exit(EXIT_NORMAL_EXIT);
    // NB - parent will kill child in finish()
}

static void
sigrestart(int sig){
    int status;

    if( i_am_parent ){
        if( childpid > 1 ){
            VERBOSE("caught sig hup - restarting child");
            kill(childpid, 1);
        }
    }else{
	// in child. exit gracefully
	VERBOSE("caught sig hup - restarting");
        runmode.winddown_and_restart();
	return;
    }
}

void
install_handler(int sig, void(*func)(int)){
    struct sigaction sigi;

    sigi.sa_handler = func;
    sigi.sa_flags = 0;
    sigemptyset( & sigi.sa_mask );
    sigaction(sig, &sigi, 0);
}

void
daemon_siginit(void){

    // sig handlers
    install_handler(SIGHUP,   sigrestart);
    install_handler(SIGINT,   sigexit);
    install_handler(SIGQUIT,  sigexit);
    install_handler(SIGTERM,  sigexit);
    install_handler(SIGPIPE,  SIG_IGN);

}

int
daemonize(int to, const char *name, int argc, char **argv){
    int status = 0;
    FILE *pf;
    int i;

    // background
    if( fork() ) exit(0);

    // close fd
    close(0);  open("/dev/null", O_RDWR);
    close(1);  open("/dev/null", O_RDWR);
#ifndef DEBUGING
    close(2);  open("/dev/null", O_RDWR);
#endif

    setsid();

    daemon_siginit();

    // pidfile
    snprintf(pidfile, sizeof(pidfile), "/var/run/%s.pid", name);
    pf = fopen(pidfile, "w");
    if( !pf ){
	FATAL("cannot open pid file");
    }
    fprintf(pf, "%d\n", getpid());
    fprintf(pf, "#");

    for(i=1;i<argc;i++){
        fprintf(pf, " %s", argv[i]);
    }
    fprintf(pf, "\n");

    fclose(pf);

    atexit(finish);

    // watcher proc
    while(1){
	DEBUG("forking");
	childpid = fork();
	if( childpid == -1 ){
	    FATAL("cannot fork");
	}
	if( childpid ){
	    // parent
            while(1){
                i = wait(&status);
                if( i == -1 && errno == EINTR ) continue;
                break;
            }
	    childpid = 0;
	    DEBUG("child exited with %d", status);
	    if( !status ){
		VERBOSE("exiting");
		exit(EXIT_NORMAL_EXIT);
	    }
            // otherwise, pause + restart
	    sleep(to);
	}else{
	    // child
            i_am_parent = 0;
	    return status;
	}
    }
}

<commit_msg>always close<commit_after>/*
  Copyright (c) 2008 by Jeff Weisberg
  Author: Jeff Weisberg <jaw @ tcp4me.com>
  Created: 2008-Dec-28 11:05 (EST)
  Function: daemonize

  $Id$

*/

#define CURRENT_SUBSYSTEM	'd'

#include "defs.h"
#include "diag.h"
#include "hrtime.h"
#include "runmode.h"

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>

static int i_am_parent = 1;
static int childpid = 0;
static char pidfile[64];

static void
finish(void){
    int status;
    int i;

    DEBUG("finishing");

    if( childpid > 1 ){
	DEBUG("killing child");
	kill(childpid, 15);
        while(1){
            i = wait(&status);
            if( i == -1 && errno == EINTR ) continue;
            break;
        }
    }
    if( i_am_parent ){
        unlink(pidfile);
    }
}

static void
sigexit(int sig){
    VERBOSE("caught signal %d - exiting", sig);

    if( !i_am_parent && sig == 15 ){
	// in child. exit
        runmode.shutdown();
	return;
    }

    exit(EXIT_NORMAL_EXIT);
    // NB - parent will kill child in finish()
}

static void
sigrestart(int sig){
    int status;

    if( i_am_parent ){
        if( childpid > 1 ){
            VERBOSE("caught sig hup - restarting child");
            kill(childpid, 1);
        }
    }else{
	// in child. exit gracefully
	VERBOSE("caught sig hup - restarting");
        runmode.winddown_and_restart();
	return;
    }
}

void
install_handler(int sig, void(*func)(int)){
    struct sigaction sigi;

    sigi.sa_handler = func;
    sigi.sa_flags = 0;
    sigemptyset( & sigi.sa_mask );
    sigaction(sig, &sigi, 0);
}

void
daemon_siginit(void){

    // sig handlers
    install_handler(SIGHUP,   sigrestart);
    install_handler(SIGINT,   sigexit);
    install_handler(SIGQUIT,  sigexit);
    install_handler(SIGTERM,  sigexit);
    install_handler(SIGPIPE,  SIG_IGN);

}

int
daemonize(int to, const char *name, int argc, char **argv){
    int status = 0;
    FILE *pf;
    int i;

    // background
    if( fork() ) exit(0);

    // close fd
    close(0);  open("/dev/null", O_RDWR);
    close(1);  open("/dev/null", O_RDWR);
    close(2);  open("/dev/null", O_RDWR);

    setsid();

    daemon_siginit();

    // pidfile
    snprintf(pidfile, sizeof(pidfile), "/var/run/%s.pid", name);
    pf = fopen(pidfile, "w");
    if( !pf ){
	FATAL("cannot open pid file");
    }
    fprintf(pf, "%d\n", getpid());
    fprintf(pf, "#");

    for(i=1;i<argc;i++){
        fprintf(pf, " %s", argv[i]);
    }
    fprintf(pf, "\n");

    fclose(pf);

    atexit(finish);

    // watcher proc
    while(1){
	DEBUG("forking");
	childpid = fork();
	if( childpid == -1 ){
	    FATAL("cannot fork");
	}
	if( childpid ){
	    // parent
            while(1){
                i = wait(&status);
                if( i == -1 && errno == EINTR ) continue;
                break;
            }
	    childpid = 0;
	    DEBUG("child exited with %d", status);
	    if( !status ){
		VERBOSE("exiting");
		exit(EXIT_NORMAL_EXIT);
	    }
            // otherwise, pause + restart
	    sleep(to);
	}else{
	    // child
            i_am_parent = 0;
	    return status;
	}
    }
}

<|endoftext|>