<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 <string>
#include "base/file_path.h"
#include "base/waitable_event.h"
#include "chrome_frame/cfproxy_private.h"
#include "chrome/test/automation/automation_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"

using testing::_;
using testing::DoAll;
using testing::NotNull;
using testing::Return;
using testing::StrictMock;
using testing::InvokeWithoutArgs;
using testing::WithoutArgs;
using testing::CreateFunctor;

// There is not much to test here since CFProxy is pretty dumb.
struct MockFactory : public ChromeProxyFactory {
  MOCK_METHOD0(CreateProxy, ChromeProxy*());
};

struct MockChromeProxyDelegate : public ChromeProxyDelegate {
  MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
  MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
  MOCK_METHOD0(Disconnected, void());
  MOCK_METHOD0(tab_handle, int());

  MOCK_METHOD4(Completed_CreateTab, void(bool success, HWND chrome_wnd,
      HWND tab_window, int tab_handle));
  MOCK_METHOD4(Completed_ConnectToTab, void(bool success, HWND chrome_window,
      HWND tab_window, int tab_handle));
  MOCK_METHOD2(Completed_Navigate, void(bool success,
      enum AutomationMsg_NavigationResponseValues res));
  MOCK_METHOD3(Completed_InstallExtension, void(bool success,
      enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
  MOCK_METHOD3(Completed_LoadExpandedExtension, void(bool success,
      enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
  MOCK_METHOD2(Completed_GetEnabledExtensions, void(bool success,
      const std::vector<FilePath>* v));

  // Network requests from Chrome.
  MOCK_METHOD2(Network_Start, void(int request_id,
      const IPC::AutomationURLRequest& request_info));
  MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
  MOCK_METHOD2(Network_End, void(int request_id, const URLRequestStatus& s));
  MOCK_METHOD1(Network_DownloadInHost, void(int request_id));
  MOCK_METHOD2(GetCookies, void(const GURL& url, int cookie_id));
  MOCK_METHOD2(SetCookie, void(const GURL& url, const std::string& cookie));

  // Navigation progress notifications.
  MOCK_METHOD2(NavigationStateChanged, void(int flags,
      const IPC::NavigationInfo& nav_info));
  MOCK_METHOD1(UpdateTargetUrl, void(const std::wstring& url));
  MOCK_METHOD2(NavigationFailed, void(int error_code, const GURL& gurl));
  MOCK_METHOD1(DidNavigate, void(const IPC::NavigationInfo& navigation_info));
  MOCK_METHOD1(TabLoaded, void(const GURL& url));

  //
  MOCK_METHOD3(OpenURL, void(const GURL& url_to_open, const GURL& referrer,
      int open_disposition));
  MOCK_METHOD1(GoToHistoryOffset, void(int offset));
  MOCK_METHOD3(MessageToHost, void(const std::string& message,
      const std::string& origin, const std::string& target));

  // Misc. UI.
  MOCK_METHOD1(HandleAccelerator, void(const MSG& accel_message));
  MOCK_METHOD1(TabbedOut, void(bool reverse));

  //
  MOCK_METHOD0(TabClosed, void());
  MOCK_METHOD1(AttachTab,
      void(const IPC::AttachExternalTabParams& attach_params));
};

struct MockSender : public IPC::Message::Sender {
  MOCK_METHOD1(Send, bool(IPC::Message* m));
};

struct MockCFProxyTraits : public CFProxyTraits {
  MOCK_METHOD2(DoCreateChannel, IPC::Message::Sender*(const std::string& id,
      IPC::Channel::Listener* l));
  MOCK_METHOD1(CloseChannel, void(IPC::Message::Sender* s));
  MOCK_METHOD1(LaunchApp, bool(const std::wstring& cmd_line));

  // Forward the CreateChannel to DoCreateChannel, but save the ipc_thread
  // and the listener (i.e. proxy implementation of Channel::Listener)
  virtual IPC::Message::Sender* CreateChannel(const std::string& id,
    IPC::Channel::Listener* l) {
      ipc_loop = MessageLoop::current();
      listener = l;
      return this->DoCreateChannel(id, l);
  }

  // Simulate some activity in the IPC thread.
  // You may find API_FIRE_XXXX macros (see below) handy instead.
  void FireConnect(base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnChannelConnected, 0), t.InMilliseconds());
  }

  void FireError(base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnChannelError), t.InMilliseconds());
  }

  void FireMessage(const IPC::Message& m, base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnMessageReceived, m), t.InMilliseconds());
  }

  MockCFProxyTraits() : ipc_loop(NULL) {}
  MockSender sender;
 private:
  MessageLoop* ipc_loop;
  IPC::Channel::Listener* listener;
};

// Handy macros when we want so similate something on the IPC thread.
#define API_FIRE_CONNECT(api, t)  InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireConnect, t))
#define API_FIRE_ERROR(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireError, t))
#define API_FIRE_MESSAGE(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireMessage, t))
DISABLE_RUNNABLE_METHOD_REFCOUNT(IPC::Channel::Listener);

TEST(ChromeProxy, DelegateAddRemove) {
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  StrictMock<MockFactory> factory;    // to be destroyed before other mocks
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate, Disconnected());

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(4);
  factory.GetProxy(&delegate, params);
  factory.ReleaseProxy(&delegate, params.profile);
}

// Not very useful test. Just for illustration. :)
TEST(ChromeProxy, SharedProxy) {
  base::WaitableEvent done1(false, false);
  base::WaitableEvent done2(false, false);
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate1;
  StrictMock<MockChromeProxyDelegate> delegate2;
  StrictMock<MockFactory> factory;
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
      API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(150)),
      Return(true)));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate1, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate2, tab_handle()).WillRepeatedly(Return(0));

  EXPECT_CALL(delegate1, Connected(proxy))
      .WillOnce(InvokeWithoutArgs(&done1, &base::WaitableEvent::Signal));
  EXPECT_CALL(delegate2, Connected(proxy))
      .WillOnce(InvokeWithoutArgs(&done2, &base::WaitableEvent::Signal));

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(4);

  factory.GetProxy(&delegate1, params);
  params.timeout = base::TimeDelta::FromSeconds(2);
  factory.GetProxy(&delegate2, params);

  EXPECT_TRUE(done1.TimedWait(base::TimeDelta::FromSeconds(1)));
  EXPECT_TRUE(done2.TimedWait(base::TimeDelta::FromSeconds(1)));

  EXPECT_CALL(delegate2, Disconnected());
  EXPECT_CALL(delegate1, Disconnected());

  factory.ReleaseProxy(&delegate2, params.profile);
  factory.ReleaseProxy(&delegate1, params.profile);
}

TEST(ChromeProxy, LaunchTimeout) {
  base::WaitableEvent done(true, false);
  StrictMock<MockFactory> factory;
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate, PeerLost(_,
                      ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT))
      .WillOnce(InvokeWithoutArgs(&done, &base::WaitableEvent::Signal));
  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromMilliseconds(300);
  factory.GetProxy(&delegate, params);
  EXPECT_TRUE(done.TimedWait(base::TimeDelta::FromSeconds(1)));

  EXPECT_CALL(delegate, Disconnected());
  factory.ReleaseProxy(&delegate, params.profile);
}

TEST(ChromeProxy, LaunchChrome) {
  base::WaitableEvent connected(false, false);
  StrictMock<MockChromeProxyDelegate> delegate;
  ChromeProxyFactory factory;

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(10);

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate, Connected(NotNull()))
    .WillOnce(InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal));

  factory.GetProxy(&delegate, params);
  EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));

  EXPECT_CALL(delegate, Disconnected());
  factory.ReleaseProxy(&delegate, params.profile);
}

///////////////////////////////////////////////////////////////////////////////
namespace {
template <typename M, typename A>
inline IPC::Message* CreateReply(M* m, const A& a) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a);
  }
  return r;
}

template <typename M, typename A, typename B>
inline IPC::Message* CreateReply(M* m, const A& a, const B& b) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a, b);
  }
  return r;
}

template <typename M, typename A, typename B, typename C>
inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a, b, c);
  }
  return r;
}
}  // namespace

DISABLE_RUNNABLE_METHOD_REFCOUNT(SyncMsgSender);
TEST(SyncMsgSender, Deserialize) {
  // Note the ipc thread is not actually needed, but we try to be close
  // to real-world conditions - that SyncMsgSender works from multiple threads.
  base::Thread ipc("ipc");
  ipc.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));

  StrictMock<MockChromeProxyDelegate> d1;
  TabsMap tab2delegate;
  SyncMsgSender queue(&tab2delegate);

  // Create some sync messages and their replies.
  AutomationMsg_InstallExtension m1(0, FilePath(L"c:\\awesome.x"), 0);
  AutomationMsg_CreateExternalTab m2(0, IPC::ExternalTabSettings(), 0, 0, 0);
  scoped_ptr<IPC::Message> r1(CreateReply(&m1,
      AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED));
  scoped_ptr<IPC::Message> r2(CreateReply(&m2, (HWND)1, (HWND)2, 6));

  queue.QueueSyncMessage(&m1, &d1, NULL);
  queue.QueueSyncMessage(&m2, &d1, NULL);

  testing::InSequence s;
  EXPECT_CALL(d1, Completed_InstallExtension(true,
      AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED, NULL));
  EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, 6));

  // Execute replies in a worker thread.
  ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
      &SyncMsgSender::OnReplyReceived, r1.get()));
  ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
      &SyncMsgSender::OnReplyReceived, r2.get()));
  ipc.Stop();

  // Expect that tab 6 has been associated with the delegate.
  EXPECT_EQ(&d1, tab2delegate[6]);
}

TEST(SyncMsgSender, OnChannelClosed) {
  // TODO(stoyan): implement.
}

