<commit_before>/*  Copyright 2020 Google Inc.

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

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

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

#include <vector>
#include <aconf.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <png.h>

#include "gmem.h"
#include "gmempp.h"
#include "parseargs.h"
#include "GString.h"
#include "gfile.h"
#include "GlobalParams.h"
#include "Object.h"
#include "PDFDoc.h"
#include "SplashBitmap.h"
#include "Splash.h"
#include "SplashOutputDev.h"
#include "Stream.h"
#include "config.h"
#include "JBIG2Stream.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
    FuzzedDataProvider fdp (data, size);
    double hdpi = fdp.ConsumeFloatingPoint<double>();
    double vdpi = fdp.ConsumeFloatingPoint<double>();
    int rotate = fdp.ConsumeIntegral<int>();
    bool useMediaBox = fdp.ConsumeBool();
    bool crop = fdp.ConsumeBool();
    bool printing = fdp.ConsumeBool();
    std::vector<char> payload = fdp.ConsumeRemainingBytes<char>();

    Object xpdf_obj;
    xpdf_obj.initNull();
    BaseStream *stream = new MemStream(payload.data(), 0, payload.size(), &xpdf_obj);

    Object info, xfa;
    Object *acroForm;
    globalParams = new GlobalParams(NULL);
    globalParams->setErrQuiet(1);
    globalParams->setupBaseFonts(NULL);
    char yes[] = "yes";
    globalParams->setEnableFreeType(yes);  // Yes, it's a string and not a bool.
    globalParams->setErrQuiet(1);

    PDFDoc *doc = NULL;
    try {
      PDFDoc doc(stream);
        if (doc.isOk() == gTrue)
        {
            doc.getNumPages();
            doc.getOutline();
            doc.getStructTreeRoot();
            doc.getXRef();
            doc.okToPrint(gTrue);
            doc.okToCopy(gTrue);
            doc.okToChange(gTrue);
            doc.okToAddNotes(gTrue);
            doc.isLinearized();
            doc.getPDFVersion();

            GString *metadata;
            if ((metadata = doc.readMetadata())) {
              (void)metadata->getCString();
            }
            delete metadata;

            Object info;
            doc.getDocInfo(&info);
            if (info.isDict()) {
              info.getDict();
            }
            info.free();

            if ((acroForm = doc.getCatalog()->getAcroForm())->isDict()) {
                acroForm->dictLookup("XFA", &xfa);
                xfa.free();
            }

            for (size_t i = 0; i < doc.getNumPages(); i++) {
              doc.getLinks(i);
              auto page = doc.getCatalog()->getPage(i);
              if (!page->isOk()) {
                continue;
              }
              page->getResourceDict();
              page->getMetadata();
              page->getResourceDict();
            }

            SplashColor paperColor = {0xff, 0xff, 0xff};
            SplashOutputDev *splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor);
            splashOut->setNoComposite(gTrue);
            splashOut->startDoc(doc.getXRef());
            for (size_t i = 0; i <= doc.getNumPages(); ++i) {
              doc.displayPage(splashOut, i, hdpi, vdpi, rotate, useMediaBox, crop, printing);
            }
            (void)splashOut->getBitmap();

            delete splashOut;

            Object globals;
            BaseStream *base_str = doc.getBaseStream();
            if (base_str) {
              JBIG2Stream *str = new JBIG2Stream(base_str, &globals);
              str->reset();
              delete str;
            }
            globals.free();
        }
    } catch (...) {

    }

    delete globalParams;

    return 0;
}

<commit_msg>Fuzz JBIG2 code by checking on each object in PDF file (#7508)<commit_after>/*  Copyright 2020 Google Inc.

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

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

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

#include <vector>
#include <aconf.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <png.h>

#include "gmem.h"
#include "gmempp.h"
#include "parseargs.h"
#include "GString.h"
#include "gfile.h"
#include "GlobalParams.h"
#include "Object.h"
#include "PDFDoc.h"
#include "SplashBitmap.h"
#include "Splash.h"
#include "SplashOutputDev.h"
#include "Stream.h"
#include "config.h"
#include "JBIG2Stream.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
    FuzzedDataProvider fdp (data, size);
    double hdpi = fdp.ConsumeFloatingPoint<double>();
    double vdpi = fdp.ConsumeFloatingPoint<double>();
    int rotate = fdp.ConsumeIntegral<int>();
    bool useMediaBox = fdp.ConsumeBool();
    bool crop = fdp.ConsumeBool();
    bool printing = fdp.ConsumeBool();
    std::vector<char> payload = fdp.ConsumeRemainingBytes<char>();

    Object xpdf_obj;
    xpdf_obj.initNull();
    BaseStream *stream = new MemStream(payload.data(), 0, payload.size(), &xpdf_obj);

    Object info, xfa;
    Object *acroForm;
    globalParams = new GlobalParams(NULL);
    globalParams->setErrQuiet(1);
    globalParams->setupBaseFonts(NULL);
    char yes[] = "yes";
    globalParams->setEnableFreeType(yes);  // Yes, it's a string and not a bool.
    globalParams->setErrQuiet(1);

    PDFDoc *doc = NULL;
    try {
      PDFDoc doc(stream);
        if (doc.isOk() == gTrue)
        {
            doc.getNumPages();
            doc.getOutline();
            doc.getStructTreeRoot();
            doc.getXRef();
            doc.okToPrint(gTrue);
            doc.okToCopy(gTrue);
            doc.okToChange(gTrue);
            doc.okToAddNotes(gTrue);
            doc.isLinearized();
            doc.getPDFVersion();

            GString *metadata;
            if ((metadata = doc.readMetadata())) {
              (void)metadata->getCString();
            }
            delete metadata;

            Object info;
            doc.getDocInfo(&info);
            if (info.isDict()) {
              info.getDict();
            }
            info.free();

            if ((acroForm = doc.getCatalog()->getAcroForm())->isDict()) {
                acroForm->dictLookup("XFA", &xfa);
                xfa.free();
            }

            for (size_t i = 0; i < doc.getNumPages(); i++) {
              doc.getLinks(i);
              auto page = doc.getCatalog()->getPage(i);
              if (!page->isOk()) {
                continue;
              }
              page->getResourceDict();
              page->getMetadata();
              page->getResourceDict();
            }

            SplashColor paperColor = {0xff, 0xff, 0xff};
            SplashOutputDev *splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor);
            splashOut->setNoComposite(gTrue);
            splashOut->startDoc(doc.getXRef());
            for (size_t i = 0; i <= doc.getNumPages(); ++i) {
              doc.displayPage(splashOut, i, hdpi, vdpi, rotate, useMediaBox, crop, printing);
            }
            (void)splashOut->getBitmap();

            delete splashOut;

            XRef *xref = doc.getXRef();
            int objNums = xref->getNumObjects();
            Object currentObj;
            for (int i = 0; i < objNums; ++i) {
              if (xref->fetch(i, 0, &currentObj)->isStream()){
                currentObj.getStream()->reset();
              }
            }
            currentObj.free();
        }
    } catch (...) {

    }

    delete globalParams;

    return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2011 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/bind.h"
#include "base/bind_helpers.h"
#include "base/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/common/automation_messages.h"
#include "chrome_frame/cfproxy_private.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;
using testing::StrEq;
using testing::Eq;

// 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(OnMessageReceived, bool(const IPC::Message& message));
  MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
  MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
  MOCK_METHOD0(Disconnected, void());
  MOCK_METHOD0(tab_handle, int());

  MOCK_METHOD5(Completed_CreateTab, void(bool success, HWND chrome_wnd,
      HWND tab_window, int tab_handle, int session_id));
  MOCK_METHOD5(Completed_ConnectToTab, void(bool success, HWND chrome_window,
      HWND tab_window, int tab_handle, int session_id));
  MOCK_METHOD2(Completed_Navigate, void(bool success,
      enum AutomationMsg_NavigationResponseValues res));

  // Network requests from Chrome.
  MOCK_METHOD2(Network_Start, void(int request_id,
      const AutomationURLRequest& request_info));
  MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
  MOCK_METHOD2(Network_End, void(int request_id,
                                 const net::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 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 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_METHOD3(HandleContextMenu, void(HANDLE menu_handle, int align_flags,
      const MiniContextMenuParams& params));
  MOCK_METHOD1(TabbedOut, void(bool reverse));

  //
  MOCK_METHOD0(TabClosed, void());
  MOCK_METHOD1(AttachTab, void(const 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, base::Bind(&IPC::Channel::Listener::OnChannelConnected,
                              base::Unretained(listener), 0),
        t.InMilliseconds());
  }

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

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

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

// Handy macros when we want so simulate 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))

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);
}

// Test that a channel error results in Completed_XYZ(false, ) called if
// the synchronious XYZ message has been sent.
TEST(ChromeProxy, ChannelError) {
  base::WaitableEvent connected(false, false);
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  StrictMock<MockFactory> factory;
  CFProxy* proxy = new CFProxy(&api);

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

  testing::InSequence s;

  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(10)),
      Return(true)));
  EXPECT_CALL(delegate, Connected(proxy))
      .WillOnce(DoAll(
          InvokeWithoutArgs(CreateFunctor(proxy, &ChromeProxy::ConnectTab,
                                          &delegate, HWND(6), 512)),
          InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal)));

  EXPECT_CALL(api.sender, Send(_));
  EXPECT_CALL(delegate, Completed_ConnectToTab(false, _, _, _, _));
  EXPECT_CALL(api, CloseChannel(&api.sender));
  EXPECT_CALL(delegate, PeerLost(_, ChromeProxyDelegate::CHANNEL_ERROR));

  factory.GetProxy(&delegate, params);
  EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
  // Simulate a channel error.
  api.FireError(base::TimeDelta::FromMilliseconds(0));

  // Expectations when the Proxy is destroyed.
  EXPECT_CALL(delegate, tab_handle()).WillOnce(Return(0));
  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;
}

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

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);

  const int kTabHandle = 6;
  const int kSessionId = 8;

  // Create a sync message and its reply.
  AutomationMsg_CreateExternalTab m(ExternalTabSettings(), 0, 0, 0, 0);
  scoped_ptr<IPC::Message> r(CreateReply(&m, (HWND)1, (HWND)2, kTabHandle,
                                         kSessionId));

  queue.QueueSyncMessage(&m, &d1, NULL);

  testing::InSequence s;
  EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, kTabHandle,
                                      kSessionId));

  // Execute replies in a worker thread.
  ipc.message_loop()->PostTask(
      FROM_HERE,
      base::Bind(base::IgnoreResult(&SyncMsgSender::OnReplyReceived),
                 base::Unretained(&queue), r.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>Scrub CFProxy tests properly.<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 <string>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/common/automation_messages.h"
#include "chrome_frame/cfproxy_private.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/test_scrubber.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;
using testing::StrEq;
using testing::Eq;

// 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(OnMessageReceived, bool(const IPC::Message& message));
  MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
  MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
  MOCK_METHOD0(Disconnected, void());
  MOCK_METHOD0(tab_handle, int());

  MOCK_METHOD5(Completed_CreateTab, void(bool success, HWND chrome_wnd,
      HWND tab_window, int tab_handle, int session_id));
  MOCK_METHOD5(Completed_ConnectToTab, void(bool success, HWND chrome_window,
      HWND tab_window, int tab_handle, int session_id));
  MOCK_METHOD2(Completed_Navigate, void(bool success,
      enum AutomationMsg_NavigationResponseValues res));

  // Network requests from Chrome.
  MOCK_METHOD2(Network_Start, void(int request_id,
      const AutomationURLRequest& request_info));
  MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
  MOCK_METHOD2(Network_End, void(int request_id,
                                 const net::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 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 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_METHOD3(HandleContextMenu, void(HANDLE menu_handle, int align_flags,
      const MiniContextMenuParams& params));
  MOCK_METHOD1(TabbedOut, void(bool reverse));

  //
  MOCK_METHOD0(TabClosed, void());
  MOCK_METHOD1(AttachTab, void(const 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, base::Bind(&IPC::Channel::Listener::OnChannelConnected,
                              base::Unretained(listener), 0),
        t.InMilliseconds());
  }

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

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

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

// Handy macros when we want so simulate 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))

class ChromeProxyTest : public ::testing::Test {
 protected:
  virtual void SetUp() OVERRIDE {
    chrome_frame_test::OverrideDataDirectoryForThisTest(
        chrome_frame_test::GetProfilePath(L"").value());
    params_.profile = "Adam N. Epilinter";
    params_.timeout = base::TimeDelta::FromSeconds(4);
  }

  ProxyParams params_;
};

TEST_F(ChromeProxyTest, 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());

  factory.GetProxy(&delegate, params_);
  factory.ReleaseProxy(&delegate, params_.profile);
}

// Not very useful test. Just for illustration. :)
TEST_F(ChromeProxyTest, 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));

  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_F(ChromeProxyTest, 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));
  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_F(ChromeProxyTest, LaunchChrome) {
  base::WaitableEvent connected(false, false);
  StrictMock<MockChromeProxyDelegate> delegate;
  ChromeProxyFactory factory;

  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);
}

// Test that a channel error results in Completed_XYZ(false, ) called if
// the synchronious XYZ message has been sent.
TEST_F(ChromeProxyTest, ChannelError) {
  base::WaitableEvent connected(false, false);
  StrictMock<MockCFProxyTraits> api;
  StrictMock<MockChromeProxyDelegate> delegate;
  StrictMock<MockFactory> factory;
  CFProxy* proxy = new CFProxy(&api);

  params_.timeout = base::TimeDelta::FromMilliseconds(300);

  testing::InSequence s;

  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(10)),
      Return(true)));
  EXPECT_CALL(delegate, Connected(proxy))
      .WillOnce(DoAll(
          InvokeWithoutArgs(CreateFunctor(proxy, &ChromeProxy::ConnectTab,
                                          &delegate, HWND(6), 512)),
          InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal)));

  EXPECT_CALL(api.sender, Send(_));
  EXPECT_CALL(delegate, Completed_ConnectToTab(false, _, _, _, _));
  EXPECT_CALL(api, CloseChannel(&api.sender));
  EXPECT_CALL(delegate, PeerLost(_, ChromeProxyDelegate::CHANNEL_ERROR));

  factory.GetProxy(&delegate, params_);
  EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
  // Simulate a channel error.
  api.FireError(base::TimeDelta::FromMilliseconds(0));

  // Expectations when the Proxy is destroyed.
  EXPECT_CALL(delegate, tab_handle()).WillOnce(Return(0));
  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;
}

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

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);

  const int kTabHandle = 6;
  const int kSessionId = 8;

  // Create a sync message and its reply.
  AutomationMsg_CreateExternalTab m(ExternalTabSettings(), 0, 0, 0, 0);
  scoped_ptr<IPC::Message> r(CreateReply(&m, (HWND)1, (HWND)2, kTabHandle,
                                         kSessionId));

  queue.QueueSyncMessage(&m, &d1, NULL);

  testing::InSequence s;
  EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, kTabHandle,
                                      kSessionId));

  // Execute replies in a worker thread.
  ipc.message_loop()->PostTask(
      FROM_HERE,
      base::Bind(base::IgnoreResult(&SyncMsgSender::OnReplyReceived),
                 base::Unretained(&queue), r.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>#pragma once

#include "boost_defs.hpp"

#include "event_queue.hpp"
#include "modifier_flag_manager.hpp"
#include "stream_utility.hpp"
#include <boost/optional.hpp>
#include <json/json.hpp>
#include <unordered_set>

namespace krbn {
namespace manipulator {
namespace details {

class event_definition {
public:
  enum class type {
    none,
    key_code,
    pointing_button,
  };

  enum class modifier {
    any,
    caps_lock,
    command,
    control,
    fn,
    left_command,
    left_control,
    left_option,
    left_shift,
    option,
    right_command,
    right_control,
    right_option,
    right_shift,
    shift,
    end_,
  };

  virtual ~event_definition(void) {
  }

  type get_type(void) const {
    return type_;
  }

  boost::optional<key_code> get_key_code(void) const {
    if (type_ == type::key_code) {
      return key_code_;
    }
    return boost::none;
  }

  boost::optional<pointing_button> get_pointing_button(void) const {
    if (type_ == type::pointing_button) {
      return pointing_button_;
    }
    return boost::none;
  }

  boost::optional<event_queue::queued_event::event> to_event(void) const {
    switch (type_) {
      case type::none:
        return boost::none;
      case type::key_code:
        return event_queue::queued_event::event(key_code_);
      case type::pointing_button:
        return event_queue::queued_event::event(pointing_button_);
    }
  }

  static std::unordered_set<modifier> make_modifiers(const nlohmann::json& json) {
    std::unordered_set<modifier> modifiers;

    for (const auto& j : json) {
      if (j.is_string()) {
        const std::string& name = j;
        if (name == "any") {
          modifiers.insert(modifier::any);
        } else if (name == "caps_lock") {
          modifiers.insert(modifier::caps_lock);
        } else if (name == "command") {
          modifiers.insert(modifier::command);
        } else if (name == "control") {
          modifiers.insert(modifier::control);
        } else if (name == "fn") {
          modifiers.insert(modifier::fn);
        } else if (name == "left_command") {
          modifiers.insert(modifier::left_command);
        } else if (name == "left_control") {
          modifiers.insert(modifier::left_control);
        } else if (name == "left_option") {
          modifiers.insert(modifier::left_option);
        } else if (name == "left_shift") {
          modifiers.insert(modifier::left_shift);
        } else if (name == "option") {
          modifiers.insert(modifier::option);
        } else if (name == "right_command") {
          modifiers.insert(modifier::right_command);
        } else if (name == "right_control") {
          modifiers.insert(modifier::right_control);
        } else if (name == "right_option") {
          modifiers.insert(modifier::right_option);
        } else if (name == "right_shift") {
          modifiers.insert(modifier::right_shift);
        } else if (name == "shift") {
          modifiers.insert(modifier::shift);
        } else {
          logger::get_logger().error("unknown modifier: {0}", name);
        }
      }
    }

    return modifiers;
  }

  static std::vector<modifier_flag> get_modifier_flags(modifier modifier) {
    switch (modifier) {
      case modifier::any:
        return {};

      case modifier::caps_lock:
        return {modifier_flag::caps_lock};

      case modifier::command:
        return {modifier_flag::left_command, modifier_flag::right_command};

      case modifier::control:
        return {modifier_flag::left_control, modifier_flag::right_control};

      case modifier::fn:
        return {modifier_flag::fn};

      case modifier::left_command:
        return {modifier_flag::left_command};

      case modifier::left_control:
        return {modifier_flag::left_control};

      case modifier::left_option:
        return {modifier_flag::left_option};

      case modifier::left_shift:
        return {modifier_flag::left_shift};

      case modifier::option:
        return {modifier_flag::left_option, modifier_flag::right_option};

      case modifier::right_command:
        return {modifier_flag::right_command};

      case modifier::right_control:
        return {modifier_flag::right_control};

      case modifier::right_option:
        return {modifier_flag::right_option};

      case modifier::right_shift:
        return {modifier_flag::right_shift};

      case modifier::shift:
        return {modifier_flag::left_shift, modifier_flag::right_shift};

      case modifier::end_:
        return {};
    }
  }

  static modifier get_modifier(modifier_flag modifier_flag) {
    switch (modifier_flag) {
      case modifier_flag::caps_lock:
        return modifier::caps_lock;

      case modifier_flag::fn:
        return modifier::fn;

      case modifier_flag::left_command:
        return modifier::left_command;

      case modifier_flag::left_control:
        return modifier::left_control;

      case modifier_flag::left_option:
        return modifier::left_option;

      case modifier_flag::left_shift:
        return modifier::left_shift;

      case modifier_flag::right_command:
        return modifier::right_command;

      case modifier_flag::right_control:
        return modifier::right_control;

      case modifier_flag::right_option:
        return modifier::right_option;

      case modifier_flag::right_shift:
        return modifier::right_shift;

      case modifier_flag::zero:
      case modifier_flag::end_:
        return modifier::end_;
    }
  }

protected:
  event_definition(const nlohmann::json& json) : type_(type::none) {
    // Set type_ and values.

    {
      const std::string key = "key_code";
      if (json.find(key) != std::end(json) && json[key].is_string()) {
        const std::string& name = json[key];
        if (auto key_code = types::get_key_code(name)) {
          type_ = type::key_code;
          key_code_ = *key_code;
          return;
        }
      }
    }
    {
      const std::string key = "pointing_button";
      if (json.find(key) != std::end(json) && json[key].is_string()) {
        if (auto pointing_button = types::get_pointing_button(json[key])) {
          type_ = type::pointing_button;
          pointing_button_ = *pointing_button;
          return;
        }
      }
    }
  }

  event_definition(key_code key_code) : type_(type::key_code),
                                        key_code_(key_code) {
  }

  event_definition(pointing_button pointing_button) : type_(type::pointing_button),
                                                      pointing_button_(pointing_button) {
  }

  type type_;
  union {
    key_code key_code_;
    pointing_button pointing_button_;
  };
};

class from_event_definition final : public event_definition {
public:
  from_event_definition(const nlohmann::json& json) : event_definition(json) {
    {
      const std::string key = "modifiers";
      if (json.find(key) != json.end() && json[key].is_object()) {
        auto& modifiers = json[key];
        {
          const std::string k = "mandatory";
          if (modifiers.find(k) != modifiers.end()) {
            mandatory_modifiers_ = make_modifiers(modifiers[k]);
          }
        }
        {
          const std::string k = "optional";
          if (modifiers.find(k) != modifiers.end()) {
            optional_modifiers_ = make_modifiers(modifiers[k]);
          }
        }
      }
    }
  }

  from_event_definition(key_code key_code,
                        std::unordered_set<modifier> mandatory_modifiers,
                        std::unordered_set<modifier> optional_modifiers) : event_definition(key_code),
                                                                           mandatory_modifiers_(mandatory_modifiers),
                                                                           optional_modifiers_(optional_modifiers) {
  }

  virtual ~from_event_definition(void) {
  }

  const std::unordered_set<modifier>& get_mandatory_modifiers(void) const {
    return mandatory_modifiers_;
  }

  const std::unordered_set<modifier>& get_optional_modifiers(void) const {
    return optional_modifiers_;
  }

  boost::optional<std::unordered_set<modifier_flag>> test_modifiers(const modifier_flag_manager& modifier_flag_manager) const {
    std::unordered_set<modifier_flag> modifier_flags;

    // If mandatory_modifiers_ contains modifier::any, return all active modifier_flags.

    if (mandatory_modifiers_.find(modifier::any) != std::end(mandatory_modifiers_)) {
      for (auto i = static_cast<uint32_t>(modifier_flag::zero) + 1; i != static_cast<uint32_t>(modifier_flag::end_); ++i) {
        auto flag = modifier_flag(i);
        if (modifier_flag_manager.is_pressed(flag)) {
          modifier_flags.insert(flag);
        }
      }
      return modifier_flags;
    }

    // Check modifier_flag state.

    for (int i = 0; i < static_cast<int>(modifier::end_); ++i) {
      auto m = modifier(i);

      if (mandatory_modifiers_.find(m) != std::end(mandatory_modifiers_)) {
        auto pair = test_modifier(modifier_flag_manager, m);
        if (!pair.first) {
          return boost::none;
        }
        if (pair.second != modifier_flag::zero) {
          modifier_flags.insert(pair.second);
        }
      }
    }

    // If optional_modifiers_ does not contain modifier::any, we have to check modifier flags strictly.

    if (optional_modifiers_.find(modifier::any) == std::end(optional_modifiers_)) {
      std::unordered_set<modifier_flag> extra_modifier_flags;
      for (auto m = static_cast<uint32_t>(modifier_flag::zero) + 1; m != static_cast<uint32_t>(modifier_flag::end_); ++m) {
        extra_modifier_flags.insert(modifier_flag(m));
      }

      for (int i = 0; i < static_cast<int>(modifier::end_); ++i) {
        auto m = modifier(i);

        if (mandatory_modifiers_.find(m) != std::end(mandatory_modifiers_) ||
            optional_modifiers_.find(m) != std::end(optional_modifiers_)) {
          for (const auto& flag : get_modifier_flags(m)) {
            extra_modifier_flags.erase(flag);
          }
        }
      }

      for (const auto& flag : extra_modifier_flags) {
        if (modifier_flag_manager.is_pressed(flag)) {
          return boost::none;
        }
      }
    }

    return modifier_flags;
  }

  static std::pair<bool, modifier_flag> test_modifier(const modifier_flag_manager& modifier_flag_manager,
                                                      modifier modifier) {
    if (modifier == modifier::any) {
      return std::make_pair(true, modifier_flag::zero);
    }

    auto modifier_flags = get_modifier_flags(modifier);
    if (!modifier_flags.empty()) {
      for (const auto& m : modifier_flags) {
        if (modifier_flag_manager.is_pressed(m)) {
          return std::make_pair(true, m);
        }
      }
    }

    return std::make_pair(false, modifier_flag::zero);
  }

private:
  std::unordered_set<modifier> mandatory_modifiers_;
  std::unordered_set<modifier> optional_modifiers_;
};

class to_event_definition final : public event_definition {
public:
  to_event_definition(const nlohmann::json& json) : event_definition(json) {
    {
      const std::string key = "modifiers";
      if (json.find(key) != json.end()) {
        modifiers_ = make_modifiers(json[key]);
      }
    }
  }

  to_event_definition(key_code key_code,
                      std::unordered_set<modifier> modifiers) : event_definition(key_code),
                                                                modifiers_(modifiers) {
  }

  virtual ~to_event_definition(void) {
  }

  const std::unordered_set<modifier>& get_modifiers(void) const {
    return modifiers_;
  }

private:
  std::unordered_set<modifier> modifiers_;
};

inline std::ostream& operator<<(std::ostream& stream, const event_definition::modifier& value) {
#define KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(MODIFIER) \
  case event_definition::modifier::MODIFIER:               \
    stream << #MODIFIER;                                   \
    break;

  switch (value) {
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(any);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(caps_lock);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(fn);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(end_);
  }

#undef KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT

  return stream;
}

template <template <class T, class A> class container>
inline std::ostream& operator<<(std::ostream& stream, const container<event_definition::modifier, std::allocator<event_definition::modifier>>& values) {
  return stream_utility::output_enums(stream, values);
}

template <template <class T, class H, class K, class A> class container>
inline std::ostream& operator<<(std::ostream& stream,
                                const container<event_definition::modifier,
                                                std::hash<event_definition::modifier>,
                                                std::equal_to<event_definition::modifier>,
                                                std::allocator<event_definition::modifier>>& values) {
  return stream_utility::output_enums(stream, values);
}
} // namespace details
} // namespace manipulator
} // namespace krbn
<commit_msg>use boost/variant<commit_after>#pragma once

#include "boost_defs.hpp"

#include "event_queue.hpp"
#include "modifier_flag_manager.hpp"
#include "stream_utility.hpp"
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <json/json.hpp>
#include <unordered_set>

namespace krbn {
namespace manipulator {
namespace details {

class event_definition {
public:
  enum class type {
    none,
    key_code,
    pointing_button,
  };

  enum class modifier {
    any,
    caps_lock,
    command,
    control,
    fn,
    left_command,
    left_control,
    left_option,
    left_shift,
    option,
    right_command,
    right_control,
    right_option,
    right_shift,
    shift,
    end_,
  };

  virtual ~event_definition(void) {
  }

  type get_type(void) const {
    return type_;
  }

  boost::optional<key_code> get_key_code(void) const {
    if (type_ == type::key_code) {
      return boost::get<key_code>(value_);
    }
    return boost::none;
  }

  boost::optional<pointing_button> get_pointing_button(void) const {
    if (type_ == type::pointing_button) {
      return boost::get<pointing_button>(value_);
    }
    return boost::none;
  }

  boost::optional<event_queue::queued_event::event> to_event(void) const {
    switch (type_) {
      case type::none:
        return boost::none;
      case type::key_code:
        return event_queue::queued_event::event(boost::get<key_code>(value_));
      case type::pointing_button:
        return event_queue::queued_event::event(boost::get<pointing_button>(value_));
    }
  }

  static std::unordered_set<modifier> make_modifiers(const nlohmann::json& json) {
    std::unordered_set<modifier> modifiers;

    for (const auto& j : json) {
      if (j.is_string()) {
        const std::string& name = j;
        if (name == "any") {
          modifiers.insert(modifier::any);
        } else if (name == "caps_lock") {
          modifiers.insert(modifier::caps_lock);
        } else if (name == "command") {
          modifiers.insert(modifier::command);
        } else if (name == "control") {
          modifiers.insert(modifier::control);
        } else if (name == "fn") {
          modifiers.insert(modifier::fn);
        } else if (name == "left_command") {
          modifiers.insert(modifier::left_command);
        } else if (name == "left_control") {
          modifiers.insert(modifier::left_control);
        } else if (name == "left_option") {
          modifiers.insert(modifier::left_option);
        } else if (name == "left_shift") {
          modifiers.insert(modifier::left_shift);
        } else if (name == "option") {
          modifiers.insert(modifier::option);
        } else if (name == "right_command") {
          modifiers.insert(modifier::right_command);
        } else if (name == "right_control") {
          modifiers.insert(modifier::right_control);
        } else if (name == "right_option") {
          modifiers.insert(modifier::right_option);
        } else if (name == "right_shift") {
          modifiers.insert(modifier::right_shift);
        } else if (name == "shift") {
          modifiers.insert(modifier::shift);
        } else {
          logger::get_logger().error("unknown modifier: {0}", name);
        }
      }
    }

    return modifiers;
  }

  static std::vector<modifier_flag> get_modifier_flags(modifier modifier) {
    switch (modifier) {
      case modifier::any:
        return {};

      case modifier::caps_lock:
        return {modifier_flag::caps_lock};

      case modifier::command:
        return {modifier_flag::left_command, modifier_flag::right_command};

      case modifier::control:
        return {modifier_flag::left_control, modifier_flag::right_control};

      case modifier::fn:
        return {modifier_flag::fn};

      case modifier::left_command:
        return {modifier_flag::left_command};

      case modifier::left_control:
        return {modifier_flag::left_control};

      case modifier::left_option:
        return {modifier_flag::left_option};

      case modifier::left_shift:
        return {modifier_flag::left_shift};

      case modifier::option:
        return {modifier_flag::left_option, modifier_flag::right_option};

      case modifier::right_command:
        return {modifier_flag::right_command};

      case modifier::right_control:
        return {modifier_flag::right_control};

      case modifier::right_option:
        return {modifier_flag::right_option};

      case modifier::right_shift:
        return {modifier_flag::right_shift};

      case modifier::shift:
        return {modifier_flag::left_shift, modifier_flag::right_shift};

      case modifier::end_:
        return {};
    }
  }

  static modifier get_modifier(modifier_flag modifier_flag) {
    switch (modifier_flag) {
      case modifier_flag::caps_lock:
        return modifier::caps_lock;

      case modifier_flag::fn:
        return modifier::fn;

      case modifier_flag::left_command:
        return modifier::left_command;

      case modifier_flag::left_control:
        return modifier::left_control;

      case modifier_flag::left_option:
        return modifier::left_option;

      case modifier_flag::left_shift:
        return modifier::left_shift;

      case modifier_flag::right_command:
        return modifier::right_command;

      case modifier_flag::right_control:
        return modifier::right_control;

      case modifier_flag::right_option:
        return modifier::right_option;

      case modifier_flag::right_shift:
        return modifier::right_shift;

      case modifier_flag::zero:
      case modifier_flag::end_:
        return modifier::end_;
    }
  }

protected:
  event_definition(const nlohmann::json& json) : type_(type::none) {
    // Set type_ and values.

    {
      const std::string key = "key_code";
      if (json.find(key) != std::end(json) && json[key].is_string()) {
        const std::string& name = json[key];
        if (auto key_code = types::get_key_code(name)) {
          type_ = type::key_code;
          value_ = *key_code;
          return;
        }
      }
    }
    {
      const std::string key = "pointing_button";
      if (json.find(key) != std::end(json) && json[key].is_string()) {
        if (auto pointing_button = types::get_pointing_button(json[key])) {
          type_ = type::pointing_button;
          value_ = *pointing_button;
          return;
        }
      }
    }
  }

  event_definition(key_code key_code) : type_(type::key_code),
                                        value_(key_code) {
  }

  event_definition(pointing_button pointing_button) : type_(type::pointing_button),
                                                      value_(pointing_button) {
  }

  type type_;
  boost::variant<key_code,
                 pointing_button>
      value_;
};

class from_event_definition final : public event_definition {
public:
  from_event_definition(const nlohmann::json& json) : event_definition(json) {
    {
      const std::string key = "modifiers";
      if (json.find(key) != json.end() && json[key].is_object()) {
        auto& modifiers = json[key];
        {
          const std::string k = "mandatory";
          if (modifiers.find(k) != modifiers.end()) {
            mandatory_modifiers_ = make_modifiers(modifiers[k]);
          }
        }
        {
          const std::string k = "optional";
          if (modifiers.find(k) != modifiers.end()) {
            optional_modifiers_ = make_modifiers(modifiers[k]);
          }
        }
      }
    }
  }

  from_event_definition(key_code key_code,
                        std::unordered_set<modifier> mandatory_modifiers,
                        std::unordered_set<modifier> optional_modifiers) : event_definition(key_code),
                                                                           mandatory_modifiers_(mandatory_modifiers),
                                                                           optional_modifiers_(optional_modifiers) {
  }

  virtual ~from_event_definition(void) {
  }

  const std::unordered_set<modifier>& get_mandatory_modifiers(void) const {
    return mandatory_modifiers_;
  }

  const std::unordered_set<modifier>& get_optional_modifiers(void) const {
    return optional_modifiers_;
  }

  boost::optional<std::unordered_set<modifier_flag>> test_modifiers(const modifier_flag_manager& modifier_flag_manager) const {
    std::unordered_set<modifier_flag> modifier_flags;

    // If mandatory_modifiers_ contains modifier::any, return all active modifier_flags.

    if (mandatory_modifiers_.find(modifier::any) != std::end(mandatory_modifiers_)) {
      for (auto i = static_cast<uint32_t>(modifier_flag::zero) + 1; i != static_cast<uint32_t>(modifier_flag::end_); ++i) {
        auto flag = modifier_flag(i);
        if (modifier_flag_manager.is_pressed(flag)) {
          modifier_flags.insert(flag);
        }
      }
      return modifier_flags;
    }

    // Check modifier_flag state.

    for (int i = 0; i < static_cast<int>(modifier::end_); ++i) {
      auto m = modifier(i);

      if (mandatory_modifiers_.find(m) != std::end(mandatory_modifiers_)) {
        auto pair = test_modifier(modifier_flag_manager, m);
        if (!pair.first) {
          return boost::none;
        }
        if (pair.second != modifier_flag::zero) {
          modifier_flags.insert(pair.second);
        }
      }
    }

    // If optional_modifiers_ does not contain modifier::any, we have to check modifier flags strictly.

    if (optional_modifiers_.find(modifier::any) == std::end(optional_modifiers_)) {
      std::unordered_set<modifier_flag> extra_modifier_flags;
      for (auto m = static_cast<uint32_t>(modifier_flag::zero) + 1; m != static_cast<uint32_t>(modifier_flag::end_); ++m) {
        extra_modifier_flags.insert(modifier_flag(m));
      }

      for (int i = 0; i < static_cast<int>(modifier::end_); ++i) {
        auto m = modifier(i);

        if (mandatory_modifiers_.find(m) != std::end(mandatory_modifiers_) ||
            optional_modifiers_.find(m) != std::end(optional_modifiers_)) {
          for (const auto& flag : get_modifier_flags(m)) {
            extra_modifier_flags.erase(flag);
          }
        }
      }

      for (const auto& flag : extra_modifier_flags) {
        if (modifier_flag_manager.is_pressed(flag)) {
          return boost::none;
        }
      }
    }

    return modifier_flags;
  }

  static std::pair<bool, modifier_flag> test_modifier(const modifier_flag_manager& modifier_flag_manager,
                                                      modifier modifier) {
    if (modifier == modifier::any) {
      return std::make_pair(true, modifier_flag::zero);
    }

    auto modifier_flags = get_modifier_flags(modifier);
    if (!modifier_flags.empty()) {
      for (const auto& m : modifier_flags) {
        if (modifier_flag_manager.is_pressed(m)) {
          return std::make_pair(true, m);
        }
      }
    }

    return std::make_pair(false, modifier_flag::zero);
  }

private:
  std::unordered_set<modifier> mandatory_modifiers_;
  std::unordered_set<modifier> optional_modifiers_;
};

class to_event_definition final : public event_definition {
public:
  to_event_definition(const nlohmann::json& json) : event_definition(json) {
    {
      const std::string key = "modifiers";
      if (json.find(key) != json.end()) {
        modifiers_ = make_modifiers(json[key]);
      }
    }
  }

  to_event_definition(key_code key_code,
                      std::unordered_set<modifier> modifiers) : event_definition(key_code),
                                                                modifiers_(modifiers) {
  }

  virtual ~to_event_definition(void) {
  }

  const std::unordered_set<modifier>& get_modifiers(void) const {
    return modifiers_;
  }

private:
  std::unordered_set<modifier> modifiers_;
};

inline std::ostream& operator<<(std::ostream& stream, const event_definition::modifier& value) {
#define KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(MODIFIER) \
  case event_definition::modifier::MODIFIER:               \
    stream << #MODIFIER;                                   \
    break;

  switch (value) {
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(any);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(caps_lock);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(fn);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(left_shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_command);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_control);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_option);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(right_shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(shift);
    KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT(end_);
  }

#undef KRBN_MANIPULATOR_DETAILS_MODIFIER_OUTPUT

  return stream;
}

template <template <class T, class A> class container>
inline std::ostream& operator<<(std::ostream& stream, const container<event_definition::modifier, std::allocator<event_definition::modifier>>& values) {
  return stream_utility::output_enums(stream, values);
}

template <template <class T, class H, class K, class A> class container>
inline std::ostream& operator<<(std::ostream& stream,
                                const container<event_definition::modifier,
                                                std::hash<event_definition::modifier>,
                                                std::equal_to<event_definition::modifier>,
                                                std::allocator<event_definition::modifier>>& values) {
  return stream_utility::output_enums(stream, values);
}
} // namespace details
} // namespace manipulator
} // namespace krbn
<|endoftext|>


<commit_before>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "pci.hh"
#include "pcireg.hh"
#include "traps.h"
#include "kstream.hh"

static console_stream verbose(true);

extern int e1000attach(struct pci_func *pcif);
extern int e1000eattach(struct pci_func *pcif);

// Flag to do "lspci" at bootup
static int pci_show_devs = 0;
static int pci_show_addrs = 0;

// PCI "configuration mechanism one"
static u32 pci_conf1_addr_ioport = 0x0cf8;
static u32 pci_conf1_data_ioport = 0x0cfc;

// PCI driver table
struct pci_driver {
  u32 key1, key2;
  int (*attachfn) (struct pci_func *pcif);
};

// Forward declarations
static int pci_bridge_attach(struct pci_func *pcif);

// pci_attach_class matches the class and subclass of a PCI device
struct pci_driver pci_attach_class[] = {
  { PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI, &pci_bridge_attach },
  { 0, 0, 0 },
};

// pci_attach_vendor matches the vendor ID and device ID of a PCI device
struct pci_driver pci_attach_vendor[] = {
  // [E1000 5.2]
  // QEMU emulates an e1000 82540EM
  { 0x8086, 0x100e, &e1000attach },
  // josmp's dual ported e1000 82546GB copper
  { 0x8086, 0x1079, &e1000attach },
  // tom's e1000 82541GI copper
  { 0x8086, 0x1076, &e1000attach },
  // Both of ud0's e1000e (82573E, 82573L)
  { 0x8086, 0x108c, &e1000eattach },
  { 0x8086, 0x109A, &e1000eattach },
  { 0, 0, 0 },
};

static const char *pci_class[] =
{
  "Unknown",
  "Storage controller",
  "Network controller",
  "Display controller",
  "Multimedia device",
  "Memory controller",
  "Bridge device",
};

static void
pci_print_func(struct pci_func *f)
{
  const char *classname = pci_class[0];
  if (PCI_CLASS(f->dev_class) < sizeof(pci_class) / sizeof(pci_class[0]))
    classname = pci_class[PCI_CLASS(f->dev_class)];

  cprintf("PCI: %x:%x.%d: %x:%x: class: %x.%x (%s) irq: %d int: %c\n",
          f->bus->busno, f->dev, f->func,
          PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
          PCI_CLASS(f->dev_class), PCI_SUBCLASS(f->dev_class), classname,
          f->irq_line, "-ABCD"[f->int_pin]);
}

void
to_stream(print_stream *s, const struct pci_func &f)
{
  s->print(sfmt(f.bus->busno).base(16).width(2).pad(), ':',
           sfmt(f.dev).base(16).width(2).pad(), '.',
           sfmt(f.func).base(16).width(2).pad());
}

static void
pci_conf1_set_addr(u32 seg,
                   u32 bus,
		   u32 dev,
		   u32 func,
		   u32 offset)
{
  if (!(seg == 0 &&
        bus < 256 &&
        dev < 32 &&
        func < 8 &&
        offset < 256))
    panic("pci_conf1_set_addr");

  u32 v = (1 << 31) |		// config-space
    (bus << 16) | (dev << 11) | (func << 8) | (offset);
  outl(pci_conf1_addr_ioport, v);
}

u32
pci_conf_read(u32 seg, u32 bus, u32 dev, u32 func, u32 offset, int width)
{
  pci_conf1_set_addr(seg, bus, dev, func, offset);
  switch (width) {
  case 8:
    return inb(pci_conf1_data_ioport + (offset & 3));
  case 16:
    return inw(pci_conf1_data_ioport + (offset & 2));
  case 32:
    return inl(pci_conf1_data_ioport);
  }
  panic("pci_conf_read: bad width %d", width);
}

static u32
pci_conf_read(struct pci_func *f, u32 off)
{
  return pci_conf_read(0, f->bus->busno, f->dev, f->func, off, 32);
}

void
pci_conf_write(u32 seg, u32 bus, u32 dev, u32 func, u32 offset,
               u32 val, int width)
{
  pci_conf1_set_addr(seg, bus, dev, func, offset);
  switch (width) {
  case 8:
    outb(pci_conf1_data_ioport, val + (offset & 3));
    return;
  case 16:
    outl(pci_conf1_data_ioport, val + (offset & 2));
    return;
  case 32:
    outw(pci_conf1_data_ioport, val);
    return;
  }
  panic("pci_conf_write: bad width %d", width);
}

static void
pci_conf_write(struct pci_func *f, u32 off, u32 v)
{
  pci_conf_write(0, f->bus->busno, f->dev, f->func, off, v, 32);
}

static int __attribute__((warn_unused_result))
pci_attach_match(u32 key1, u32 key2,
		 struct pci_driver *list, struct pci_func *pcif)
{
  u32 i;

  for (i = 0; list[i].attachfn; i++) {
    if (list[i].key1 == key1 && list[i].key2 == key2) {
      int r = list[i].attachfn(pcif);
      if (r > 0)
        return r;
      if (r < 0)
        cprintf("pci_attach_match: attaching "
                "%x.%x (%p): %d\n",
                key1, key2, list[i].attachfn, r);
    }
  }
  return 0;
}

static int
pci_attach(struct pci_func *f)
{
  return
    pci_attach_match(PCI_CLASS(f->dev_class),
                     PCI_SUBCLASS(f->dev_class),
                     &pci_attach_class[0], f) ||
    pci_attach_match(PCI_VENDOR(f->dev_id),
                     PCI_PRODUCT(f->dev_id),
                     &pci_attach_vendor[0], f);
}

static void
pci_scan_caplist(struct pci_func* f)
{
  u32 cap_ptr = PCI_CAPLIST_PTR(pci_conf_read(f, PCI_CAPLISTPTR_REG));
  for (int i = 0; i < 10 && cap_ptr != 0; i++) {
    u32 cap_entry = pci_conf_read(f, cap_ptr);
    switch (PCI_CAPLIST_CAP(cap_entry)) {
    case PCI_CAP_MSI:
      f->msi_capreg = cap_ptr;
      break;
    default:
      break;
    }
    cap_ptr = PCI_CAPLIST_NEXT(cap_entry);
  }
}

void
pci_msi_enable(struct pci_func *f, u8 irqnum)
{
  // PCI System Architecture, Fourth Edition

  assert(f->msi_capreg != 0);
  u32 cap_entry = pci_conf_read(f, f->msi_capreg);

  if (!(cap_entry & PCI_MSI_MCR_64BIT))
    panic("pci_msi_enable only handles 64-bit address capable devices");
  if (PCI_MSI_MCR_MMC(cap_entry) != 0)
    panic("pci_msi_enable only handles 1 requested message");

  // [PCI SA pg 253]
  // Step 4. Assign a dword-aligned memory address to the device's
  // Message Address Register.
  // (The Message Address Register format is mandated by the x86
  // architecture.  See 9.11.1 in the Vol. 3 of the Intel architecture
  // manual.)
  pci_conf_write(f, f->msi_capreg + 4*1,
                 (0x0fee << 20) |   // magic constant for northbridge
                 (0 << 12) |        // destination ID
                 (1 << 3) |         // redirection hint
                 (0 << 2));         // destination mode
  pci_conf_write(f, f->msi_capreg + 4*2, 0);

  // Step 5 and 6. Allocate messages for the device.  Since we
  // support only one message and that is the default value in
  // the message control register, we do nothing.

  // Step 7. Write base message data pattern into the device's
  // Message Data Register.
  // (The Message Data Register format is mandated by the x86
  // architecture.  See 9.11.2 in the Vol. 3 of the Intel architecture
  // manual.
  pci_conf_write(f, f->msi_capreg + 4*3,
                 (0 << 15) |        // trigger mode (edge)
                 //(0 << 14) |      // level for trigger mode (don't care)
                 (0 << 8) |         // delivery mode (fixed)
                 (irqnum+T_IRQ0));  // vector

  // Step 8. Set the MSI enable bit in the device's Message
  // control register.
  pci_conf_write(f, f->msi_capreg, cap_entry | (1 << 16));
}

static int
pci_scan_bus(struct pci_bus *bus)
{
  verbose.println("pci: Scanning bus ", shex(bus->busno));

  int totaldev = 0;
  struct pci_func df;
  memset(&df, 0, sizeof(df));
  df.bus = bus;

  for (df.dev = 0; df.dev < 32; df.dev++) {
    u32 bhlc = pci_conf_read(&df, PCI_BHLC_REG);
    if (PCI_HDRTYPE_TYPE(bhlc) > 1)	    // Unsupported or no device
      continue;

    totaldev++;

    struct pci_func         f  = df;
    for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1);
         f.func++) {
      struct pci_func af = f;

      af.dev_id                  = pci_conf_read(&f, PCI_ID_REG);
      if (PCI_VENDOR(af.dev_id) == 0xffff)
				continue;

      u32 intr = pci_conf_read(&af, PCI_INTERRUPT_REG);
      af.irq_line = PCI_INTERRUPT_LINE(intr);
      af.int_pin = PCI_INTERRUPT_PIN(intr);

      u32 cmd_status = pci_conf_read(&af, PCI_COMMAND_STATUS_REG);
      if (cmd_status & PCI_STATUS_CAPLIST_SUPPORT)
        pci_scan_caplist(&af);

      af.dev_class = pci_conf_read(&af, PCI_CLASS_REG);
      if (pci_show_devs)
        pci_print_func(&af);
      pci_attach(&af);
    }
  }
  return totaldev;
}

static int
pci_bridge_attach(struct pci_func *pcif)
{
  u32 busreg = pci_conf_read(pcif, PCI_BRIDGE_BUS_REG);

  struct pci_bus nbus;
  memset(&nbus, 0, sizeof(nbus));
  nbus.parent_bridge = pcif;
  nbus.busno = (busreg >> PCI_BRIDGE_BUS_SECONDARY_SHIFT) & 0xff;

  if (pci_show_devs)
    cprintf("PCI: %x:%x.%d: bridge to PCI bus %d--%d\n",
            pcif->bus->busno, pcif->dev, pcif->func,
            nbus.busno,
            (busreg >> PCI_BRIDGE_BUS_SUBORDINATE_SHIFT) & 0xff);

  pci_scan_bus(&nbus);
  return 1;
}

void
pci_func_enable(struct pci_func *f)
{
  pci_conf_write(f, PCI_COMMAND_STATUS_REG,
                 PCI_COMMAND_IO_ENABLE |
                 PCI_COMMAND_MEM_ENABLE |
                 PCI_COMMAND_MASTER_ENABLE);

  u32 bar_width;
  u32 bar;
  for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
       bar += bar_width)
  {
    u32 oldv = pci_conf_read(f, bar);

    bar_width = 4;
    pci_conf_write(f, bar, 0xffffffff);
    u32 rv = pci_conf_read(f, bar);

    if (rv == 0)
      continue;

    int regnum = PCI_MAPREG_NUM(bar);
    u32 base, size;
    if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
      if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
        bar_width = 8;

      size = PCI_MAPREG_MEM_SIZE(rv);
      base = PCI_MAPREG_MEM_ADDR(oldv);
      if (pci_show_addrs)
        cprintf("  mem region %d: %d bytes at 0x%x\n",
                regnum, size, base);
    } else {
      size = PCI_MAPREG_IO_SIZE(rv);
      base = PCI_MAPREG_IO_ADDR(oldv);
      if (pci_show_addrs)
        cprintf("  io region %d: %d bytes at 0x%x\n",
                regnum, size, base);
    }

    pci_conf_write(f, bar, oldv);
    f->reg_base[regnum] = base;
    f->reg_size[regnum] = size;

    if (size && !base)
      cprintf("PCI device %02x:%02x.%d (%04x:%04x) "
              "may be misconfigured: "
              "region %d: base 0x%x, size %d\n",
              f->bus->busno, f->dev, f->func,
              PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
              regnum, base, size);
  }

  if (VERBOSE)
    cprintf("PCI function %x:%x.%d (%x:%x) enabled\n",
            f->bus->busno, f->dev, f->func,
            PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id));
}

void
initpci(void)
{
  if (!acpi_pci_scan_roots(pci_scan_bus)) {
    // Assume a single root bus
    static struct pci_bus root_bus;
    memset(&root_bus, 0, sizeof(root_bus));

    pci_scan_bus(&root_bus);
  }
}
<commit_msg>pci: Don't assume MSI destination is APICID 0<commit_after>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "pci.hh"
#include "pcireg.hh"
#include "traps.h"
#include "kstream.hh"
#include "cpu.hh"

static console_stream verbose(true);

extern int e1000attach(struct pci_func *pcif);
extern int e1000eattach(struct pci_func *pcif);

// Flag to do "lspci" at bootup
static int pci_show_devs = 0;
static int pci_show_addrs = 0;

// PCI "configuration mechanism one"
static u32 pci_conf1_addr_ioport = 0x0cf8;
static u32 pci_conf1_data_ioport = 0x0cfc;

// PCI driver table
struct pci_driver {
  u32 key1, key2;
  int (*attachfn) (struct pci_func *pcif);
};

// Forward declarations
static int pci_bridge_attach(struct pci_func *pcif);

// pci_attach_class matches the class and subclass of a PCI device
struct pci_driver pci_attach_class[] = {
  { PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI, &pci_bridge_attach },
  { 0, 0, 0 },
};

// pci_attach_vendor matches the vendor ID and device ID of a PCI device
struct pci_driver pci_attach_vendor[] = {
  // [E1000 5.2]
  // QEMU emulates an e1000 82540EM
  { 0x8086, 0x100e, &e1000attach },
  // josmp's dual ported e1000 82546GB copper
  { 0x8086, 0x1079, &e1000attach },
  // tom's e1000 82541GI copper
  { 0x8086, 0x1076, &e1000attach },
  // Both of ud0's e1000e (82573E, 82573L)
  { 0x8086, 0x108c, &e1000eattach },
  { 0x8086, 0x109A, &e1000eattach },
  { 0, 0, 0 },
};

static const char *pci_class[] =
{
  "Unknown",
  "Storage controller",
  "Network controller",
  "Display controller",
  "Multimedia device",
  "Memory controller",
  "Bridge device",
};

static void
pci_print_func(struct pci_func *f)
{
  const char *classname = pci_class[0];
  if (PCI_CLASS(f->dev_class) < sizeof(pci_class) / sizeof(pci_class[0]))
    classname = pci_class[PCI_CLASS(f->dev_class)];

  cprintf("PCI: %x:%x.%d: %x:%x: class: %x.%x (%s) irq: %d int: %c\n",
          f->bus->busno, f->dev, f->func,
          PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
          PCI_CLASS(f->dev_class), PCI_SUBCLASS(f->dev_class), classname,
          f->irq_line, "-ABCD"[f->int_pin]);
}

void
to_stream(print_stream *s, const struct pci_func &f)
{
  s->print(sfmt(f.bus->busno).base(16).width(2).pad(), ':',
           sfmt(f.dev).base(16).width(2).pad(), '.',
           sfmt(f.func).base(16).width(2).pad());
}

static void
pci_conf1_set_addr(u32 seg,
                   u32 bus,
		   u32 dev,
		   u32 func,
		   u32 offset)
{
  if (!(seg == 0 &&
        bus < 256 &&
        dev < 32 &&
        func < 8 &&
        offset < 256))
    panic("pci_conf1_set_addr");

  u32 v = (1 << 31) |		// config-space
    (bus << 16) | (dev << 11) | (func << 8) | (offset);
  outl(pci_conf1_addr_ioport, v);
}

u32
pci_conf_read(u32 seg, u32 bus, u32 dev, u32 func, u32 offset, int width)
{
  pci_conf1_set_addr(seg, bus, dev, func, offset);
  switch (width) {
  case 8:
    return inb(pci_conf1_data_ioport + (offset & 3));
  case 16:
    return inw(pci_conf1_data_ioport + (offset & 2));
  case 32:
    return inl(pci_conf1_data_ioport);
  }
  panic("pci_conf_read: bad width %d", width);
}

static u32
pci_conf_read(struct pci_func *f, u32 off)
{
  return pci_conf_read(0, f->bus->busno, f->dev, f->func, off, 32);
}

void
pci_conf_write(u32 seg, u32 bus, u32 dev, u32 func, u32 offset,
               u32 val, int width)
{
  pci_conf1_set_addr(seg, bus, dev, func, offset);
  switch (width) {
  case 8:
    outb(pci_conf1_data_ioport, val + (offset & 3));
    return;
  case 16:
    outl(pci_conf1_data_ioport, val + (offset & 2));
    return;
  case 32:
    outw(pci_conf1_data_ioport, val);
    return;
  }
  panic("pci_conf_write: bad width %d", width);
}

static void
pci_conf_write(struct pci_func *f, u32 off, u32 v)
{
  pci_conf_write(0, f->bus->busno, f->dev, f->func, off, v, 32);
}

static int __attribute__((warn_unused_result))
pci_attach_match(u32 key1, u32 key2,
		 struct pci_driver *list, struct pci_func *pcif)
{
  u32 i;

  for (i = 0; list[i].attachfn; i++) {
    if (list[i].key1 == key1 && list[i].key2 == key2) {
      int r = list[i].attachfn(pcif);
      if (r > 0)
        return r;
      if (r < 0)
        cprintf("pci_attach_match: attaching "
                "%x.%x (%p): %d\n",
                key1, key2, list[i].attachfn, r);
    }
  }
  return 0;
}

static int
pci_attach(struct pci_func *f)
{
  return
    pci_attach_match(PCI_CLASS(f->dev_class),
                     PCI_SUBCLASS(f->dev_class),
                     &pci_attach_class[0], f) ||
    pci_attach_match(PCI_VENDOR(f->dev_id),
                     PCI_PRODUCT(f->dev_id),
                     &pci_attach_vendor[0], f);
}

static void
pci_scan_caplist(struct pci_func* f)
{
  u32 cap_ptr = PCI_CAPLIST_PTR(pci_conf_read(f, PCI_CAPLISTPTR_REG));
  for (int i = 0; i < 10 && cap_ptr != 0; i++) {
    u32 cap_entry = pci_conf_read(f, cap_ptr);
    switch (PCI_CAPLIST_CAP(cap_entry)) {
    case PCI_CAP_MSI:
      f->msi_capreg = cap_ptr;
      break;
    default:
      break;
    }
    cap_ptr = PCI_CAPLIST_NEXT(cap_entry);
  }
}

void
pci_msi_enable(struct pci_func *f, u8 irqnum)
{
  // PCI System Architecture, Fourth Edition

  assert(f->msi_capreg != 0);
  u32 cap_entry = pci_conf_read(f, f->msi_capreg);

  if (!(cap_entry & PCI_MSI_MCR_64BIT))
    panic("pci_msi_enable only handles 64-bit address capable devices");
  if (PCI_MSI_MCR_MMC(cap_entry) != 0)
    panic("pci_msi_enable only handles 1 requested message");

  // [PCI SA pg 253]
  // Step 4. Assign a dword-aligned memory address to the device's
  // Message Address Register.
  // (The Message Address Register format is mandated by the x86
  // architecture.  See 9.11.1 in the Vol. 3 of the Intel architecture
  // manual.)
  uint64_t dest = cpus[0].hwid.num;
  pci_conf_write(f, f->msi_capreg + 4*1,
                 (0x0fee << 20) |   // magic constant for northbridge
                 (dest << 12) |     // destination ID
                 (1 << 3) |         // redirection hint
                 (0 << 2));         // destination mode
  pci_conf_write(f, f->msi_capreg + 4*2, 0);

  // Step 5 and 6. Allocate messages for the device.  Since we
  // support only one message and that is the default value in
  // the message control register, we do nothing.

  // Step 7. Write base message data pattern into the device's
  // Message Data Register.
  // (The Message Data Register format is mandated by the x86
  // architecture.  See 9.11.2 in the Vol. 3 of the Intel architecture
  // manual.
  pci_conf_write(f, f->msi_capreg + 4*3,
                 (0 << 15) |        // trigger mode (edge)
                 //(0 << 14) |      // level for trigger mode (don't care)
                 (0 << 8) |         // delivery mode (fixed)
                 (irqnum+T_IRQ0));  // vector

  // Step 8. Set the MSI enable bit in the device's Message
  // control register.
  pci_conf_write(f, f->msi_capreg, cap_entry | (1 << 16));
}

static int
pci_scan_bus(struct pci_bus *bus)
{
  verbose.println("pci: Scanning bus ", shex(bus->busno));

  int totaldev = 0;
  struct pci_func df;
  memset(&df, 0, sizeof(df));
  df.bus = bus;

  for (df.dev = 0; df.dev < 32; df.dev++) {
    u32 bhlc = pci_conf_read(&df, PCI_BHLC_REG);
    if (PCI_HDRTYPE_TYPE(bhlc) > 1)	    // Unsupported or no device
      continue;

    totaldev++;

    struct pci_func         f  = df;
    for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1);
         f.func++) {
      struct pci_func af = f;

      af.dev_id                  = pci_conf_read(&f, PCI_ID_REG);
      if (PCI_VENDOR(af.dev_id) == 0xffff)
				continue;

      u32 intr = pci_conf_read(&af, PCI_INTERRUPT_REG);
      af.irq_line = PCI_INTERRUPT_LINE(intr);
      af.int_pin = PCI_INTERRUPT_PIN(intr);

      u32 cmd_status = pci_conf_read(&af, PCI_COMMAND_STATUS_REG);
      if (cmd_status & PCI_STATUS_CAPLIST_SUPPORT)
        pci_scan_caplist(&af);

      af.dev_class = pci_conf_read(&af, PCI_CLASS_REG);
      if (pci_show_devs)
        pci_print_func(&af);
      pci_attach(&af);
    }
  }
  return totaldev;
}

static int
pci_bridge_attach(struct pci_func *pcif)
{
  u32 busreg = pci_conf_read(pcif, PCI_BRIDGE_BUS_REG);

  struct pci_bus nbus;
  memset(&nbus, 0, sizeof(nbus));
  nbus.parent_bridge = pcif;
  nbus.busno = (busreg >> PCI_BRIDGE_BUS_SECONDARY_SHIFT) & 0xff;

  if (pci_show_devs)
    cprintf("PCI: %x:%x.%d: bridge to PCI bus %d--%d\n",
            pcif->bus->busno, pcif->dev, pcif->func,
            nbus.busno,
            (busreg >> PCI_BRIDGE_BUS_SUBORDINATE_SHIFT) & 0xff);

  pci_scan_bus(&nbus);
  return 1;
}

void
pci_func_enable(struct pci_func *f)
{
  pci_conf_write(f, PCI_COMMAND_STATUS_REG,
                 PCI_COMMAND_IO_ENABLE |
                 PCI_COMMAND_MEM_ENABLE |
                 PCI_COMMAND_MASTER_ENABLE);

  u32 bar_width;
  u32 bar;
  for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
       bar += bar_width)
  {
    u32 oldv = pci_conf_read(f, bar);

    bar_width = 4;
    pci_conf_write(f, bar, 0xffffffff);
    u32 rv = pci_conf_read(f, bar);

    if (rv == 0)
      continue;

    int regnum = PCI_MAPREG_NUM(bar);
    u32 base, size;
    if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
      if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
        bar_width = 8;

      size = PCI_MAPREG_MEM_SIZE(rv);
      base = PCI_MAPREG_MEM_ADDR(oldv);
      if (pci_show_addrs)
        cprintf("  mem region %d: %d bytes at 0x%x\n",
                regnum, size, base);
    } else {
      size = PCI_MAPREG_IO_SIZE(rv);
      base = PCI_MAPREG_IO_ADDR(oldv);
      if (pci_show_addrs)
        cprintf("  io region %d: %d bytes at 0x%x\n",
                regnum, size, base);
    }

    pci_conf_write(f, bar, oldv);
    f->reg_base[regnum] = base;
    f->reg_size[regnum] = size;

    if (size && !base)
      cprintf("PCI device %02x:%02x.%d (%04x:%04x) "
              "may be misconfigured: "
              "region %d: base 0x%x, size %d\n",
              f->bus->busno, f->dev, f->func,
              PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
              regnum, base, size);
  }

  if (VERBOSE)
    cprintf("PCI function %x:%x.%d (%x:%x) enabled\n",
            f->bus->busno, f->dev, f->func,
            PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id));
}

void
initpci(void)
{
  if (!acpi_pci_scan_roots(pci_scan_bus)) {
    // Assume a single root bus
    static struct pci_bus root_bus;
    memset(&root_bus, 0, sizeof(root_bus));

    pci_scan_bus(&root_bus);
  }
}
<|endoftext|>


<commit_before>#include "GLTexture3D.h"
#include "GLTextureRectangle.h"

#include <iostream>
#include "GLUtility.h"

using namespace std;

// ----------------------------------------------------------------------------
GLTexture3D *GLTexture3D::New(int width, int height, int depth,
							  int internalformat, int format, int type,
							  void *data)
{
	// Check if width and height are powers of two
    unsigned int xs = static_cast<unsigned int>(width);
    unsigned int ys = static_cast<unsigned int>(height);
	unsigned int zs = static_cast<unsigned int>(depth);
    if ((xs & (xs - 1)) || (ys & (ys - 1)) || (zs & (zs - 1)))
	{
		// Non-power-of-two sizes, check available extensions
		if (GLEW_ARB_texture_non_power_of_two)
		{
			cout << "GLTexture: sizes are not powers of two, creating NPOTS texture" << endl;
			GLTexture3D *tex = new GLTexture3D(width, height, depth, internalformat);
			if (!tex->Allocate(format, type, data))
			{
				delete tex;
				return 0;
			}
			return tex;
		}
		cerr << "GLTexture: non-power-of-two sized textures not supported" << endl;
		return 0;
	}
	else
	{
		// Create a normal texture
		GLTexture3D *tex = new GLTexture3D(width, height, depth, internalformat);
		if (!tex->Allocate(format, type, data))
		{
			delete tex;
			return 0;
		}
		return tex;
	}
}

// ----------------------------------------------------------------------------
GLTexture3D::GLTexture3D(int width, int height, int depth, int internalformat)
: GLTexture(width, height, internalformat), depth(depth)
{
	//cout << "GLTexture3D: Constructor" << endl;
}

// ----------------------------------------------------------------------------
GLTexture3D::~GLTexture3D()
{
	//cout << "GLTexture3D: Destructor" << endl;
}

// ----------------------------------------------------------------------------
bool GLTexture3D::Allocate(int format, int type, void *data)
{
	//cout << "GLTexture3D: Allocate" << endl;
	// Store old binding to avoid messing up the state
	glPushAttrib(GL_TEXTURE_BIT);

	// Store new params
	this->dataformat = format;
	this->datatype = type;

	BindToCurrent();

	// Set texture object parameters
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );

	// Try a proxy allocation to check available memory and parameters
	glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat,
		width, height, depth, 0, format, type, data);
	GLint w;
	glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &w);

	GLUtility::CheckOpenGLError("GLTexture3D: Allocate() - proxy allocation");

	bool eflag = GLUtility::GetErrorFlag();
	if (w == 0 || eflag)
	{
		cerr << "GLTexture3D: Proxy allocation failed, may be out of video memory" << endl;
		UnbindCurrent();
		glPopAttrib();
		return false;
	}

	// Allocate the texture
	glTexImage3D(GetTextureTarget(), 0, internalformat,
		width, height, depth, 0, format, type, data);
	GLUtility::CheckOpenGLError("GLTexture3D: Allocate - glTexImage3D");

	UnbindCurrent();
	glPopAttrib();

	if (GLUtility::GetErrorFlag())
	{
		cerr << "GLTexture3D: An OpenGL error occurred while allocating the texture" << endl;
		GLUtility::ClearOpenGLError();
		return false;
	}

	return true;
}
<commit_msg>Whitespace cleanup.<commit_after>#include "GLTexture3D.h"
#include "GLTextureRectangle.h"

#include <iostream>
#include "GLUtility.h"

using namespace std;

// ----------------------------------------------------------------------------
GLTexture3D *GLTexture3D::New(int width, int height, int depth,
							  int internalformat, int format, int type,
							  void *data)
{
	// Check if width and height are powers of two
    unsigned int xs = static_cast<unsigned int>(width);
    unsigned int ys = static_cast<unsigned int>(height);
	unsigned int zs = static_cast<unsigned int>(depth);
    if ((xs & (xs - 1)) || (ys & (ys - 1)) || (zs & (zs - 1)))
	{
		// Non-power-of-two sizes, check available extensions
		if (GLEW_ARB_texture_non_power_of_two)
		{
			cout << "GLTexture: sizes are not powers of two, creating NPOTS texture" << endl;
			GLTexture3D *tex = new GLTexture3D(width, height, depth, internalformat);
			if (!tex->Allocate(format, type, data))
			{
				delete tex;
				return 0;
			}
			return tex;
		}
		cerr << "GLTexture: non-power-of-two sized textures not supported" << endl;
		return 0;
	}
	else
	{
		// Create a normal texture
		GLTexture3D *tex = new GLTexture3D(width, height, depth, internalformat);
		if (!tex->Allocate(format, type, data))
		{
			delete tex;
			return 0;
		}
		return tex;
	}
}

// ----------------------------------------------------------------------------
GLTexture3D::GLTexture3D(int width, int height, int depth, int internalformat)
: GLTexture(width, height, internalformat), depth(depth)
{
	//cout << "GLTexture3D: Constructor" << endl;
}

// ----------------------------------------------------------------------------
GLTexture3D::~GLTexture3D()
{
	//cout << "GLTexture3D: Destructor" << endl;
}

// ----------------------------------------------------------------------------
bool GLTexture3D::Allocate(int format, int type, void *data)
{
	//cout << "GLTexture3D: Allocate" << endl;
	// Store old binding to avoid messing up the state
	glPushAttrib(GL_TEXTURE_BIT);

	// Store new params
	this->dataformat = format;
	this->datatype = type;

	BindToCurrent();

	// Set texture object parameters
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GetTextureTarget(), GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

	// Try a proxy allocation to check available memory and parameters
	glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat,
		width, height, depth, 0, format, type, data);
	GLint w;
	glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &w);

	GLUtility::CheckOpenGLError("GLTexture3D: Allocate() - proxy allocation");

	bool eflag = GLUtility::GetErrorFlag();
	if (w == 0 || eflag)
	{
		cerr << "GLTexture3D: Proxy allocation failed, may be out of video memory" << endl;
		UnbindCurrent();
		glPopAttrib();
		return false;
	}

	// Allocate the texture
	glTexImage3D(GetTextureTarget(), 0, internalformat,
		width, height, depth, 0, format, type, data);
	GLUtility::CheckOpenGLError("GLTexture3D: Allocate - glTexImage3D");

	UnbindCurrent();
	glPopAttrib();

	if (GLUtility::GetErrorFlag())
	{
		cerr << "GLTexture3D: An OpenGL error occurred while allocating the texture" << endl;
		GLUtility::ClearOpenGLError();
		return false;
	}

	return true;
}
<|endoftext|>


<commit_before>#include "TimerWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  void
  TimerWrapper::initialize(IOWorkLoop *_workLoop, OSObject *owner, IOTimerEventSource::Action func)
  {
    if (timer) terminate();

    if (! _workLoop) return;

    workLoop = _workLoop;
    if (owner == NULL) {
      owner = reinterpret_cast<OSObject *>(this);
    }
    timer = IOTimerEventSource::timerEventSource(owner, func);

    if (workLoop->addEventSource(timer) != kIOReturnSuccess) {
      timer->release();
      timer = NULL;
    }
  }

  void
  TimerWrapper::terminate(void)
  {
    if (timer) {
      timer->cancelTimeout();
      if (workLoop) {
        workLoop->removeEventSource(timer);
      }
      timer->release();
      timer = NULL;
    }
    workLoop = NULL;
  }
}
<commit_msg>update kext<commit_after>#include "TimerWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  void
  TimerWrapper::initialize(IOWorkLoop *_workLoop, OSObject *owner, IOTimerEventSource::Action func)
  {
    if (timer) terminate();

    if (! _workLoop) return;

    workLoop = _workLoop;
    if (owner == NULL) {
      owner = reinterpret_cast<OSObject *>(this);
    }
    timer = IOTimerEventSource::timerEventSource(owner, func);

    if (workLoop->addEventSource(timer) != kIOReturnSuccess) {
      IOLog("[KeyRemap4MacBook ERROR] TimerWrapper addEventSource failed\n");
      timer->release();
      timer = NULL;
    }
  }

  void
  TimerWrapper::terminate(void)
  {
    if (timer) {
      timer->cancelTimeout();
      if (workLoop) {
        workLoop->removeEventSource(timer);
      }
      timer->release();
      timer = NULL;
    }
    workLoop = NULL;
  }
}
<|endoftext|>


<commit_before>// Copyright 2016 ct_common authors. See LICENSE file for details.

#include "ct_common/common/constraint_a_binary_instances.h"

#include "ct_common/base/arithmetic_utils.h"

namespace ct_common {

#define CONSTRAINT_A_BINARY_SKELETON(CLASS_NAME, OP_TOKEN, EVAL_FUNC)   \
  REGISTER_CLASS_NAME(CLASS_NAME);                                      \
                                                                        \
  CLASS_NAME::CLASS_NAME() = default;                                   \
                                                                        \
  CLASS_NAME::~CLASS_NAME() = default;                                  \
                                                                        \
  bool CLASS_NAME::EvaluateIntInternal(                                 \
      int loprd_val, int roprd_val) const {                             \
    return EVAL_FUNC(loprd_val, roprd_val, precision_);                 \
  }                                                                     \
                                                                        \
  bool CLASS_NAME::EvaluateDoubleInternal(                              \
      double loprd_val, double roprd_val) const {                       \
    return EVAL_FUNC(loprd_val, roprd_val, precision_);                 \
  }                                                                     \
                                                                        \
  std::string CLASS_NAME::GetOpToken() const {                          \
    return OP_TOKEN;                                                    \
  }

#include "ct_common/common/constraint_a_binary_instances.inc"

#undef CONSTRAINT_A_BINARY_SKELETON

}  // namespace ct_common
<commit_msg>fixed integer constraints<commit_after>// Copyright 2016 ct_common authors. See LICENSE file for details.

#include "ct_common/common/constraint_a_binary_instances.h"

#include "ct_common/base/arithmetic_utils.h"

namespace ct_common {

#define CONSTRAINT_A_BINARY_SKELETON(CLASS_NAME, OP_TOKEN, EVAL_FUNC)   \
  REGISTER_CLASS_NAME(CLASS_NAME);                                      \
                                                                        \
  CLASS_NAME::CLASS_NAME() = default;                                   \
                                                                        \
  CLASS_NAME::~CLASS_NAME() = default;                                  \
                                                                        \
  bool CLASS_NAME::EvaluateIntInternal(                                 \
      int loprd_val, int roprd_val) const {                             \
    return EVAL_FUNC(loprd_val, roprd_val);                             \
  }                                                                     \
                                                                        \
  bool CLASS_NAME::EvaluateDoubleInternal(                              \
      double loprd_val, double roprd_val) const {                       \
    return EVAL_FUNC(loprd_val, roprd_val, precision_);                 \
  }                                                                     \
                                                                        \
  std::string CLASS_NAME::GetOpToken() const {                          \
    return OP_TOKEN;                                                    \
  }

#include "ct_common/common/constraint_a_binary_instances.inc"

#undef CONSTRAINT_A_BINARY_SKELETON

}  // namespace ct_common
<|endoftext|>