<commit_msg>Fix the ChromeFrame Launch timeout test - mock destruction order. TBR=amit Review URL: http://codereview.chromium.org/3588010<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 <string>
#include "base/file_path.h"
#include "base/waitable_event.h"
#include "chrome_frame/cfproxy_private.h"
#include "chrome/test/automation/automation_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"

using testing::_;
using testing::DoAll;
using testing::NotNull;
using testing::Return;
using testing::StrictMock;
using testing::InvokeWithoutArgs;
using testing::WithoutArgs;
using testing::CreateFunctor;

// There is not much to test here since CFProxy is pretty dumb.
struct MockFactory : public ChromeProxyFactory {
  MOCK_METHOD0(CreateProxy, ChromeProxy*());
};

struct MockChromeProxyDelegate : public ChromeProxyDelegate {
  MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
  MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
  MOCK_METHOD0(Disconnected, void());
  MOCK_METHOD0(tab_handle, int());

  MOCK_METHOD4(Completed_CreateTab, void(bool success, HWND chrome_wnd,
      HWND tab_window, int tab_handle));
  MOCK_METHOD4(Completed_ConnectToTab, void(bool success, HWND chrome_window,
      HWND tab_window, int tab_handle));
  MOCK_METHOD2(Completed_Navigate, void(bool success,
      enum AutomationMsg_NavigationResponseValues res));
  MOCK_METHOD3(Completed_InstallExtension, void(bool success,
      enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
  MOCK_METHOD3(Completed_LoadExpandedExtension, void(bool success,
      enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
  MOCK_METHOD2(Completed_GetEnabledExtensions, void(bool success,
      const std::vector<FilePath>* v));

  // Network requests from Chrome.
  MOCK_METHOD2(Network_Start, void(int request_id,
      const IPC::AutomationURLRequest& request_info));
  MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
  MOCK_METHOD2(Network_End, void(int request_id, const URLRequestStatus& s));
  MOCK_METHOD1(Network_DownloadInHost, void(int request_id));
  MOCK_METHOD2(GetCookies, void(const GURL& url, int cookie_id));
  MOCK_METHOD2(SetCookie, void(const GURL& url, const std::string& cookie));

  // Navigation progress notifications.
  MOCK_METHOD2(NavigationStateChanged, void(int flags,
      const IPC::NavigationInfo& nav_info));
  MOCK_METHOD1(UpdateTargetUrl, void(const std::wstring& url));
  MOCK_METHOD2(NavigationFailed, void(int error_code, const GURL& gurl));
  MOCK_METHOD1(DidNavigate, void(const IPC::NavigationInfo& navigation_info));
  MOCK_METHOD1(TabLoaded, void(const GURL& url));

  //
  MOCK_METHOD3(OpenURL, void(const GURL& url_to_open, const GURL& referrer,
      int open_disposition));
  MOCK_METHOD1(GoToHistoryOffset, void(int offset));
  MOCK_METHOD3(MessageToHost, void(const std::string& message,
      const std::string& origin, const std::string& target));

  // Misc. UI.
  MOCK_METHOD1(HandleAccelerator, void(const MSG& accel_message));
  MOCK_METHOD1(TabbedOut, void(bool reverse));

  //
  MOCK_METHOD0(TabClosed, void());
  MOCK_METHOD1(AttachTab,
      void(const IPC::AttachExternalTabParams& attach_params));
};

struct MockSender : public IPC::Message::Sender {
  MOCK_METHOD1(Send, bool(IPC::Message* m));
};

struct MockCFProxyTraits : public CFProxyTraits {
  MOCK_METHOD2(DoCreateChannel, IPC::Message::Sender*(const std::string& id,
      IPC::Channel::Listener* l));
  MOCK_METHOD1(CloseChannel, void(IPC::Message::Sender* s));
  MOCK_METHOD1(LaunchApp, bool(const std::wstring& cmd_line));

  // Forward the CreateChannel to DoCreateChannel, but save the ipc_thread
  // and the listener (i.e. proxy implementation of Channel::Listener)
  virtual IPC::Message::Sender* CreateChannel(const std::string& id,
    IPC::Channel::Listener* l) {
      ipc_loop = MessageLoop::current();
      listener = l;
      return this->DoCreateChannel(id, l);
  }

  // Simulate some activity in the IPC thread.
  // You may find API_FIRE_XXXX macros (see below) handy instead.
  void FireConnect(base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnChannelConnected, 0), t.InMilliseconds());
  }

  void FireError(base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnChannelError), t.InMilliseconds());
  }

  void FireMessage(const IPC::Message& m, base::TimeDelta t) {
    ASSERT_TRUE(ipc_loop != NULL);
    ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
        &IPC::Channel::Listener::OnMessageReceived, m), t.InMilliseconds());
  }

  MockCFProxyTraits() : ipc_loop(NULL) {}
  MockSender sender;
 private:
  MessageLoop* ipc_loop;
  IPC::Channel::Listener* listener;
};

// Handy macros when we want so similate something on the IPC thread.
#define API_FIRE_CONNECT(api, t)  InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireConnect, t))
#define API_FIRE_ERROR(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireError, t))
#define API_FIRE_MESSAGE(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
                                       &MockCFProxyTraits::FireMessage, t))
DISABLE_RUNNABLE_METHOD_REFCOUNT(IPC::Channel::Listener);

TEST(ChromeProxy, DelegateAddRemove) {
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  StrictMock<MockFactory> factory;    // to be destroyed before other mocks
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate, Disconnected());

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(4);
  factory.GetProxy(&delegate, params);
  factory.ReleaseProxy(&delegate, params.profile);
}

// Not very useful test. Just for illustration. :)
TEST(ChromeProxy, SharedProxy) {
  base::WaitableEvent done1(false, false);
  base::WaitableEvent done2(false, false);
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate1;
  StrictMock<MockChromeProxyDelegate> delegate2;
  StrictMock<MockFactory> factory;
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
      API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(150)),
      Return(true)));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate1, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate2, tab_handle()).WillRepeatedly(Return(0));

  EXPECT_CALL(delegate1, Connected(proxy))
      .WillOnce(InvokeWithoutArgs(&done1, &base::WaitableEvent::Signal));
  EXPECT_CALL(delegate2, Connected(proxy))
      .WillOnce(InvokeWithoutArgs(&done2, &base::WaitableEvent::Signal));

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(4);

  factory.GetProxy(&delegate1, params);
  params.timeout = base::TimeDelta::FromSeconds(2);
  factory.GetProxy(&delegate2, params);

  EXPECT_TRUE(done1.TimedWait(base::TimeDelta::FromSeconds(1)));
  EXPECT_TRUE(done2.TimedWait(base::TimeDelta::FromSeconds(1)));

  EXPECT_CALL(delegate2, Disconnected());
  EXPECT_CALL(delegate1, Disconnected());

  factory.ReleaseProxy(&delegate2, params.profile);
  factory.ReleaseProxy(&delegate1, params.profile);
}

TEST(ChromeProxy, LaunchTimeout) {
  base::WaitableEvent done(true, false);
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  StrictMock<MockFactory> factory;
  CFProxy* proxy = new CFProxy(&api);

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
  EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
  EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
  EXPECT_CALL(api, CloseChannel(&api.sender));

  EXPECT_CALL(delegate, PeerLost(_,
                      ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT))
      .WillOnce(InvokeWithoutArgs(&done, &base::WaitableEvent::Signal));
  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromMilliseconds(300);
  factory.GetProxy(&delegate, params);
  EXPECT_TRUE(done.TimedWait(base::TimeDelta::FromSeconds(1)));

  EXPECT_CALL(delegate, Disconnected());
  factory.ReleaseProxy(&delegate, params.profile);
}

TEST(ChromeProxy, LaunchChrome) {
  base::WaitableEvent connected(false, false);
  StrictMock<MockChromeProxyDelegate> delegate;
  ChromeProxyFactory factory;

  ProxyParams params;
  params.profile = "Adam N. Epilinter";
  params.timeout = base::TimeDelta::FromSeconds(10);

  EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
  EXPECT_CALL(delegate, Connected(NotNull()))
    .WillOnce(InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal));

  factory.GetProxy(&delegate, params);
  EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));

  EXPECT_CALL(delegate, Disconnected());
  factory.ReleaseProxy(&delegate, params.profile);
}

///////////////////////////////////////////////////////////////////////////////
namespace {
template <typename M, typename A>
inline IPC::Message* CreateReply(M* m, const A& a) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a);
  }
  return r;
}

template <typename M, typename A, typename B>
inline IPC::Message* CreateReply(M* m, const A& a, const B& b) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a, b);
  }
  return r;
}

template <typename M, typename A, typename B, typename C>
inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c) {
  IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
  if (r) {
    M::WriteReplyParams(r, a, b, c);
  }
  return r;
}
}  // namespace

DISABLE_RUNNABLE_METHOD_REFCOUNT(SyncMsgSender);
TEST(SyncMsgSender, Deserialize) {
  // Note the ipc thread is not actually needed, but we try to be close
  // to real-world conditions - that SyncMsgSender works from multiple threads.
  base::Thread ipc("ipc");
  ipc.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));

  StrictMock<MockChromeProxyDelegate> d1;
  TabsMap tab2delegate;
  SyncMsgSender queue(&tab2delegate);

  // Create some sync messages and their replies.
  AutomationMsg_InstallExtension m1(0, FilePath(L"c:\\awesome.x"), 0);
  AutomationMsg_CreateExternalTab m2(0, IPC::ExternalTabSettings(), 0, 0, 0);
  scoped_ptr<IPC::Message> r1(CreateReply(&m1,
      AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED));
  scoped_ptr<IPC::Message> r2(CreateReply(&m2, (HWND)1, (HWND)2, 6));

  queue.QueueSyncMessage(&m1, &d1, NULL);
  queue.QueueSyncMessage(&m2, &d1, NULL);

  testing::InSequence s;
  EXPECT_CALL(d1, Completed_InstallExtension(true,
      AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED, NULL));
  EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, 6));

  // Execute replies in a worker thread.
  ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
      &SyncMsgSender::OnReplyReceived, r1.get()));
  ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
      &SyncMsgSender::OnReplyReceived, r2.get()));
  ipc.Stop();

  // Expect that tab 6 has been associated with the delegate.
  EXPECT_EQ(&d1, tab2delegate[6]);
}

TEST(SyncMsgSender, OnChannelClosed) {
  // TODO(stoyan): implement.
}

<|endoftext|>


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

#include "chrome_frame/module_utils.h"

#include <aclapi.h>
#include <atlbase.h>
#include <atlsecurity.h>
#include <sddl.h>

#include "base/file_path.h"
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/shared_memory.h"
#include "base/sys_info.h"
#include "base/utf_string_conversions.h"
#include "base/version.h"
#include "chrome_frame/utils.h"

const wchar_t kSharedMemoryName[] = L"ChromeFrameVersionBeacon_";
const uint32 kSharedMemorySize = 128;
const uint32 kSharedMemoryLockTimeoutMs = 1000;

// static
DllRedirector::DllRedirector() : first_module_handle_(NULL) {
  // TODO(robertshield): Allow for overrides to be taken from the environment.
  std::wstring beacon_name(kSharedMemoryName);
  beacon_name += GetHostProcessName(false);
  shared_memory_.reset(new base::SharedMemory(beacon_name));
}

DllRedirector::DllRedirector(const char* shared_memory_name)
    : shared_memory_name_(shared_memory_name), first_module_handle_(NULL) {
  shared_memory_.reset(new base::SharedMemory(ASCIIToWide(shared_memory_name)));
}

DllRedirector::~DllRedirector() {
  if (first_module_handle_) {
    if (first_module_handle_ != reinterpret_cast<HMODULE>(&__ImageBase)) {
      FreeLibrary(first_module_handle_);
    }
    first_module_handle_ = NULL;
  }
  UnregisterAsFirstCFModule();
}

bool DllRedirector::BuildSecurityAttributesForLock(
    CSecurityAttributes* sec_attr) {
  DCHECK(sec_attr);
  int32 major_version, minor_version, fix_version;
  base::SysInfo::OperatingSystemVersionNumbers(&major_version,
                                               &minor_version,
                                               &fix_version);
  if (major_version < 6) {
    // Don't bother with changing ACLs on pre-vista.
    return false;
  }

  bool success = false;

  // Fill out the rest of the security descriptor from the process token.
  CAccessToken token;
  if (token.GetProcessToken(TOKEN_QUERY)) {
    CSecurityDesc security_desc;
    // Set the SACL from an SDDL string that allows access to low-integrity
    // processes. See http://msdn.microsoft.com/en-us/library/bb625958.aspx.
    if (security_desc.FromString(L"S:(ML;;NW;;;LW)")) {
      CSid sid_owner;
      if (token.GetOwner(&sid_owner)) {
        security_desc.SetOwner(sid_owner);
      } else {
        NOTREACHED() << "Could not get owner.";
      }
      CSid sid_group;
      if (token.GetPrimaryGroup(&sid_group)) {
        security_desc.SetGroup(sid_group);
      } else {
        NOTREACHED() << "Could not get group.";
      }
      CDacl dacl;
      if (token.GetDefaultDacl(&dacl)) {
        // Add an access control entry mask for the current user.
        // This is what grants this user access from lower integrity levels.
        CSid sid_user;
        if (token.GetUser(&sid_user)) {
          success = dacl.AddAllowedAce(sid_user, MUTEX_ALL_ACCESS);
          security_desc.SetDacl(dacl);
          sec_attr->Set(security_desc);
        }
      }
    }
  }

  return success;
}

bool DllRedirector::SetFileMappingToReadOnly(base::SharedMemoryHandle mapping) {
  bool success = false;

  CAccessToken token;
  if (token.GetProcessToken(TOKEN_QUERY)) {
    CSid sid_user;
    if (token.GetUser(&sid_user)) {
      CDacl dacl;
      dacl.AddAllowedAce(sid_user, STANDARD_RIGHTS_READ | FILE_MAP_READ);
      success = AtlSetDacl(mapping, SE_KERNEL_OBJECT, dacl);
    }
  }

  return success;
}

bool DllRedirector::RegisterAsFirstCFModule() {
  DCHECK(first_module_handle_ == NULL);

  // Build our own file version outside of the lock:
  scoped_ptr<Version> our_version(GetCurrentModuleVersion());

  // We sadly can't use the autolock here since we want to have a timeout.
  // Be careful not to return while holding the lock. Also, attempt to do as
  // little as possible while under this lock.

  bool lock_acquired = false;
  CSecurityAttributes sec_attr;
  if (BuildSecurityAttributesForLock(&sec_attr)) {
    lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, &sec_attr);
  } else {
    lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL);
  }

  if (!lock_acquired) {
    // We couldn't get the lock in a reasonable amount of time, so fall
    // back to loading our current version. We return true to indicate that the
    // caller should not attempt to delegate to an already loaded version.
    dll_version_.swap(our_version);
    first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
    return true;
  }

  bool created_beacon = true;
  bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(),
                                            false,  // open_existing
                                            kSharedMemorySize);

  if (result) {
    // We created the beacon, now we need to mutate the security attributes
    // on the shared memory to allow read-only access and let low-integrity
    // processes open it.
    bool acls_set = SetFileMappingToReadOnly(shared_memory_->handle());
    DCHECK(acls_set);
  } else {
    created_beacon = false;

    // We failed to create the shared memory segment, suggesting it may already
    // exist: try to create it read-only.
    result = shared_memory_->Open(shared_memory_name_.c_str(),
                                  true /* read_only */);
  }

  if (result) {
    // Map in the whole thing.
    result = shared_memory_->Map(0);
    DCHECK(shared_memory_->memory());

    if (result) {
      // Either write our own version number or read it in if it was already
      // present in the shared memory section.
      if (created_beacon) {
        dll_version_.swap(our_version);

        lstrcpynA(reinterpret_cast<char*>(shared_memory_->memory()),
                  dll_version_->GetString().c_str(),
                  std::min(kSharedMemorySize,
                           dll_version_->GetString().length() + 1));

        // Mark ourself as the first module in.
        first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
      } else {
        char buffer[kSharedMemorySize] = {0};
        memcpy(buffer, shared_memory_->memory(), kSharedMemorySize - 1);
        dll_version_.reset(Version::GetVersionFromString(buffer));

        if (!dll_version_.get() || dll_version_->Equals(*our_version.get())) {
          // If we either couldn't parse a valid version out of the shared
          // memory or we did parse a version and it is the same as our own,
          // then pretend we're first in to avoid trying to load any other DLLs.
          dll_version_.reset(our_version.release());
          first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
          created_beacon = true;
        }
      }
    } else {
      NOTREACHED() << "Failed to map in version beacon.";
    }
  } else {
    NOTREACHED() << "Could not create file mapping for version beacon, gle: "
                 << ::GetLastError();
  }

  // Matching Unlock.
  shared_memory_->Unlock();

  return created_beacon;
}

void DllRedirector::UnregisterAsFirstCFModule() {
  if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) {
    bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL);
    if (lock_acquired) {
      // Free our handles. The last closed handle SHOULD result in it being
      // deleted.
      shared_memory_->Close();
      shared_memory_->Unlock();
    }
  }
}

LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() {
  HMODULE first_module_handle = GetFirstModule();

  LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>(
      GetProcAddress(first_module_handle, "DllGetClassObject"));
  if (!proc_ptr) {
    DPLOG(ERROR) << "DllRedirector: Could not get address of DllGetClassObject "
                    "from first loaded module.";
    // Oh boink, the first module we loaded was somehow bogus, make ourselves
    // the first module again.
    first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase);
  }
  return proc_ptr;
}

Version* DllRedirector::GetCurrentModuleVersion() {
  scoped_ptr<FileVersionInfo> file_version_info(
      FileVersionInfo::CreateFileVersionInfoForCurrentModule());
  DCHECK(file_version_info.get());

  Version* current_version = NULL;
  if (file_version_info.get()) {
     current_version = Version::GetVersionFromString(
        file_version_info->file_version());
    DCHECK(current_version);
  }

  return current_version;
}

HMODULE DllRedirector::GetFirstModule() {
  DCHECK(dll_version_.get())
      << "Error: Did you call RegisterAsFirstCFModule() first?";

  if (first_module_handle_ == NULL) {
    first_module_handle_ = LoadVersionedModule(dll_version_.get());
    if (!first_module_handle_) {
      first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
    }
  }

  return first_module_handle_;
}

HMODULE DllRedirector::LoadVersionedModule(Version* version) {
  DCHECK(version);

  FilePath module_path;
  PathService::Get(base::DIR_MODULE, &module_path);
  DCHECK(!module_path.empty());

  FilePath module_name = module_path.BaseName();
  module_path = module_path.DirName()
                           .Append(ASCIIToWide(version->GetString()))
                           .Append(module_name);

  HMODULE hmodule = LoadLibrary(module_path.value().c_str());
  if (hmodule == NULL) {
    DPLOG(ERROR) << "Could not load reported module version "
                 << version->GetString();
  }

  return hmodule;
}

<commit_msg>Remove a DCHECK when failing to secure the shared memory used to hold the current version. This may well fail on older (read non-NTFS) systems since you can't secure file mappings without a securable file system underneath.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome_frame/module_utils.h"

#include <aclapi.h>
#include <atlbase.h>
#include <atlsecurity.h>
#include <sddl.h>

#include "base/file_path.h"
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/shared_memory.h"
#include "base/sys_info.h"
#include "base/utf_string_conversions.h"
#include "base/version.h"
#include "chrome_frame/utils.h"

const wchar_t kSharedMemoryName[] = L"ChromeFrameVersionBeacon_";
const uint32 kSharedMemorySize = 128;
const uint32 kSharedMemoryLockTimeoutMs = 1000;

// static
DllRedirector::DllRedirector() : first_module_handle_(NULL) {
  // TODO(robertshield): Allow for overrides to be taken from the environment.
  std::wstring beacon_name(kSharedMemoryName);
  beacon_name += GetHostProcessName(false);
  shared_memory_.reset(new base::SharedMemory(beacon_name));
}

DllRedirector::DllRedirector(const char* shared_memory_name)
    : shared_memory_name_(shared_memory_name), first_module_handle_(NULL) {
  shared_memory_.reset(new base::SharedMemory(ASCIIToWide(shared_memory_name)));
}

DllRedirector::~DllRedirector() {
  if (first_module_handle_) {
    if (first_module_handle_ != reinterpret_cast<HMODULE>(&__ImageBase)) {
      FreeLibrary(first_module_handle_);
    }
    first_module_handle_ = NULL;
  }
  UnregisterAsFirstCFModule();
}

bool DllRedirector::BuildSecurityAttributesForLock(
    CSecurityAttributes* sec_attr) {
  DCHECK(sec_attr);
  int32 major_version, minor_version, fix_version;
  base::SysInfo::OperatingSystemVersionNumbers(&major_version,
                                               &minor_version,
                                               &fix_version);
  if (major_version < 6) {
    // Don't bother with changing ACLs on pre-vista.
    return false;
  }

  bool success = false;

  // Fill out the rest of the security descriptor from the process token.
  CAccessToken token;
  if (token.GetProcessToken(TOKEN_QUERY)) {
    CSecurityDesc security_desc;
    // Set the SACL from an SDDL string that allows access to low-integrity
    // processes. See http://msdn.microsoft.com/en-us/library/bb625958.aspx.
    if (security_desc.FromString(L"S:(ML;;NW;;;LW)")) {
      CSid sid_owner;
      if (token.GetOwner(&sid_owner)) {
        security_desc.SetOwner(sid_owner);
      } else {
        NOTREACHED() << "Could not get owner.";
      }
      CSid sid_group;
      if (token.GetPrimaryGroup(&sid_group)) {
        security_desc.SetGroup(sid_group);
      } else {
        NOTREACHED() << "Could not get group.";
      }
      CDacl dacl;
      if (token.GetDefaultDacl(&dacl)) {
        // Add an access control entry mask for the current user.
        // This is what grants this user access from lower integrity levels.
        CSid sid_user;
        if (token.GetUser(&sid_user)) {
          success = dacl.AddAllowedAce(sid_user, MUTEX_ALL_ACCESS);
          security_desc.SetDacl(dacl);
          sec_attr->Set(security_desc);
        }
      }
    }
  }

  return success;
}

bool DllRedirector::SetFileMappingToReadOnly(base::SharedMemoryHandle mapping) {
  bool success = false;

  CAccessToken token;
  if (token.GetProcessToken(TOKEN_QUERY)) {
    CSid sid_user;
    if (token.GetUser(&sid_user)) {
      CDacl dacl;
      dacl.AddAllowedAce(sid_user, STANDARD_RIGHTS_READ | FILE_MAP_READ);
      success = AtlSetDacl(mapping, SE_KERNEL_OBJECT, dacl);
    }
  }

  return success;
}

bool DllRedirector::RegisterAsFirstCFModule() {
  DCHECK(first_module_handle_ == NULL);

  // Build our own file version outside of the lock:
  scoped_ptr<Version> our_version(GetCurrentModuleVersion());

  // We sadly can't use the autolock here since we want to have a timeout.
  // Be careful not to return while holding the lock. Also, attempt to do as
  // little as possible while under this lock.

  bool lock_acquired = false;
  CSecurityAttributes sec_attr;
  if (BuildSecurityAttributesForLock(&sec_attr)) {
    lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, &sec_attr);
  } else {
    lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL);
  }

  if (!lock_acquired) {
    // We couldn't get the lock in a reasonable amount of time, so fall
    // back to loading our current version. We return true to indicate that the
    // caller should not attempt to delegate to an already loaded version.
    dll_version_.swap(our_version);
    first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
    return true;
  }

  bool created_beacon = true;
  bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(),
                                            false,  // open_existing
                                            kSharedMemorySize);

  if (result) {
    // We created the beacon, now we need to mutate the security attributes
    // on the shared memory to allow read-only access and let low-integrity
    // processes open it. This will fail on FAT32 file systems.
    if (!SetFileMappingToReadOnly(shared_memory_->handle())) {
      DLOG(ERROR) << "Failed to set file mapping permissions.";
    }
  } else {
    created_beacon = false;

    // We failed to create the shared memory segment, suggesting it may already
    // exist: try to create it read-only.
    result = shared_memory_->Open(shared_memory_name_.c_str(),
                                  true /* read_only */);
  }

  if (result) {
    // Map in the whole thing.
    result = shared_memory_->Map(0);
    DCHECK(shared_memory_->memory());

    if (result) {
      // Either write our own version number or read it in if it was already
      // present in the shared memory section.
      if (created_beacon) {
        dll_version_.swap(our_version);

        lstrcpynA(reinterpret_cast<char*>(shared_memory_->memory()),
                  dll_version_->GetString().c_str(),
                  std::min(kSharedMemorySize,
                           dll_version_->GetString().length() + 1));

        // Mark ourself as the first module in.
        first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
      } else {
        char buffer[kSharedMemorySize] = {0};
        memcpy(buffer, shared_memory_->memory(), kSharedMemorySize - 1);
        dll_version_.reset(Version::GetVersionFromString(buffer));

        if (!dll_version_.get() || dll_version_->Equals(*our_version.get())) {
          // If we either couldn't parse a valid version out of the shared
          // memory or we did parse a version and it is the same as our own,
          // then pretend we're first in to avoid trying to load any other DLLs.
          dll_version_.reset(our_version.release());
          first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
          created_beacon = true;
        }
      }
    } else {
      NOTREACHED() << "Failed to map in version beacon.";
    }
  } else {
    NOTREACHED() << "Could not create file mapping for version beacon, gle: "
                 << ::GetLastError();
  }

  // Matching Unlock.
  shared_memory_->Unlock();

  return created_beacon;
}

void DllRedirector::UnregisterAsFirstCFModule() {
  if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) {
    bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL);
    if (lock_acquired) {
      // Free our handles. The last closed handle SHOULD result in it being
      // deleted.
      shared_memory_->Close();
      shared_memory_->Unlock();
    }
  }
}

LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() {
  HMODULE first_module_handle = GetFirstModule();

  LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>(
      GetProcAddress(first_module_handle, "DllGetClassObject"));
  if (!proc_ptr) {
    DPLOG(ERROR) << "DllRedirector: Could not get address of DllGetClassObject "
                    "from first loaded module.";
    // Oh boink, the first module we loaded was somehow bogus, make ourselves
    // the first module again.
    first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase);
  }
  return proc_ptr;
}

Version* DllRedirector::GetCurrentModuleVersion() {
  scoped_ptr<FileVersionInfo> file_version_info(
      FileVersionInfo::CreateFileVersionInfoForCurrentModule());
  DCHECK(file_version_info.get());

  Version* current_version = NULL;
  if (file_version_info.get()) {
     current_version = Version::GetVersionFromString(
        file_version_info->file_version());
    DCHECK(current_version);
  }

  return current_version;
}

HMODULE DllRedirector::GetFirstModule() {
  DCHECK(dll_version_.get())
      << "Error: Did you call RegisterAsFirstCFModule() first?";

  if (first_module_handle_ == NULL) {
    first_module_handle_ = LoadVersionedModule(dll_version_.get());
    if (!first_module_handle_) {
      first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase);
    }
  }

  return first_module_handle_;
}

HMODULE DllRedirector::LoadVersionedModule(Version* version) {
  DCHECK(version);

  FilePath module_path;
  PathService::Get(base::DIR_MODULE, &module_path);
  DCHECK(!module_path.empty());

  FilePath module_name = module_path.BaseName();
  module_path = module_path.DirName()
                           .Append(ASCIIToWide(version->GetString()))
                           .Append(module_name);

  HMODULE hmodule = LoadLibrary(module_path.value().c_str());
  if (hmodule == NULL) {
    DPLOG(ERROR) << "Could not load reported module version "
                 << version->GetString();
  }

  return hmodule;
}

<|endoftext|>


<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 "ui/webui/web_ui_util.h"

#include <vector>

#include "base/base64.h"
#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_number_conversions.h"
#include "grit/app_locale_settings.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif

namespace webui {

std::string GetBitmapDataUrl(const SkBitmap& bitmap) {
  TRACE_EVENT2("oobe", "GetImageDataUrl",
               "width", bitmap.width(), "height", bitmap.height());
  std::vector<unsigned char> output;
  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
  std::string str_url;
  str_url.insert(str_url.end(), output.begin(), output.end());

  base::Base64Encode(str_url, &str_url);
  str_url.insert(0, "data:image/png;base64,");
  return str_url;
}

std::string GetBitmapDataUrlFromResource(int res) {
  // Load resource icon and covert to base64 encoded data url
  base::RefCountedStaticMemory* icon_data =
      ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
          res, ui::SCALE_FACTOR_100P);
  if (!icon_data)
    return std::string();
  scoped_refptr<base::RefCountedMemory> raw_icon(icon_data);
  std::string str_url;
  str_url.insert(str_url.end(),
    raw_icon->front(),
    raw_icon->front() + raw_icon->size());
  base::Base64Encode(str_url, &str_url);
  str_url.insert(0, "data:image/png;base64,");
  return str_url;
}

WindowOpenDisposition GetDispositionFromClick(const base::ListValue* args,
                                              int start_index) {
  double button = 0.0;
  bool alt_key = false;
  bool ctrl_key = false;
  bool meta_key = false;
  bool shift_key = false;

  CHECK(args->GetDouble(start_index++, &button));
  CHECK(args->GetBoolean(start_index++, &alt_key));
  CHECK(args->GetBoolean(start_index++, &ctrl_key));
  CHECK(args->GetBoolean(start_index++, &meta_key));
  CHECK(args->GetBoolean(start_index++, &shift_key));
  return ui::DispositionFromClick(
      button == 1.0, alt_key, ctrl_key, meta_key, shift_key);
}

bool ParseScaleFactor(const base::StringPiece& identifier,
                      ui::ScaleFactor* scale_factor) {
  *scale_factor = ui::SCALE_FACTOR_100P;
  if (identifier.empty()) {
    LOG(ERROR) << "Invalid scale factor format: " << identifier;
    return false;
  }

  if (*identifier.rbegin() != 'x') {
    LOG(ERROR) << "Invalid scale factor format: " << identifier;
    return false;
  }

  double scale = 0;
  std::string stripped;
  identifier.substr(0, identifier.length() - 1).CopyToString(&stripped);
  if (!base::StringToDouble(stripped, &scale)) {
    LOG(ERROR) << "Invalid scale factor format: " << identifier;
    return false;
  }

  *scale_factor = ui::GetScaleFactorFromScale(static_cast<float>(scale));
  return true;
}

void ParsePathAndScale(const GURL& url,
                       std::string* path,
                       ui::ScaleFactor* scale_factor) {
  *path = net::UnescapeURLComponent(url.path().substr(1),
                                    (net::UnescapeRule::URL_SPECIAL_CHARS |
                                     net::UnescapeRule::SPACES));
  if (scale_factor)
    *scale_factor = ui::SCALE_FACTOR_100P;

  // Detect and parse resource string ending in @<scale>x.
  std::size_t pos = path->rfind('@');
  if (pos != std::string::npos) {
    base::StringPiece stripped_path(*path);
    ui::ScaleFactor factor;

    if (ParseScaleFactor(stripped_path.substr(
            pos + 1, stripped_path.length() - pos - 1), &factor)) {
      // Strip scale factor specification from path.
      stripped_path.remove_suffix(stripped_path.length() - pos);
      stripped_path.CopyToString(path);
    }
    if (scale_factor)
      *scale_factor = factor;
  }
}

// static
void SetFontAndTextDirection(base::DictionaryValue* localized_strings) {
  int web_font_family_id = IDS_WEB_FONT_FAMILY;
  int web_font_size_id = IDS_WEB_FONT_SIZE;
#if defined(OS_WIN)
  // Vary font settings for Windows XP.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    web_font_family_id = IDS_WEB_FONT_FAMILY_XP;
    web_font_size_id = IDS_WEB_FONT_SIZE_XP;
  }
#endif

  std::string font_family = l10n_util::GetStringUTF8(web_font_family_id);

#if defined(TOOLKIT_GTK)
  // Use the system font on Linux/GTK. Keep the hard-coded font families as
  // backup in case for some crazy reason this one isn't available.
  font_family = ui::ResourceBundle::GetSharedInstance().GetFont(
      ui::ResourceBundle::BaseFont).GetFontName() + ", " + font_family;
#endif

  localized_strings->SetString("fontfamily", font_family);
  localized_strings->SetString("fontsize",
      l10n_util::GetStringUTF8(web_font_size_id));
  localized_strings->SetString("textdirection",
      base::i18n::IsRTL() ? "rtl" : "ltr");
}

}  // namespace webui
<commit_msg>Downgrade ERROR to WARNING for invalid scale factor formats in ParseScaleFactor<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 "ui/webui/web_ui_util.h"

#include <vector>

#include "base/base64.h"
#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_number_conversions.h"
#include "grit/app_locale_settings.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif

namespace webui {

std::string GetBitmapDataUrl(const SkBitmap& bitmap) {
  TRACE_EVENT2("oobe", "GetImageDataUrl",
               "width", bitmap.width(), "height", bitmap.height());
  std::vector<unsigned char> output;
  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
  std::string str_url;
  str_url.insert(str_url.end(), output.begin(), output.end());

  base::Base64Encode(str_url, &str_url);
  str_url.insert(0, "data:image/png;base64,");
  return str_url;
}

std::string GetBitmapDataUrlFromResource(int res) {
  // Load resource icon and covert to base64 encoded data url
  base::RefCountedStaticMemory* icon_data =
      ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
          res, ui::SCALE_FACTOR_100P);
  if (!icon_data)
    return std::string();
  scoped_refptr<base::RefCountedMemory> raw_icon(icon_data);
  std::string str_url;
  str_url.insert(str_url.end(),
    raw_icon->front(),
    raw_icon->front() + raw_icon->size());
  base::Base64Encode(str_url, &str_url);
  str_url.insert(0, "data:image/png;base64,");
  return str_url;
}

WindowOpenDisposition GetDispositionFromClick(const base::ListValue* args,
                                              int start_index) {
  double button = 0.0;
  bool alt_key = false;
  bool ctrl_key = false;
  bool meta_key = false;
  bool shift_key = false;

  CHECK(args->GetDouble(start_index++, &button));
  CHECK(args->GetBoolean(start_index++, &alt_key));
  CHECK(args->GetBoolean(start_index++, &ctrl_key));
  CHECK(args->GetBoolean(start_index++, &meta_key));
  CHECK(args->GetBoolean(start_index++, &shift_key));
  return ui::DispositionFromClick(
      button == 1.0, alt_key, ctrl_key, meta_key, shift_key);
}

bool ParseScaleFactor(const base::StringPiece& identifier,
                      ui::ScaleFactor* scale_factor) {
  *scale_factor = ui::SCALE_FACTOR_100P;
  if (identifier.empty()) {
    LOG(WARNING) << "Invalid scale factor format: " << identifier;
    return false;
  }

  if (*identifier.rbegin() != 'x') {
    LOG(WARNING) << "Invalid scale factor format: " << identifier;
    return false;
  }

  double scale = 0;
  std::string stripped;
  identifier.substr(0, identifier.length() - 1).CopyToString(&stripped);
  if (!base::StringToDouble(stripped, &scale)) {
    LOG(WARNING) << "Invalid scale factor format: " << identifier;
    return false;
  }

  *scale_factor = ui::GetScaleFactorFromScale(static_cast<float>(scale));
  return true;
}

void ParsePathAndScale(const GURL& url,
                       std::string* path,
                       ui::ScaleFactor* scale_factor) {
  *path = net::UnescapeURLComponent(url.path().substr(1),
                                    (net::UnescapeRule::URL_SPECIAL_CHARS |
                                     net::UnescapeRule::SPACES));
  if (scale_factor)
    *scale_factor = ui::SCALE_FACTOR_100P;

  // Detect and parse resource string ending in @<scale>x.
  std::size_t pos = path->rfind('@');
  if (pos != std::string::npos) {
    base::StringPiece stripped_path(*path);
    ui::ScaleFactor factor;

    if (ParseScaleFactor(stripped_path.substr(
            pos + 1, stripped_path.length() - pos - 1), &factor)) {
      // Strip scale factor specification from path.
      stripped_path.remove_suffix(stripped_path.length() - pos);
      stripped_path.CopyToString(path);
    }
    if (scale_factor)
      *scale_factor = factor;
  }
}

// static
void SetFontAndTextDirection(base::DictionaryValue* localized_strings) {
  int web_font_family_id = IDS_WEB_FONT_FAMILY;
  int web_font_size_id = IDS_WEB_FONT_SIZE;
#if defined(OS_WIN)
  // Vary font settings for Windows XP.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    web_font_family_id = IDS_WEB_FONT_FAMILY_XP;
    web_font_size_id = IDS_WEB_FONT_SIZE_XP;
  }
#endif

  std::string font_family = l10n_util::GetStringUTF8(web_font_family_id);

#if defined(TOOLKIT_GTK)
  // Use the system font on Linux/GTK. Keep the hard-coded font families as
  // backup in case for some crazy reason this one isn't available.
  font_family = ui::ResourceBundle::GetSharedInstance().GetFont(
      ui::ResourceBundle::BaseFont).GetFontName() + ", " + font_family;
#endif

  localized_strings->SetString("fontfamily", font_family);
  localized_strings->SetString("fontsize",
      l10n_util::GetStringUTF8(web_font_size_id));
  localized_strings->SetString("textdirection",
      base::i18n::IsRTL() ? "rtl" : "ltr");
}

}  // namespace webui
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkDataSetTriangleFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDataSetTriangleFilter.h"

#include <assert.h>
#include "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkGenericCell.h"
#include "vtkIdList.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPointData.h"
#include "vtkStructuredGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkUnstructuredGrid.h"
#include "vtkRectilinearGrid.h"
#include "vtkUnsignedCharArray.h"

vtkStandardNewMacro(vtkDataSetTriangleFilter);

vtkDataSetTriangleFilter::vtkDataSetTriangleFilter()
{
  this->Triangulator = vtkOrderedTriangulator::New();
  this->Triangulator->PreSortedOff();
  this->Triangulator->UseTemplatesOn();
  this->TetrahedraOnly = 0;
}

vtkDataSetTriangleFilter::~vtkDataSetTriangleFilter()
{
  this->Triangulator->Delete();
  this->Triangulator = NULL;
}

int vtkDataSetTriangleFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input->IsA("vtkStructuredPoints") ||
      input->IsA("vtkStructuredGrid") ||
      input->IsA("vtkImageData") ||
      input->IsA("vtkRectilinearGrid"))
    {
    this->StructuredExecute(input, output);
    }
  else
    {
    this->UnstructuredExecute(input, output);
    }

  vtkDebugMacro(<<"Produced " << this->GetOutput()->GetNumberOfCells() << " cells");

  return 1;
}

void vtkDataSetTriangleFilter::StructuredExecute(vtkDataSet *input,
                                                 vtkUnstructuredGrid *output)
{
  int dimensions[3], i, j, k, l, m;
  vtkIdType newCellId, inId;
  vtkGenericCell *cell = vtkGenericCell::New();
  vtkCellData *inCD = input->GetCellData();
  vtkCellData *outCD = output->GetCellData();
  vtkPoints *cellPts = vtkPoints::New();
  vtkPoints *newPoints = vtkPoints::New();
  vtkIdList *cellPtIds = vtkIdList::New();
  int numSimplices, numPts, dim, type;
  vtkIdType pts[4], num;

  // Create an array of points. This does an explicit creation
  // of each point.
  num = input->GetNumberOfPoints();
  newPoints->SetNumberOfPoints(num);
  for (i = 0; i < num; ++i)
    {
    newPoints->SetPoint(i,input->GetPoint(i));
    }

  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  if (input->IsA("vtkStructuredPoints"))
    {
    static_cast<vtkStructuredPoints*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkStructuredGrid"))
    {
    static_cast<vtkStructuredGrid*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkImageData"))
    {
    static_cast<vtkImageData*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkRectilinearGrid"))
    {
    static_cast<vtkRectilinearGrid*>(input)->GetDimensions(dimensions);
    }
  else
    {
    assert(0);
    }
  dimensions[0] = dimensions[0] - 1;
  dimensions[1] = dimensions[1] - 1;
  dimensions[2] = dimensions[2] - 1;

  vtkIdType numSlices = ( dimensions[2] > 0 ? dimensions[2] : 1 );
  int abort=0;
  for (k = 0; k < numSlices && !abort; k++)
    {
    this->UpdateProgress(static_cast<double>(k) / numSlices);
    abort = this->GetAbortExecute();

    for (j = 0; j < dimensions[1]; j++)
      {
      for (i = 0; i < dimensions[0]; i++)
        {
        inId = i+(j+(k*dimensions[1]))*dimensions[0];
        input->GetCell(inId, cell);
        if ((i+j+k)%2 == 0)
          {
          cell->Triangulate(0, cellPtIds, cellPts);
          }
        else
          {
          cell->Triangulate(1, cellPtIds, cellPts);
          }

        dim = cell->GetCellDimension() + 1;

        numPts = cellPtIds->GetNumberOfIds();
        numSimplices = numPts / dim;
        type = 0;
        switch (dim)
          {
          case 1:
            type = VTK_VERTEX;    break;
          case 2:
            type = VTK_LINE;      break;
          case 3:
            type = VTK_TRIANGLE;  break;
          case 4:
            type = VTK_TETRA;     break;
          }
        if (!this->TetrahedraOnly || type == VTK_TETRA)
          {
          for (l = 0; l < numSimplices; l++ )
            {
            for (m = 0; m < dim; m++)
              {
              pts[m] = cellPtIds->GetId(dim*l+m);
              }
            // copy cell data
            newCellId = output->InsertNextCell(type, dim, pts);
            outCD->CopyData(inCD, inId, newCellId);
            }//for all simplices
          }
        }//i dimension
      }//j dimension
    }//k dimension

  // Update output
  output->SetPoints(newPoints);
  output->GetPointData()->PassData(input->GetPointData());
  output->Squeeze();

  cell->Delete();
  newPoints->Delete();
  cellPts->Delete();
  cellPtIds->Delete();
}

// 3D cells use the ordered triangulator. The ordered triangulator is used
// to create templates on the fly. Once the templates are created then they
// are used to produce the final triangulation.
//
void vtkDataSetTriangleFilter::UnstructuredExecute(vtkDataSet *dataSetInput,
                                                   vtkUnstructuredGrid *output)
{
  vtkPointSet *input = static_cast<vtkPointSet*>(dataSetInput); //has to be
  vtkIdType numCells = input->GetNumberOfCells();
  vtkGenericCell *cell;
  vtkIdType newCellId, j;
  int k;
  vtkCellData *inCD=input->GetCellData();
  vtkCellData *outCD=output->GetCellData();
  vtkPoints *cellPts;
  vtkIdList *cellPtIds;
  vtkIdType ptId, numTets, ncells;
  int numPts, type;
  int numSimplices, dim;
  vtkIdType pts[4];
  double x[3];

  if (numCells == 0)
    {
    return;
    }

  vtkUnstructuredGrid * inUgrid =
    vtkUnstructuredGrid::SafeDownCast(dataSetInput);
  if (inUgrid)
    {
    //avoid doing cell simplification if all cells are already simplices
    vtkUnsignedCharArray* cellTypes = inUgrid->GetCellTypesArray();
    if (cellTypes)
      {
      int allsimplices = 1;
      for (vtkIdType cellId = 0; cellId < cellTypes->GetSize() && allsimplices; cellId++)
        {
        switch (cellTypes->GetValue(cellId))
          {
          case VTK_TETRA:
            break;
          case VTK_VERTEX:
          case VTK_LINE:
          case VTK_TRIANGLE:
            if (this->TetrahedraOnly)
              {
              allsimplices = 0; //don't shallowcopy need to stip non tets
              }
            break;
          default:
            allsimplices = 0;
            break;
          }
        }
      if (allsimplices)
        {
        output->ShallowCopy(input);
        return;
        }
      }
    }

  cell = vtkGenericCell::New();
  cellPts = vtkPoints::New();
  cellPtIds = vtkIdList::New();

  // Create an array of points
  vtkCellData *tempCD = vtkCellData::New();
  tempCD->ShallowCopy(inCD);
  tempCD->SetActiveGlobalIds(NULL);

  outCD->CopyAllocate(tempCD, input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  // Points are passed through
  output->SetPoints(input->GetPoints());
  output->GetPointData()->PassData(input->GetPointData());

  int abort=0;
  vtkIdType updateTime = numCells/20 + 1;  // update roughly every 5%
  for (vtkIdType cellId=0; cellId < numCells && !abort; cellId++)
    {
    if ( !(cellId % updateTime) )
      {
      this->UpdateProgress(static_cast<double>(cellId) / numCells);
      abort = this->GetAbortExecute();
      }

    input->GetCell(cellId, cell);
    dim = cell->GetCellDimension();

    if (cell->GetCellType() == VTK_POLYHEDRON) //polyhedron
      {
      dim = 4;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = VTK_TETRA;

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(tempCD, cellId, newCellId);
        }
      }

    else if ( dim == 3 ) //use ordered triangulation
      {
      numPts = cell->GetNumberOfPoints();
      double *p, *pPtr=cell->GetParametricCoords();
      this->Triangulator->InitTriangulation(0.0,1.0, 0.0,1.0, 0.0,1.0, numPts);
      for (p=pPtr, j=0; j<numPts; j++, p+=3)
        {
        ptId = cell->PointIds->GetId(j);
        cell->Points->GetPoint(j, x);
        this->Triangulator->InsertPoint(ptId, x, p, 0);
        }//for all cell points
      if ( cell->IsPrimaryCell() ) //use templates if topology is fixed
        {
        int numEdges=cell->GetNumberOfEdges();
        this->Triangulator->TemplateTriangulate(cell->GetCellType(),
                                                numPts,numEdges);
        }
      else //use ordered triangulator
        {
        this->Triangulator->Triangulate();
        }

      ncells = output->GetNumberOfCells();
      numTets = this->Triangulator->AddTetras(0,output);

      for (j=0; j < numTets; j++)
        {
        outCD->CopyData(tempCD, cellId, ncells+j);
        }
      }

    else if (!this->TetrahedraOnly) //2D or lower dimension
      {
      dim++;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = 0;
      switch (dim)
        {
        case 1:
          type = VTK_VERTEX;    break;
        case 2:
          type = VTK_LINE;      break;
        case 3:
          type = VTK_TRIANGLE;  break;
        }

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(tempCD, cellId, newCellId);
        }
      } //if 2D or less cell
    } //for all cells

  // Update output
  output->Squeeze();

  tempCD->Delete();

  cellPts->Delete();
  cellPtIds->Delete();
  cell->Delete();
}

int vtkDataSetTriangleFilter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

void vtkDataSetTriangleFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "TetrahedraOnly: " << (this->TetrahedraOnly ? "On":"Off") << "\n";
}

<commit_msg>Replace unrecognized data set assert with a vtkErrorMacro.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataSetTriangleFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDataSetTriangleFilter.h"

#include "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkGenericCell.h"
#include "vtkIdList.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPointData.h"
#include "vtkStructuredGrid.h"
#include "vtkStructuredPoints.h"
#include "vtkUnstructuredGrid.h"
#include "vtkRectilinearGrid.h"
#include "vtkUnsignedCharArray.h"

vtkStandardNewMacro(vtkDataSetTriangleFilter);

vtkDataSetTriangleFilter::vtkDataSetTriangleFilter()
{
  this->Triangulator = vtkOrderedTriangulator::New();
  this->Triangulator->PreSortedOff();
  this->Triangulator->UseTemplatesOn();
  this->TetrahedraOnly = 0;
}

vtkDataSetTriangleFilter::~vtkDataSetTriangleFilter()
{
  this->Triangulator->Delete();
  this->Triangulator = NULL;
}

int vtkDataSetTriangleFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (input->IsA("vtkStructuredPoints") ||
      input->IsA("vtkStructuredGrid") ||
      input->IsA("vtkImageData") ||
      input->IsA("vtkRectilinearGrid"))
    {
    this->StructuredExecute(input, output);
    }
  else
    {
    this->UnstructuredExecute(input, output);
    }

  vtkDebugMacro(<<"Produced " << this->GetOutput()->GetNumberOfCells() << " cells");

  return 1;
}

void vtkDataSetTriangleFilter::StructuredExecute(vtkDataSet *input,
                                                 vtkUnstructuredGrid *output)
{
  int dimensions[3], i, j, k, l, m;
  vtkIdType newCellId, inId;
  vtkGenericCell *cell = vtkGenericCell::New();
  vtkCellData *inCD = input->GetCellData();
  vtkCellData *outCD = output->GetCellData();
  vtkPoints *cellPts = vtkPoints::New();
  vtkPoints *newPoints = vtkPoints::New();
  vtkIdList *cellPtIds = vtkIdList::New();
  int numSimplices, numPts, dim, type;
  vtkIdType pts[4], num;

  // Create an array of points. This does an explicit creation
  // of each point.
  num = input->GetNumberOfPoints();
  newPoints->SetNumberOfPoints(num);
  for (i = 0; i < num; ++i)
    {
    newPoints->SetPoint(i,input->GetPoint(i));
    }

  outCD->CopyAllocate(inCD,input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  if (input->IsA("vtkStructuredPoints"))
    {
    static_cast<vtkStructuredPoints*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkStructuredGrid"))
    {
    static_cast<vtkStructuredGrid*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkImageData"))
    {
    static_cast<vtkImageData*>(input)->GetDimensions(dimensions);
    }
  else if (input->IsA("vtkRectilinearGrid"))
    {
    static_cast<vtkRectilinearGrid*>(input)->GetDimensions(dimensions);
    }
  else
    {
    // Every kind of structured data is listed above, this should never happen.
    // Report an error and produce no output.
    vtkErrorMacro("Unrecognized data set " << input->GetClassName());
    // Dimensions of 1x1x1 means a single point, i.e. dimensionality of zero.
    dimensions[0] = 1;
    dimensions[1] = 1;
    dimensions[2] = 1;
    }

  dimensions[0] = dimensions[0] - 1;
  dimensions[1] = dimensions[1] - 1;
  dimensions[2] = dimensions[2] - 1;

  vtkIdType numSlices = ( dimensions[2] > 0 ? dimensions[2] : 1 );
  int abort=0;
  for (k = 0; k < numSlices && !abort; k++)
    {
    this->UpdateProgress(static_cast<double>(k) / numSlices);
    abort = this->GetAbortExecute();

    for (j = 0; j < dimensions[1]; j++)
      {
      for (i = 0; i < dimensions[0]; i++)
        {
        inId = i+(j+(k*dimensions[1]))*dimensions[0];
        input->GetCell(inId, cell);
        if ((i+j+k)%2 == 0)
          {
          cell->Triangulate(0, cellPtIds, cellPts);
          }
        else
          {
          cell->Triangulate(1, cellPtIds, cellPts);
          }

        dim = cell->GetCellDimension() + 1;

        numPts = cellPtIds->GetNumberOfIds();
        numSimplices = numPts / dim;
        type = 0;
        switch (dim)
          {
          case 1:
            type = VTK_VERTEX;    break;
          case 2:
            type = VTK_LINE;      break;
          case 3:
            type = VTK_TRIANGLE;  break;
          case 4:
            type = VTK_TETRA;     break;
          }
        if (!this->TetrahedraOnly || type == VTK_TETRA)
          {
          for (l = 0; l < numSimplices; l++ )
            {
            for (m = 0; m < dim; m++)
              {
              pts[m] = cellPtIds->GetId(dim*l+m);
              }
            // copy cell data
            newCellId = output->InsertNextCell(type, dim, pts);
            outCD->CopyData(inCD, inId, newCellId);
            }//for all simplices
          }
        }//i dimension
      }//j dimension
    }//k dimension

  // Update output
  output->SetPoints(newPoints);
  output->GetPointData()->PassData(input->GetPointData());
  output->Squeeze();

  cell->Delete();
  newPoints->Delete();
  cellPts->Delete();
  cellPtIds->Delete();
}

// 3D cells use the ordered triangulator. The ordered triangulator is used
// to create templates on the fly. Once the templates are created then they
// are used to produce the final triangulation.
//
void vtkDataSetTriangleFilter::UnstructuredExecute(vtkDataSet *dataSetInput,
                                                   vtkUnstructuredGrid *output)
{
  vtkPointSet *input = static_cast<vtkPointSet*>(dataSetInput); //has to be
  vtkIdType numCells = input->GetNumberOfCells();
  vtkGenericCell *cell;
  vtkIdType newCellId, j;
  int k;
  vtkCellData *inCD=input->GetCellData();
  vtkCellData *outCD=output->GetCellData();
  vtkPoints *cellPts;
  vtkIdList *cellPtIds;
  vtkIdType ptId, numTets, ncells;
  int numPts, type;
  int numSimplices, dim;
  vtkIdType pts[4];
  double x[3];

  if (numCells == 0)
    {
    return;
    }

  vtkUnstructuredGrid * inUgrid =
    vtkUnstructuredGrid::SafeDownCast(dataSetInput);
  if (inUgrid)
    {
    //avoid doing cell simplification if all cells are already simplices
    vtkUnsignedCharArray* cellTypes = inUgrid->GetCellTypesArray();
    if (cellTypes)
      {
      int allsimplices = 1;
      for (vtkIdType cellId = 0; cellId < cellTypes->GetSize() && allsimplices; cellId++)
        {
        switch (cellTypes->GetValue(cellId))
          {
          case VTK_TETRA:
            break;
          case VTK_VERTEX:
          case VTK_LINE:
          case VTK_TRIANGLE:
            if (this->TetrahedraOnly)
              {
              allsimplices = 0; //don't shallowcopy need to stip non tets
              }
            break;
          default:
            allsimplices = 0;
            break;
          }
        }
      if (allsimplices)
        {
        output->ShallowCopy(input);
        return;
        }
      }
    }

  cell = vtkGenericCell::New();
  cellPts = vtkPoints::New();
  cellPtIds = vtkIdList::New();

  // Create an array of points
  vtkCellData *tempCD = vtkCellData::New();
  tempCD->ShallowCopy(inCD);
  tempCD->SetActiveGlobalIds(NULL);

  outCD->CopyAllocate(tempCD, input->GetNumberOfCells()*5);
  output->Allocate(input->GetNumberOfCells()*5);

  // Points are passed through
  output->SetPoints(input->GetPoints());
  output->GetPointData()->PassData(input->GetPointData());

  int abort=0;
  vtkIdType updateTime = numCells/20 + 1;  // update roughly every 5%
  for (vtkIdType cellId=0; cellId < numCells && !abort; cellId++)
    {
    if ( !(cellId % updateTime) )
      {
      this->UpdateProgress(static_cast<double>(cellId) / numCells);
      abort = this->GetAbortExecute();
      }

    input->GetCell(cellId, cell);
    dim = cell->GetCellDimension();

    if (cell->GetCellType() == VTK_POLYHEDRON) //polyhedron
      {
      dim = 4;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = VTK_TETRA;

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(tempCD, cellId, newCellId);
        }
      }

    else if ( dim == 3 ) //use ordered triangulation
      {
      numPts = cell->GetNumberOfPoints();
      double *p, *pPtr=cell->GetParametricCoords();
      this->Triangulator->InitTriangulation(0.0,1.0, 0.0,1.0, 0.0,1.0, numPts);
      for (p=pPtr, j=0; j<numPts; j++, p+=3)
        {
        ptId = cell->PointIds->GetId(j);
        cell->Points->GetPoint(j, x);
        this->Triangulator->InsertPoint(ptId, x, p, 0);
        }//for all cell points
      if ( cell->IsPrimaryCell() ) //use templates if topology is fixed
        {
        int numEdges=cell->GetNumberOfEdges();
        this->Triangulator->TemplateTriangulate(cell->GetCellType(),
                                                numPts,numEdges);
        }
      else //use ordered triangulator
        {
        this->Triangulator->Triangulate();
        }

      ncells = output->GetNumberOfCells();
      numTets = this->Triangulator->AddTetras(0,output);

      for (j=0; j < numTets; j++)
        {
        outCD->CopyData(tempCD, cellId, ncells+j);
        }
      }

    else if (!this->TetrahedraOnly) //2D or lower dimension
      {
      dim++;
      cell->Triangulate(0, cellPtIds, cellPts);
      numPts = cellPtIds->GetNumberOfIds();

      numSimplices = numPts / dim;
      type = 0;
      switch (dim)
        {
        case 1:
          type = VTK_VERTEX;    break;
        case 2:
          type = VTK_LINE;      break;
        case 3:
          type = VTK_TRIANGLE;  break;
        }

      for ( j=0; j < numSimplices; j++ )
        {
        for (k=0; k<dim; k++)
          {
          pts[k] = cellPtIds->GetId(dim*j+k);
          }
        // copy cell data
        newCellId = output->InsertNextCell(type, dim, pts);
        outCD->CopyData(tempCD, cellId, newCellId);
        }
      } //if 2D or less cell
    } //for all cells

  // Update output
  output->Squeeze();

  tempCD->Delete();

  cellPts->Delete();
  cellPtIds->Delete();
  cell->Delete();
}

int vtkDataSetTriangleFilter::FillInputPortInformation(int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

void vtkDataSetTriangleFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "TetrahedraOnly: " << (this->TetrahedraOnly ? "On":"Off") << "\n";
}

<|endoftext|>


<commit_before>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#include <qi/log.hpp>
#include "src/messaging/master_client.hpp"
#include <qimessaging/serialization.hpp>
#include "src/messaging/network/master_endpoint.hpp"

namespace qi {
  namespace detail {

    using qi::transport::Buffer;
    using qi::Message;

    static const std::string methodUnregisterEndpoint("master.unregisterEndpoint::v:s");
    static const std::string methodRegisterTopic("master.registerTopic::v:sbs");
    static const std::string methodUnregisterTopic("master.unregisterTopic::v:ss");
    static const std::string methodGetNewPort("master.getNewPort::i:s");
    static const std::string methodRegisterMachine("master.registerMachine::v:sssi");
    static const std::string methodRegisterEndpoint("master.registerEndpoint::v:issssii");
    static const std::string methodTopicExists("master.topicExists::b:s");
    static const std::string methodLocateService("master.locateService::s:ss");
    static const std::string methodRegisterService("master.registerService::v:ss");
    static const std::string methodUnregisterService("master.unregisterService::v:s");
    static const std::string methodLocateTopic("master.locateTopic::s:ss");
    static const std::string methodRegisterTopicParticipant("master.registerTopicParticipant::v:ss");

    MasterClient::~MasterClient() {
    }

    MasterClient::MasterClient(qi::Context *ctx)
      : _isInitialized(false),
        _qiContextPtr( (ctx == NULL)? getDefaultQiContextPtr() : ctx),
        _transportClient(_qiContextPtr->getTransportContext())
    {
    }

    void MasterClient::connect(const std::string masterAddress) {
      _masterAddress = masterAddress;
      std::pair<std::string, int> masterEndpointAndPort;
      if (!qi::detail::validateMasterEndpoint(_masterAddress, masterEndpointAndPort)) {
        _isInitialized = false;
        qiLogError("qimessaging") << "Initialized with invalid master address: \""
            << _masterAddress << "\" All calls will fail." << std::endl;
        return;
      }
      _isInitialized = _transportClient.connect(masterEndpointAndPort.first);
      if (! _isInitialized ) {
        qiLogError("qimessaging") << "Could not connect to master "
            "at address \"" << masterEndpointAndPort.first << "\""
            << std::endl;
        return;
      }
    }

    bool MasterClient::isInitialized() const {
      return _isInitialized;
    }

    const std::string& MasterClient::getMasterAddress() const {
      return _masterAddress;
    }

    int MasterClient::getNewPort(const std::string& machineID) {
      if (!_isInitialized) {
        return 0;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodGetNewPort);
      msg.writeString(machineID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      int port;
      retSer.readInt(port);
      return port;
    }

    void MasterClient::registerMachine(const qi::detail::MachineContext& m) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodRegisterMachine);
      msg.writeString(m.hostName);
      msg.writeString(m.machineID);
      msg.writeString(m.publicIP);
      msg.writeInt(   m.platformID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::registerEndpoint(const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterEndpoint);
      msg.writeInt((int)e.type);
      msg.writeString(e.name);
      msg.writeString(e.endpointID);
      msg.writeString(e.contextID);
      msg.writeString(e.machineID);
      msg.writeInt(   e.processID);
      msg.writeInt(   e.port);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterEndpoint(const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodUnregisterEndpoint);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    std::string MasterClient::locateService(const std::string& methodSignature, const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return "";
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodLocateService);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      std::string endpoint;
      retSer.readString(endpoint);
      return endpoint;
    }

    void MasterClient::registerService(
        const std::string& methodSignature, const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterService);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterService(const std::string& methodSignature)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodUnregisterService);
      msg.writeString(methodSignature);
      _transportClient.send(msg.str(), ret);
    }

    std::string MasterClient::locateTopic(const std::string& methodSignature, const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return "";
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodLocateTopic);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      std::string endpoint;
      retSer.readString(endpoint);
      return endpoint;
    }

    bool MasterClient::topicExists(const std::string& signature)
    {
      if (!_isInitialized) {
        return false;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodTopicExists);
      msg.writeString(signature);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      bool exists;
      retSer.readBool(exists);
      return exists;
    }

    void MasterClient::registerTopic(
        const std::string& signature, const bool& isManyToMany,
        const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterTopic);
      msg.writeString(signature);
      msg.writeBool(isManyToMany);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::registerTopicParticipant(
      const std::string& signature,
      const std::string& endpointID)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterTopicParticipant);
      msg.writeString(signature);
      msg.writeString(endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterTopic(
      const std::string& signature,
      const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodUnregisterTopic);
      msg.writeString(signature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }
  }
}

<commit_msg>masterclient: signature have changed<commit_after>/*
*  Author(s):
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#include <qi/log.hpp>
#include "src/messaging/master_client.hpp"
#include <qimessaging/serialization.hpp>
#include "src/messaging/network/master_endpoint.hpp"

namespace qi {
  namespace detail {

    using qi::transport::Buffer;
    using qi::Message;

    static const std::string methodUnregisterEndpoint("master.unregisterEndpoint::v(s)");
    static const std::string methodRegisterTopic("master.registerTopic::v(sbs)");
    static const std::string methodUnregisterTopic("master.unregisterTopic::v(ss)");
    static const std::string methodGetNewPort("master.getNewPort::i(s)");
    static const std::string methodRegisterMachine("master.registerMachine::v(sssi)");
    static const std::string methodRegisterEndpoint("master.registerEndpoint::v(issssii)");
    static const std::string methodTopicExists("master.topicExists::b(s)");
    static const std::string methodLocateService("master.locateService::s(ss)");
    static const std::string methodRegisterService("master.registerService::v(ss)");
    static const std::string methodUnregisterService("master.unregisterService::v(s)");
    static const std::string methodLocateTopic("master.locateTopic::s(ss)");
    static const std::string methodRegisterTopicParticipant("master.registerTopicParticipant::v(ss)");

    MasterClient::~MasterClient() {
    }

    MasterClient::MasterClient(qi::Context *ctx)
      : _isInitialized(false),
        _qiContextPtr( (ctx == NULL)? getDefaultQiContextPtr() : ctx),
        _transportClient(_qiContextPtr->getTransportContext())
    {
    }

    void MasterClient::connect(const std::string masterAddress) {
      _masterAddress = masterAddress;
      std::pair<std::string, int> masterEndpointAndPort;
      if (!qi::detail::validateMasterEndpoint(_masterAddress, masterEndpointAndPort)) {
        _isInitialized = false;
        qiLogError("qimessaging") << "Initialized with invalid master address: \""
            << _masterAddress << "\" All calls will fail." << std::endl;
        return;
      }
      _isInitialized = _transportClient.connect(masterEndpointAndPort.first);
      if (! _isInitialized ) {
        qiLogError("qimessaging") << "Could not connect to master "
            "at address \"" << masterEndpointAndPort.first << "\""
            << std::endl;
        return;
      }
    }

    bool MasterClient::isInitialized() const {
      return _isInitialized;
    }

    const std::string& MasterClient::getMasterAddress() const {
      return _masterAddress;
    }

    int MasterClient::getNewPort(const std::string& machineID) {
      if (!_isInitialized) {
        return 0;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodGetNewPort);
      msg.writeString(machineID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      int port;
      retSer.readInt(port);
      return port;
    }

    void MasterClient::registerMachine(const qi::detail::MachineContext& m) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodRegisterMachine);
      msg.writeString(m.hostName);
      msg.writeString(m.machineID);
      msg.writeString(m.publicIP);
      msg.writeInt(   m.platformID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::registerEndpoint(const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterEndpoint);
      msg.writeInt((int)e.type);
      msg.writeString(e.name);
      msg.writeString(e.endpointID);
      msg.writeString(e.contextID);
      msg.writeString(e.machineID);
      msg.writeInt(   e.processID);
      msg.writeInt(   e.port);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterEndpoint(const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodUnregisterEndpoint);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    std::string MasterClient::locateService(const std::string& methodSignature, const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return "";
      }
      Buffer ret;
      Message msg;
      msg.writeString(methodLocateService);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      std::string endpoint;
      retSer.readString(endpoint);
      return endpoint;
    }

    void MasterClient::registerService(
        const std::string& methodSignature, const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterService);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterService(const std::string& methodSignature)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodUnregisterService);
      msg.writeString(methodSignature);
      _transportClient.send(msg.str(), ret);
    }

    std::string MasterClient::locateTopic(const std::string& methodSignature, const qi::detail::EndpointContext& e) {
      if (!_isInitialized) {
        return "";
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodLocateTopic);
      msg.writeString(methodSignature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      std::string endpoint;
      retSer.readString(endpoint);
      return endpoint;
    }

    bool MasterClient::topicExists(const std::string& signature)
    {
      if (!_isInitialized) {
        return false;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodTopicExists);
      msg.writeString(signature);
      _transportClient.send(msg.str(), ret);
      Message retSer(ret);
      bool exists;
      retSer.readBool(exists);
      return exists;
    }

    void MasterClient::registerTopic(
        const std::string& signature, const bool& isManyToMany,
        const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterTopic);
      msg.writeString(signature);
      msg.writeBool(isManyToMany);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::registerTopicParticipant(
      const std::string& signature,
      const std::string& endpointID)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodRegisterTopicParticipant);
      msg.writeString(signature);
      msg.writeString(endpointID);
      _transportClient.send(msg.str(), ret);
    }

    void MasterClient::unregisterTopic(
      const std::string& signature,
      const qi::detail::EndpointContext& e)
    {
      if (!_isInitialized) {
        return;
      }
      Buffer ret;
      Message msg;

      msg.writeString(methodUnregisterTopic);
      msg.writeString(signature);
      msg.writeString(e.endpointID);
      _transportClient.send(msg.str(), ret);
    }
  }
}

<|endoftext|>