<commit_before>#include <dlfcn.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <map>
#include <functional>
#include <experimental/optional>

#include "History.hpp"
#include "TerminalInfo.hpp"

#define cursor_forward(x) printf("\033[%dC", static_cast<int>(x))
#define cursor_backward(x) printf("\033[%dD", static_cast<int>(x))

// https://www.akkadia.org/drepper/tls.pdf

using namespace yb;

thread_local std::array<char, 1024> lineBuffer;
thread_local auto lineBufferPos = lineBuffer.begin();

thread_local std::string printBuffer;
thread_local std::string::iterator printBufferPos;

thread_local History history;
thread_local History::const_iterator historyPos;

thread_local static char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);
using Char = unsigned char;
using CharOpt = std::experimental::optional<Char>;

CharOpt newlineHandler(Char);
CharOpt tabHandler(Char);
CharOpt backspaceHandler(Char);
CharOpt regularCHarHandler(Char);
CharOpt arrowHandler1(Char);
CharOpt arrowHandler2(Char);
CharOpt arrowHandler3(Char);

thread_local std::map<Char, std::function<CharOpt(Char)>> handlers = {
    {0x06, tabHandler},
    {0x0d, newlineHandler},
    {0x17, newlineHandler}, // TODO: this should delete one word
    {0x1b, arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    for (int i = 0; i < width - pos; i++)
        printf(" ");
    fflush(stdout);
    for (int i = 0; i < width - pos; i++)
        cursor_backward(1);
}

std::string findCompletion(History::const_iterator start, const std::string &pattern) {
    for (auto it = start; it != history.end(); it++) {
        if (it->compare(0, pattern.length(), pattern) == 0) {
            historyPos = it;
            return *it;
        }
    }

    historyPos = history.begin();
    return pattern;
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);

    clearTerminalLine();

    if (offset)
        cursor_forward(offset);
    printf("\e[1;30m%s\e[0m", completion.c_str() + pattern.length());

    cursor_backward(completion.length() - pattern.length() + offset);
    fflush(stdout);
}

CharOpt newlineHandler(Char) {
    lineBuffer.fill(0);
    lineBufferPos = lineBuffer.begin();
    return {};
}

CharOpt backspaceHandler(Char) {
    if (lineBufferPos != lineBuffer.begin()) {
        *(--lineBufferPos) = 0;
    }

    return {};
}

CharOpt regularCharHandler(Char c) {
    *lineBufferPos = c;
    lineBufferPos++;

    printCompletion(history.begin(), 1);

    return {};
}

CharOpt tabHandler(Char) {
    printCompletion(std::next(historyPos, 1), 0);
    return Char{0}; // TODO: this does not seem to work.
}

CharOpt arrowHandler1(Char) {
    arrowIndicator = 1;
    return {};
}

CharOpt arrowHandler2(Char c) {
    if (arrowIndicator == 1) {
        arrowIndicator = 2;
        return {};
    }
    else {
        return regularCharHandler(c);
    }
}

CharOpt arrowHandler3(Char c) {
    CharOpt return_value = {};
    if (arrowIndicator == 2) {
        arrowIndicator = 0;
        try {
            printBuffer = historyPos->substr(lineBufferPos - lineBuffer.begin());
            printBufferPos = printBuffer.begin();
        } catch (...) {
            // FIXME:
        }
    }
    else {
        return_value = regularCharHandler(c);
    }

    return return_value;
}

static unsigned char yebash(unsigned char c) {

    // TODO: uncomment later
    //if (!getenv("YEBASH"))
    //    return;
    history.read(std::string{getenv("HOME")} + "/.bash_history");

    auto handler = handlers[c];

    // TODO(Mrokkk): There would be a problem with processing all escape codes
    // that bash is using (e.g. ctrl+r for history searching, arrows for moving, etc.).
    // It would be thoughtful if we just disable our yebash if any of these codes would
    // occur and reenable it after a newline
    CharOpt cReturned;

    if (handler) {
        cReturned = handler(c);
    }
    else {
        if (c < 0x20) {
            newlineHandler(c);
        }
        else {
            regularCharHandler(c);
        }
    }

    return cReturned.value_or(c);

}

ssize_t read(int fd, void *buf, size_t count) {

    ssize_t returnValue;
    static thread_local ReadSignature realRead = nullptr;

    if (fd == 0) { // TODO: make it look good
        if (printBuffer.length()) {
            // Return printBuffer to bash one char at time
            *reinterpret_cast<char *>(buf) = *printBufferPos;
            *lineBufferPos++ =  *printBufferPos++;
            if (printBufferPos == printBuffer.end()) {
                printBuffer.erase(printBuffer.begin(), printBuffer.end());
            }
            return 1;
        }
    }

    if (!realRead)
        realRead = reinterpret_cast<ReadSignature>(dlsym(RTLD_NEXT, "read"));

    returnValue = realRead(fd, buf, count);

    if (fd == 0 && isatty(fileno(stdin)))
        *reinterpret_cast<unsigned char *>(buf) = yebash(*reinterpret_cast<unsigned char *>(buf));

    return returnValue;
}

<commit_msg>Improve checking if input comes from terminal<commit_after>#include <dlfcn.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <map>
#include <functional>
#include <experimental/optional>

#include "History.hpp"
#include "TerminalInfo.hpp"

#define cursor_forward(x) printf("\033[%dC", static_cast<int>(x))
#define cursor_backward(x) printf("\033[%dD", static_cast<int>(x))

// https://www.akkadia.org/drepper/tls.pdf

using namespace yb;

thread_local std::array<char, 1024> lineBuffer;
thread_local auto lineBufferPos = lineBuffer.begin();

thread_local std::string printBuffer;
thread_local std::string::iterator printBufferPos;

thread_local History history;
thread_local History::const_iterator historyPos;

thread_local static char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);
using Char = unsigned char;
using CharOpt = std::experimental::optional<Char>;

CharOpt newlineHandler(Char);
CharOpt tabHandler(Char);
CharOpt backspaceHandler(Char);
CharOpt regularCHarHandler(Char);
CharOpt arrowHandler1(Char);
CharOpt arrowHandler2(Char);
CharOpt arrowHandler3(Char);

thread_local std::map<Char, std::function<CharOpt(Char)>> handlers = {
    {0x06, tabHandler},
    {0x0d, newlineHandler},
    {0x17, newlineHandler}, // TODO: this should delete one word
    {0x1b, arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    for (int i = 0; i < width - pos; i++)
        printf(" ");
    fflush(stdout);
    for (int i = 0; i < width - pos; i++)
        cursor_backward(1);
}

std::string findCompletion(History::const_iterator start, const std::string &pattern) {
    for (auto it = start; it != history.end(); it++) {
        if (it->compare(0, pattern.length(), pattern) == 0) {
            historyPos = it;
            return *it;
        }
    }

    historyPos = history.begin();
    return pattern;
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);

    clearTerminalLine();

    if (offset)
        cursor_forward(offset);
    printf("\e[1;30m%s\e[0m", completion.c_str() + pattern.length());

    cursor_backward(completion.length() - pattern.length() + offset);
    fflush(stdout);
}

CharOpt newlineHandler(Char) {
    lineBuffer.fill(0);
    lineBufferPos = lineBuffer.begin();
    return {};
}

CharOpt backspaceHandler(Char) {
    if (lineBufferPos != lineBuffer.begin()) {
        *(--lineBufferPos) = 0;
    }

    return {};
}

CharOpt regularCharHandler(Char c) {
    *lineBufferPos = c;
    lineBufferPos++;

    printCompletion(history.begin(), 1);

    return {};
}

CharOpt tabHandler(Char) {
    printCompletion(std::next(historyPos, 1), 0);
    return Char{0}; // TODO: this does not seem to work.
}

CharOpt arrowHandler1(Char) {
    arrowIndicator = 1;
    return {};
}

CharOpt arrowHandler2(Char c) {
    if (arrowIndicator == 1) {
        arrowIndicator = 2;
        return {};
    }
    else {
        return regularCharHandler(c);
    }
}

CharOpt arrowHandler3(Char c) {
    CharOpt return_value = {};
    if (arrowIndicator == 2) {
        arrowIndicator = 0;
        try {
            printBuffer = historyPos->substr(lineBufferPos - lineBuffer.begin());
            printBufferPos = printBuffer.begin();
        } catch (...) {
            // FIXME:
        }
    }
    else {
        return_value = regularCharHandler(c);
    }

    return return_value;
}

static unsigned char yebash(unsigned char c) {

    // TODO: uncomment later
    //if (!getenv("YEBASH"))
    //    return;
    history.read(std::string{getenv("HOME")} + "/.bash_history");

    auto handler = handlers[c];

    // TODO(Mrokkk): There would be a problem with processing all escape codes
    // that bash is using (e.g. ctrl+r for history searching, arrows for moving, etc.).
    // It would be thoughtful if we just disable our yebash if any of these codes would
    // occur and reenable it after a newline
    CharOpt cReturned;

    if (handler) {
        cReturned = handler(c);
    }
    else {
        if (c < 0x20) {
            newlineHandler(c);
        }
        else {
            regularCharHandler(c);
        }
    }

    return cReturned.value_or(c);

}

static inline bool is_terminal_input(int fd) {
    return isatty(fd);
}

ssize_t read(int fd, void *buf, size_t count) {

    ssize_t returnValue;
    static thread_local ReadSignature realRead = nullptr;

    if (is_terminal_input(fd)) { // TODO: make it look good
        if (printBuffer.length()) {
            // Return printBuffer to bash one char at time
            *reinterpret_cast<char *>(buf) = *printBufferPos;
            *lineBufferPos++ =  *printBufferPos++;
            if (printBufferPos == printBuffer.end()) {
                printBuffer.erase(printBuffer.begin(), printBuffer.end());
            }
            return 1;
        }
    }

    if (!realRead)
        realRead = reinterpret_cast<ReadSignature>(dlsym(RTLD_NEXT, "read"));

    returnValue = realRead(fd, buf, count);

    if (is_terminal_input(fd))
        *reinterpret_cast<unsigned char *>(buf) = yebash(*reinterpret_cast<unsigned char *>(buf));

    return returnValue;
}

<|endoftext|>


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

// Navigates the browser to server and client redirect pages and makes sure
// that the correct redirects are reflected in the history database. Errors
// here might indicate that WebKit changed the calls our glue layer gets in
// the case of redirects. It may also mean problems with the history system.

#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "ui/base/events.h"

namespace {

class RedirectTest : public UITest {
 public:
  RedirectTest()
      : test_server_(net::TestServer::TYPE_HTTP,
                     FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
  }

 protected:
  net::TestServer test_server_;
};

// Tests a single server redirect
TEST_F(RedirectTest, Server) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec());

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests a single client redirect.
TEST_F(RedirectTest, Client) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + final_url.spec());

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());

  // The address bar should display the final URL.
  GURL tab_url;
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);

  // Navigate one more time.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  // The address bar should still display the final URL.
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);
}

// http://code.google.com/p/chromium/issues/detail?id=62772
TEST_F(RedirectTest, FLAKY_ClientEmptyReferer) {
  ASSERT_TRUE(test_server_.Start());

  // Create the file contents, which will do a redirect to the
  // test server.
  GURL final_url = test_server_.GetURL(std::string());
  ASSERT_TRUE(final_url.is_valid());
  std::string file_redirect_contents = StringPrintf(
      ""
      ""
      ""
      "",
      final_url.spec().c_str());

  // Write the contents to a temporary file.
  ScopedTempDir temp_directory;
  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
  FilePath temp_file;
  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
                                                  &temp_file));
  ASSERT_EQ(static_cast<int>(file_redirect_contents.size()),
            file_util::WriteFile(temp_file,
                                 file_redirect_contents.data(),
                                 file_redirect_contents.size()));

  // Navigate to the file through the browser. The client redirect will appear
  // as two page visits in the browser.
  GURL first_url = net::FilePathToFileURL(temp_file);
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  std::vector<GURL> redirects;
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests to make sure a location change when a pending redirect exists isn't
// flagged as a redirect.
#if defined(USE_AURA)
// http://crbug.com/104396
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#elif defined(OS_MACOSX)
// SimulateOSClick is broken on the Mac: http://crbug.com/45162
#define MAYBE_ClientCancelled DISABLED_ClientCancelled
#elif defined(OS_WIN)
// http://crbug.com/53091
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#else
#define MAYBE_ClientCancelled ClientCancelled
#endif

TEST_F(RedirectTest, MAYBE_ClientCancelled) {
  FilePath first_path(test_data_directory_);
  first_path = first_path.AppendASCII("cancelled_redirect_test.html");
  ASSERT_TRUE(file_util::AbsolutePath(&first_path));
  GURL first_url = net::FilePathToFileURL(first_path);

  NavigateToURLBlockUntilNavigationsComplete(first_url, 1);

  scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
  ASSERT_TRUE(browser.get());
  scoped_refptr<WindowProxy> window = browser->GetWindow();
  ASSERT_TRUE(window.get());
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  int64 last_nav_time = 0;
  EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time));
  // Simulate a click to force to make a user-initiated location change;
  // otherwise, a non user-initiated in-page location change will be treated
  // as client redirect and the redirect will be recoreded, which can cause
  // this test failed.
  gfx::Rect tab_view_bounds;
  ASSERT_TRUE(browser->BringToFront());
  ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds,
                                    true));
  ASSERT_TRUE(window->SimulateOSClick(tab_view_bounds.CenterPoint(),
                                      ui::EF_LEFT_MOUSE_BUTTON));
  EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time));

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  // There should be no redirects from first_url, because the anchor location
  // change that occurs should not be flagged as a redirect and the meta-refresh
  // won't have fired yet.
  ASSERT_EQ(0U, redirects.size());
  GURL current_url;
  ASSERT_TRUE(tab_proxy->GetCurrentURL(&current_url));

  // Need to test final path and ref separately since constructing a file url
  // containing an anchor using FilePathToFileURL will escape the anchor as
  // %23, but in current_url the anchor will be '#'.
  std::string final_ref = "myanchor";
  FilePath current_path;
  ASSERT_TRUE(net::FileURLToFilePath(current_url, &current_path));
  ASSERT_TRUE(file_util::AbsolutePath(&current_path));
  // Path should remain unchanged.
  EXPECT_EQ(StringToLowerASCII(first_path.value()),
            StringToLowerASCII(current_path.value()));
  EXPECT_EQ(final_ref, current_url.ref());
}

// Tests a client->server->server redirect
TEST_F(RedirectTest, ClientServerServer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL next_to_last = test_server_.GetURL(
      "server-redirect?" + final_url.spec());
  GURL second_url = test_server_.GetURL(
      "server-redirect?" + next_to_last.spec());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + second_url.spec());
  std::vector<GURL> redirects;

  // We need the sleep for the client redirects, because it appears as two
  // page visits in the browser.
  NavigateToURL(first_url);

  for (int i = 0; i < 10; ++i) {
    base::PlatformThread::Sleep(TestTimeouts::action_timeout());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
    if (!redirects.empty())
      break;
  }

  ASSERT_EQ(3U, redirects.size());
  EXPECT_EQ(second_url.spec(), redirects[0].spec());
  EXPECT_EQ(next_to_last.spec(), redirects[1].spec());
  EXPECT_EQ(final_url.spec(), redirects[2].spec());
}

// Tests that the "#reference" gets preserved across server redirects.
TEST_F(RedirectTest, ServerReference) {
  ASSERT_TRUE(test_server_.Start());

  const std::string ref("reference");

  GURL final_url = test_server_.GetURL(std::string());
  GURL initial_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec() + "#" + ref);

  NavigateToURL(initial_url);

  GURL url = GetActiveTabURL();
  EXPECT_EQ(ref, url.ref());
}

// Test that redirect from http:// to file:// :
// A) does not crash the browser or confuse the redirect chain, see bug 1080873
// B) does not take place.
//
// Flaky on XP and Vista, http://crbug.com/69390.
TEST_F(RedirectTest, FLAKY_NoHttpToFile) {
  ASSERT_TRUE(test_server_.Start());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("http_to_file.html");
  GURL file_url = net::FilePathToFileURL(test_file);

  GURL initial_url = test_server_.GetURL(
      "client-redirect?" + file_url.spec());

  NavigateToURL(initial_url);
  // UITest will check for crashes. We make sure the title doesn't match the
  // title from the file, because the nav should not have taken place.
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  std::wstring actual_title;
  ASSERT_TRUE(tab_proxy->GetTabTitle(&actual_title));
  EXPECT_NE("File!", WideToUTF8(actual_title));
}

// Ensures that non-user initiated location changes (within page) are
// flagged as client redirects. See bug 1139823.
TEST_F(RedirectTest, ClientFragments) {
  ASSERT_TRUE(test_server_.Start());

  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("ref_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);
  std::vector<GURL> redirects;

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  EXPECT_EQ(1U, redirects.size());
  EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
}

// TODO(timsteele): This is disabled because our current testserver can't
// handle multiple requests in parallel, making it hang on the first request
// to /slow?60. It's unable to serve our second request for files/title2.html
// until /slow? completes, which doesn't give the desired behavior. We could
// alternatively load the second page from disk, but we would need to start
// the browser for this testcase with --process-per-tab, and I don't think
// we can do this at test-case-level granularity at the moment.
// http://crbug.com/45056
TEST_F(RedirectTest,
       DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
  // We want to initiate a second navigation after the provisional load for
  // the client redirect destination has started, but before this load is
  // committed. To achieve this, we tell the browser to load a slow page,
  // which causes it to start a provisional load, and while it is waiting
  // for the response (which means it hasn't committed the load for the client
  // redirect destination page yet), we issue a new navigation request.
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL("files/title2.html");
  GURL slow = test_server_.GetURL("slow?60");
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + slow.spec());
  std::vector<GURL> redirects;

  NavigateToURL(first_url);
  // We don't sleep here - the first navigation won't have been committed yet
  // because we told the server to wait a minute. This means the browser has
  // started it's provisional load for the client redirect destination page but
  // hasn't completed. Our time is now!
  NavigateToURL(final_url);

  std::wstring tab_title;
  std::wstring final_url_title = UTF8ToWide("Title Of Awesomeness");
  // Wait till the final page has been loaded.
  for (int i = 0; i < 10; ++i) {
    base::PlatformThread::Sleep(TestTimeouts::action_timeout());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title));
    if (tab_title == final_url_title) {
      ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
      break;
    }
  }

  // Check to make sure the navigation did in fact take place and we are
  // at the expected page.
  EXPECT_EQ(final_url_title, tab_title);

  bool final_navigation_not_redirect = true;
  // Check to make sure our request for files/title2.html doesn't get flagged
  // as a client redirect from the first (/client-redirect?) page.
  for (std::vector<GURL>::iterator it = redirects.begin();
       it != redirects.end(); ++it) {
    if (final_url.spec() == it->spec()) {
      final_navigation_not_redirect = false;
      break;
    }
  }
  EXPECT_TRUE(final_navigation_not_redirect);
}

}  // namespace
<commit_msg>Disable RedirectTest.ClientCancelled on linux.<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.

// Navigates the browser to server and client redirect pages and makes sure
// that the correct redirects are reflected in the history database. Errors
// here might indicate that WebKit changed the calls our glue layer gets in
// the case of redirects. It may also mean problems with the history system.

#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "ui/base/events.h"

namespace {

class RedirectTest : public UITest {
 public:
  RedirectTest()
      : test_server_(net::TestServer::TYPE_HTTP,
                     FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
  }

 protected:
  net::TestServer test_server_;
};

// Tests a single server redirect
TEST_F(RedirectTest, Server) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec());

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests a single client redirect.
TEST_F(RedirectTest, Client) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + final_url.spec());

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());

  // The address bar should display the final URL.
  GURL tab_url;
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);

  // Navigate one more time.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  // The address bar should still display the final URL.
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);
}

// http://code.google.com/p/chromium/issues/detail?id=62772
TEST_F(RedirectTest, FLAKY_ClientEmptyReferer) {
  ASSERT_TRUE(test_server_.Start());

  // Create the file contents, which will do a redirect to the
  // test server.
  GURL final_url = test_server_.GetURL(std::string());
  ASSERT_TRUE(final_url.is_valid());
  std::string file_redirect_contents = StringPrintf(
      ""
      ""
      ""
      "",
      final_url.spec().c_str());

  // Write the contents to a temporary file.
  ScopedTempDir temp_directory;
  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
  FilePath temp_file;
  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
                                                  &temp_file));
  ASSERT_EQ(static_cast<int>(file_redirect_contents.size()),
            file_util::WriteFile(temp_file,
                                 file_redirect_contents.data(),
                                 file_redirect_contents.size()));

  // Navigate to the file through the browser. The client redirect will appear
  // as two page visits in the browser.
  GURL first_url = net::FilePathToFileURL(temp_file);
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  std::vector<GURL> redirects;
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests to make sure a location change when a pending redirect exists isn't
// flagged as a redirect.
#if defined(USE_AURA)
// http://crbug.com/104396
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#elif defined(OS_MACOSX)
// SimulateOSClick is broken on the Mac: http://crbug.com/45162
#define MAYBE_ClientCancelled DISABLED_ClientCancelled
#elif defined(OS_WIN)
// http://crbug.com/53091
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#elif defined(OS_LINUX)
// SimulateOSClick is broken on the Linux: http://crbug.com/113958
#define MAYBE_ClientCancelled DISABLED_ClientCancelled
#else
#define MAYBE_ClientCancelled ClientCancelled
#endif

TEST_F(RedirectTest, MAYBE_ClientCancelled) {
  FilePath first_path(test_data_directory_);
  first_path = first_path.AppendASCII("cancelled_redirect_test.html");
  ASSERT_TRUE(file_util::AbsolutePath(&first_path));
  GURL first_url = net::FilePathToFileURL(first_path);

  NavigateToURLBlockUntilNavigationsComplete(first_url, 1);

  scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
  ASSERT_TRUE(browser.get());
  scoped_refptr<WindowProxy> window = browser->GetWindow();
  ASSERT_TRUE(window.get());
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  int64 last_nav_time = 0;
  EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time));
  // Simulate a click to force to make a user-initiated location change;
  // otherwise, a non user-initiated in-page location change will be treated
  // as client redirect and the redirect will be recoreded, which can cause
  // this test failed.
  gfx::Rect tab_view_bounds;
  ASSERT_TRUE(browser->BringToFront());
  ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds,
                                    true));
  ASSERT_TRUE(window->SimulateOSClick(tab_view_bounds.CenterPoint(),
                                      ui::EF_LEFT_MOUSE_BUTTON));
  EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time));

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  // There should be no redirects from first_url, because the anchor location
  // change that occurs should not be flagged as a redirect and the meta-refresh
  // won't have fired yet.
  ASSERT_EQ(0U, redirects.size());
  GURL current_url;
  ASSERT_TRUE(tab_proxy->GetCurrentURL(&current_url));

  // Need to test final path and ref separately since constructing a file url
  // containing an anchor using FilePathToFileURL will escape the anchor as
  // %23, but in current_url the anchor will be '#'.
  std::string final_ref = "myanchor";
  FilePath current_path;
  ASSERT_TRUE(net::FileURLToFilePath(current_url, &current_path));
  ASSERT_TRUE(file_util::AbsolutePath(&current_path));
  // Path should remain unchanged.
  EXPECT_EQ(StringToLowerASCII(first_path.value()),
            StringToLowerASCII(current_path.value()));
  EXPECT_EQ(final_ref, current_url.ref());
}

// Tests a client->server->server redirect
TEST_F(RedirectTest, ClientServerServer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL next_to_last = test_server_.GetURL(
      "server-redirect?" + final_url.spec());
  GURL second_url = test_server_.GetURL(
      "server-redirect?" + next_to_last.spec());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + second_url.spec());
  std::vector<GURL> redirects;

  // We need the sleep for the client redirects, because it appears as two
  // page visits in the browser.
  NavigateToURL(first_url);

  for (int i = 0; i < 10; ++i) {
    base::PlatformThread::Sleep(TestTimeouts::action_timeout());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
    if (!redirects.empty())
      break;
  }

  ASSERT_EQ(3U, redirects.size());
  EXPECT_EQ(second_url.spec(), redirects[0].spec());
  EXPECT_EQ(next_to_last.spec(), redirects[1].spec());
  EXPECT_EQ(final_url.spec(), redirects[2].spec());
}

// Tests that the "#reference" gets preserved across server redirects.
TEST_F(RedirectTest, ServerReference) {
  ASSERT_TRUE(test_server_.Start());

  const std::string ref("reference");

  GURL final_url = test_server_.GetURL(std::string());
  GURL initial_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec() + "#" + ref);

  NavigateToURL(initial_url);

  GURL url = GetActiveTabURL();
  EXPECT_EQ(ref, url.ref());
}

// Test that redirect from http:// to file:// :
// A) does not crash the browser or confuse the redirect chain, see bug 1080873
// B) does not take place.
//
// Flaky on XP and Vista, http://crbug.com/69390.
TEST_F(RedirectTest, FLAKY_NoHttpToFile) {
  ASSERT_TRUE(test_server_.Start());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("http_to_file.html");
  GURL file_url = net::FilePathToFileURL(test_file);

  GURL initial_url = test_server_.GetURL(
      "client-redirect?" + file_url.spec());

  NavigateToURL(initial_url);
  // UITest will check for crashes. We make sure the title doesn't match the
  // title from the file, because the nav should not have taken place.
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  std::wstring actual_title;
  ASSERT_TRUE(tab_proxy->GetTabTitle(&actual_title));
  EXPECT_NE("File!", WideToUTF8(actual_title));
}

// Ensures that non-user initiated location changes (within page) are
// flagged as client redirects. See bug 1139823.
TEST_F(RedirectTest, ClientFragments) {
  ASSERT_TRUE(test_server_.Start());

  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("ref_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);
  std::vector<GURL> redirects;

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  EXPECT_EQ(1U, redirects.size());
  EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
}

// TODO(timsteele): This is disabled because our current testserver can't
// handle multiple requests in parallel, making it hang on the first request
// to /slow?60. It's unable to serve our second request for files/title2.html
// until /slow? completes, which doesn't give the desired behavior. We could
// alternatively load the second page from disk, but we would need to start
// the browser for this testcase with --process-per-tab, and I don't think
// we can do this at test-case-level granularity at the moment.
// http://crbug.com/45056
TEST_F(RedirectTest,
       DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
  // We want to initiate a second navigation after the provisional load for
  // the client redirect destination has started, but before this load is
  // committed. To achieve this, we tell the browser to load a slow page,
  // which causes it to start a provisional load, and while it is waiting
  // for the response (which means it hasn't committed the load for the client
  // redirect destination page yet), we issue a new navigation request.
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL("files/title2.html");
  GURL slow = test_server_.GetURL("slow?60");
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + slow.spec());
  std::vector<GURL> redirects;

  NavigateToURL(first_url);
  // We don't sleep here - the first navigation won't have been committed yet
  // because we told the server to wait a minute. This means the browser has
  // started it's provisional load for the client redirect destination page but
  // hasn't completed. Our time is now!
  NavigateToURL(final_url);

  std::wstring tab_title;
  std::wstring final_url_title = UTF8ToWide("Title Of Awesomeness");
  // Wait till the final page has been loaded.
  for (int i = 0; i < 10; ++i) {
    base::PlatformThread::Sleep(TestTimeouts::action_timeout());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title));
    if (tab_title == final_url_title) {
      ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
      break;
    }
  }

  // Check to make sure the navigation did in fact take place and we are
  // at the expected page.
  EXPECT_EQ(final_url_title, tab_title);

  bool final_navigation_not_redirect = true;
  // Check to make sure our request for files/title2.html doesn't get flagged
  // as a client redirect from the first (/client-redirect?) page.
  for (std::vector<GURL>::iterator it = redirects.begin();
       it != redirects.end(); ++it) {
    if (final_url.spec() == it->spec()) {
      final_navigation_not_redirect = false;
      break;
    }
  }
  EXPECT_TRUE(final_navigation_not_redirect);
}

}  // namespace
<|endoftext|>


<commit_before>//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines a set of flow-insensitive security checks.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {
class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
  BugReporter &BR;
  IdentifierInfo *II_gets;
  enum { num_ids = 6 };
  IdentifierInfo *II_setid[num_ids];

public:
  WalkAST(BugReporter &br) : BR(br),
    II_gets(0), II_setid() {}

  // Statement visitor methods.
  void VisitCallExpr(CallExpr *CE);
  void VisitForStmt(ForStmt *S);
  void VisitCompoundStmt (CompoundStmt *S);
  void VisitStmt(Stmt *S) { VisitChildren(S); }

  void VisitChildren(Stmt *S);

  // Helpers.
  IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);

  // Checker-specific methods.
  void CheckLoopConditionForFloat(const ForStmt *FS);
  void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
  void CheckUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Helper methods.
//===----------------------------------------------------------------------===//

IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
  if (!II)
    II = &BR.getContext().Idents.get(str);

  return II;
}

//===----------------------------------------------------------------------===//
// AST walking.
//===----------------------------------------------------------------------===//

void WalkAST::VisitChildren(Stmt *S) {
  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    if (Stmt *child = *I)
      Visit(child);
}

void WalkAST::VisitCallExpr(CallExpr *CE) {
  if (const FunctionDecl *FD = CE->getDirectCallee()) {
    CheckCall_gets(CE, FD);
  }

  // Recurse and check children.
  VisitChildren(CE);
}

void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    if (Stmt *child = *I)
      {
	if (CallExpr *CE = dyn_cast<CallExpr>(child))
	  CheckUncheckedReturnValue(CE);
	Visit(child);
      }
}

void WalkAST::VisitForStmt(ForStmt *FS) {
  CheckLoopConditionForFloat(FS);

  // Recurse and check children.
  VisitChildren(FS);
}

//===----------------------------------------------------------------------===//
// Check: floating poing variable used as loop counter.
// Originally: <rdar://problem/6336718>
// Implements: CERT security coding advisory FLP-30.
//===----------------------------------------------------------------------===//

static const DeclRefExpr*
GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
  expr = expr->IgnoreParenCasts();

  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
    if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
          B->getOpcode() == BinaryOperator::Comma))
      return NULL;

    if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
      return lhs;

    if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
      return rhs;

    return NULL;
  }

  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
    const NamedDecl *ND = DR->getDecl();
    return ND == x || ND == y ? DR : NULL;
  }

  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
    return U->isIncrementDecrementOp()
      ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;

  return NULL;
}

/// CheckLoopConditionForFloat - This check looks for 'for' statements that
///  use a floating point variable as a loop counter.
///  CERT: FLP30-C, FLP30-CPP.
///
void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
  // Does the loop have a condition?
  const Expr *condition = FS->getCond();

  if (!condition)
    return;

  // Does the loop have an increment?
  const Expr *increment = FS->getInc();

  if (!increment)
    return;

  // Strip away '()' and casts.
  condition = condition->IgnoreParenCasts();
  increment = increment->IgnoreParenCasts();

  // Is the loop condition a comparison?
  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);

  if (!B)
    return;

  // Is this a comparison?
  if (!(B->isRelationalOp() || B->isEqualityOp()))
    return;

  // Are we comparing variables?
  const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
  const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());

  // Does at least one of the variables have a floating point type?
  drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL;
  drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL;

  if (!drLHS && !drRHS)
    return;

  const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
  const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;

  if (!vdLHS && !vdRHS)
    return;

  // Does either variable appear in increment?
  const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);

  if (!drInc)
    return;

  // Emit the error.  First figure out which DeclRefExpr in the condition
  // referenced the compared variable.
  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;

  llvm::SmallVector<SourceRange, 2> ranges;
  std::string sbuf;
  llvm::raw_string_ostream os(sbuf);

  os << "Variable '" << drCond->getDecl()->getNameAsCString()
     << "' with floating point type '" << drCond->getType().getAsString()
     << "' should not be used as a loop counter";

  ranges.push_back(drCond->getSourceRange());
  ranges.push_back(drInc->getSourceRange());

  const char *bugType = "Floating point variable used as loop counter";
  BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
                     FS->getLocStart(), ranges.data(), ranges.size());
}

//===----------------------------------------------------------------------===//
// Check: Any use of 'gets' is insecure.
// Originally: <rdar://problem/6335715>
// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
//===----------------------------------------------------------------------===//

void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
  if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
    return;

  const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
  if (!FTP)
    return;

  // Verify that the function takes a single argument.
  if (FTP->getNumArgs() != 1)
    return;

  // Is the argument a 'char*'?
  const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
  if (!PT)
    return;

  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    return;

  // Issue a warning.
  SourceRange R = CE->getCallee()->getSourceRange();
  BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
                     "Security",
                     "Call to function 'gets' is extremely insecure as it can "
                     "always result in a buffer overflow",
                     CE->getLocStart(), &R, 1);
}

//===----------------------------------------------------------------------===//
// Check: Should check whether privileges are dropped successfully.
// Originally: <rdar://problem/6337132>
//===----------------------------------------------------------------------===//

void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
  const FunctionDecl *FD = CE->getDirectCallee();
  if (!FD)
    return;

  if (II_setid[0] == NULL) {
    static const char * const identifiers[num_ids] = {
      "setuid", "setgid", "seteuid", "setegid",
      "setreuid", "setregid"
    };

    for (size_t i = 0; i < num_ids; i++)
      II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
  }

  const IdentifierInfo *id = FD->getIdentifier();
  size_t identifierid;

  for (identifierid = 0; identifierid < num_ids; identifierid++)
    if (id == II_setid[identifierid])
      break;

  if (identifierid >= num_ids)
    return;

  const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
  if (!FTP)
    return;

  /* Verify that the function takes one or two arguments (depending on
     the function).  */
  if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
    return;

  // The arguments must be integers.
  for (unsigned i = 0; i < FTP->getNumArgs(); i++)
    if (! FTP->getArgType(i)->isIntegerType())
      return;

  // Issue a warning.
  std::string buf1;
  llvm::raw_string_ostream os1(buf1);
  os1 << "Return value is not checked in call to '" << FD->getNameAsString()
     << "'";

  std::string buf2;
  llvm::raw_string_ostream os2(buf2);
  os2 << "The return value from the call to '" << FD->getNameAsString()
      << "' is not checked.  If an error occurs in '"
      << FD->getNameAsString()
      << "', the following code may execute with unexpected privileges";

  SourceRange R = CE->getCallee()->getSourceRange();

  BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
                     CE->getLocStart(), &R, 1);
}

//===----------------------------------------------------------------------===//
// Entry point for check.
//===----------------------------------------------------------------------===//

void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
  WalkAST walker(BR);
  walker.Visit(D->getBody());
}
<commit_msg>Use C++ style comments.<commit_after>//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines a set of flow-insensitive security checks.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {
class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
  BugReporter &BR;
  IdentifierInfo *II_gets;
  enum { num_ids = 6 };
  IdentifierInfo *II_setid[num_ids];

public:
  WalkAST(BugReporter &br) : BR(br),
    II_gets(0), II_setid() {}

  // Statement visitor methods.
  void VisitCallExpr(CallExpr *CE);
  void VisitForStmt(ForStmt *S);
  void VisitCompoundStmt (CompoundStmt *S);
  void VisitStmt(Stmt *S) { VisitChildren(S); }

  void VisitChildren(Stmt *S);

  // Helpers.
  IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);

  // Checker-specific methods.
  void CheckLoopConditionForFloat(const ForStmt *FS);
  void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
  void CheckUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Helper methods.
//===----------------------------------------------------------------------===//

IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
  if (!II)
    II = &BR.getContext().Idents.get(str);

  return II;
}

//===----------------------------------------------------------------------===//
// AST walking.
//===----------------------------------------------------------------------===//

void WalkAST::VisitChildren(Stmt *S) {
  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    if (Stmt *child = *I)
      Visit(child);
}

void WalkAST::VisitCallExpr(CallExpr *CE) {
  if (const FunctionDecl *FD = CE->getDirectCallee()) {
    CheckCall_gets(CE, FD);
  }

  // Recurse and check children.
  VisitChildren(CE);
}

void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    if (Stmt *child = *I)
      {
	if (CallExpr *CE = dyn_cast<CallExpr>(child))
	  CheckUncheckedReturnValue(CE);
	Visit(child);
      }
}

void WalkAST::VisitForStmt(ForStmt *FS) {
  CheckLoopConditionForFloat(FS);

  // Recurse and check children.
  VisitChildren(FS);
}

//===----------------------------------------------------------------------===//
// Check: floating poing variable used as loop counter.
// Originally: <rdar://problem/6336718>
// Implements: CERT security coding advisory FLP-30.
//===----------------------------------------------------------------------===//

static const DeclRefExpr*
GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
  expr = expr->IgnoreParenCasts();

  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
    if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
          B->getOpcode() == BinaryOperator::Comma))
      return NULL;

    if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
      return lhs;

    if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
      return rhs;

    return NULL;
  }

  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
    const NamedDecl *ND = DR->getDecl();
    return ND == x || ND == y ? DR : NULL;
  }

  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
    return U->isIncrementDecrementOp()
      ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;

  return NULL;
}

/// CheckLoopConditionForFloat - This check looks for 'for' statements that
///  use a floating point variable as a loop counter.
///  CERT: FLP30-C, FLP30-CPP.
///
void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
  // Does the loop have a condition?
  const Expr *condition = FS->getCond();

  if (!condition)
    return;

  // Does the loop have an increment?
  const Expr *increment = FS->getInc();

  if (!increment)
    return;

  // Strip away '()' and casts.
  condition = condition->IgnoreParenCasts();
  increment = increment->IgnoreParenCasts();

  // Is the loop condition a comparison?
  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);

  if (!B)
    return;

  // Is this a comparison?
  if (!(B->isRelationalOp() || B->isEqualityOp()))
    return;

  // Are we comparing variables?
  const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
  const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());

  // Does at least one of the variables have a floating point type?
  drLHS = drLHS && drLHS->getType()->isFloatingType() ? drLHS : NULL;
  drRHS = drRHS && drRHS->getType()->isFloatingType() ? drRHS : NULL;

  if (!drLHS && !drRHS)
    return;

  const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
  const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;

  if (!vdLHS && !vdRHS)
    return;

  // Does either variable appear in increment?
  const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);

  if (!drInc)
    return;

  // Emit the error.  First figure out which DeclRefExpr in the condition
  // referenced the compared variable.
  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;

  llvm::SmallVector<SourceRange, 2> ranges;
  std::string sbuf;
  llvm::raw_string_ostream os(sbuf);

  os << "Variable '" << drCond->getDecl()->getNameAsCString()
     << "' with floating point type '" << drCond->getType().getAsString()
     << "' should not be used as a loop counter";

  ranges.push_back(drCond->getSourceRange());
  ranges.push_back(drInc->getSourceRange());

  const char *bugType = "Floating point variable used as loop counter";
  BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
                     FS->getLocStart(), ranges.data(), ranges.size());
}

//===----------------------------------------------------------------------===//
// Check: Any use of 'gets' is insecure.
// Originally: <rdar://problem/6335715>
// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
//===----------------------------------------------------------------------===//

void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
  if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
    return;

  const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
  if (!FTP)
    return;

  // Verify that the function takes a single argument.
  if (FTP->getNumArgs() != 1)
    return;

  // Is the argument a 'char*'?
  const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
  if (!PT)
    return;

  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    return;

  // Issue a warning.
  SourceRange R = CE->getCallee()->getSourceRange();
  BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
                     "Security",
                     "Call to function 'gets' is extremely insecure as it can "
                     "always result in a buffer overflow",
                     CE->getLocStart(), &R, 1);
}

//===----------------------------------------------------------------------===//
// Check: Should check whether privileges are dropped successfully.
// Originally: <rdar://problem/6337132>
//===----------------------------------------------------------------------===//

void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
  const FunctionDecl *FD = CE->getDirectCallee();
  if (!FD)
    return;

  if (II_setid[0] == NULL) {
    static const char * const identifiers[num_ids] = {
      "setuid", "setgid", "seteuid", "setegid",
      "setreuid", "setregid"
    };

    for (size_t i = 0; i < num_ids; i++)
      II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
  }

  const IdentifierInfo *id = FD->getIdentifier();
  size_t identifierid;

  for (identifierid = 0; identifierid < num_ids; identifierid++)
    if (id == II_setid[identifierid])
      break;

  if (identifierid >= num_ids)
    return;

  const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
  if (!FTP)
    return;

  // Verify that the function takes one or two arguments (depending on
  //   the function).
  if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
    return;

  // The arguments must be integers.
  for (unsigned i = 0; i < FTP->getNumArgs(); i++)
    if (! FTP->getArgType(i)->isIntegerType())
      return;

  // Issue a warning.
  std::string buf1;
  llvm::raw_string_ostream os1(buf1);
  os1 << "Return value is not checked in call to '" << FD->getNameAsString()
     << "'";

  std::string buf2;
  llvm::raw_string_ostream os2(buf2);
  os2 << "The return value from the call to '" << FD->getNameAsString()
      << "' is not checked.  If an error occurs in '"
      << FD->getNameAsString()
      << "', the following code may execute with unexpected privileges";

  SourceRange R = CE->getCallee()->getSourceRange();

  BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
                     CE->getLocStart(), &R, 1);
}

//===----------------------------------------------------------------------===//
// Entry point for check.
//===----------------------------------------------------------------------===//

void clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
  WalkAST walker(BR);
  walker.Visit(D->getBody());
}
<|endoftext|>


<commit_before>// Copyright  2010-2017 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once

#include "Stdafx.h"
#include "WcfEnabledSubProcess.h"

using namespace System::ServiceModel;

namespace CefSharp
{
    namespace BrowserSubprocess
    {
        void WcfEnabledSubProcess::OnBrowserCreated(CefBrowserWrapper^ browser)
        {
            if (!parentBrowserId.HasValue)
            {
                parentBrowserId = browser->BrowserId;
            }

            if (!parentProcessId.HasValue || !parentBrowserId.HasValue)
            {
                return;
            }

            auto browserId = browser->IsPopup ? parentBrowserId.Value : browser->BrowserId;

            auto serviceName = RenderprocessClientFactory::GetServiceName(parentProcessId.Value, browserId);

            auto binding = BrowserProcessServiceHost::CreateBinding();

            auto channelFactory = gcnew ChannelFactory<IBrowserProcess^>(
                binding,
                gcnew EndpointAddress(serviceName)
                );

            channelFactory->Open();

            auto browserProcess = channelFactory->CreateChannel();
            auto clientChannel = ((IClientChannel^)browserProcess);

            try
            {
                clientChannel->Open();

                browser->ChannelFactory = channelFactory;
                browser->BrowserProcess = browserProcess;
            }
            catch (Exception^)
            {
            }
        }

        void WcfEnabledSubProcess::OnBrowserDestroyed(CefBrowserWrapper^ browser)
        {
            auto channelFactory = browser->ChannelFactory;

            if (channelFactory->State == CommunicationState::Opened)
            {
                channelFactory->Close();
            }

            auto clientChannel = ((IClientChannel^)browser->BrowserProcess);

            if (clientChannel->State == CommunicationState::Opened)
            {
                clientChannel->Close();
            }

            browser->ChannelFactory = nullptr;
            browser->BrowserProcess = nullptr;
        }
    }
}<commit_msg>WcfEnabledSubProcess - Add better error handling when closing the WCF channel/factory<commit_after>// Copyright  2010-2017 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#pragma once

#include "Stdafx.h"
#include "WcfEnabledSubProcess.h"

using namespace System::ServiceModel;

namespace CefSharp
{
    namespace BrowserSubprocess
    {
        void WcfEnabledSubProcess::OnBrowserCreated(CefBrowserWrapper^ browser)
        {
            if (!parentBrowserId.HasValue)
            {
                parentBrowserId = browser->BrowserId;
            }

            if (!parentProcessId.HasValue || !parentBrowserId.HasValue)
            {
                return;
            }

            auto browserId = browser->IsPopup ? parentBrowserId.Value : browser->BrowserId;

            auto serviceName = RenderprocessClientFactory::GetServiceName(parentProcessId.Value, browserId);

            auto binding = BrowserProcessServiceHost::CreateBinding();

            auto channelFactory = gcnew ChannelFactory<IBrowserProcess^>(
                binding,
                gcnew EndpointAddress(serviceName)
                );

            channelFactory->Open();

            auto browserProcess = channelFactory->CreateChannel();
            auto clientChannel = ((IClientChannel^)browserProcess);

            try
            {
                clientChannel->Open();

                browser->ChannelFactory = channelFactory;
                browser->BrowserProcess = browserProcess;
            }
            catch (Exception^)
            {
            }
        }

        void WcfEnabledSubProcess::OnBrowserDestroyed(CefBrowserWrapper^ browser)
        {
            auto channelFactory = browser->ChannelFactory;

            try
            {
                if (channelFactory->State == CommunicationState::Opened)
                {
                    channelFactory->Close();
                }
            }
            catch (Exception^)
            {

                channelFactory->Abort();
            }

            auto clientChannel = ((IClientChannel^)browser->BrowserProcess);

            try
            {
                if (clientChannel->State == CommunicationState::Opened)
                {
                    clientChannel->Close();
                }
            }
            catch (Exception^)
            {
                clientChannel->Abort();
            }

            browser->ChannelFactory = nullptr;
            browser->BrowserProcess = nullptr;
        }
    }
}<|endoftext|>


<commit_before>#include "Poker.h"
#include "../GameObject.h"
#include "../Timer.h"
#include "../Advertisement.h"

Poker::Poker() :
    m_InitialPlayers(4),
    m_InitialMoney(1000),
    m_RoundCounter(1),
    m_PotMoney(0),
    bettingCycle(1),
    player0Frame(20, 16, 38, 7),
    player1Frame(0 ,  9, 38, 7),
    player2Frame(20,  1, 38, 7),
    player3Frame(40,  9, 38, 7),
    m_HumanPlayer(0, m_InitialMoney, "Human"),
    m_AiPlayer_1(1, m_InitialMoney, "West"),
    m_AiPlayer_2(2, m_InitialMoney, "North"),
    m_AiPlayer_3(3, m_InitialMoney, "East"),
    m_Players(),
	GAME_DISPLAY()
{
    m_HumanPlayer.setFrame(&player0Frame);
    m_AiPlayer_1.setFrame(&player1Frame);
    m_AiPlayer_2.setFrame(&player2Frame);
    m_AiPlayer_3.setFrame(&player3Frame);

    m_Players.push_back(&m_AiPlayer_1);
    m_Players.push_back(&m_AiPlayer_2);
    m_Players.push_back(&m_AiPlayer_3);
    m_Players.push_back(&m_HumanPlayer);

    initializeDisplay();
}

Poker::~Poker() {}

void Poker::initializeDisplay() {
    updateGameInfo();
}

void Poker::setTopBannerText(string text) {
    GAME_DISPLAY.bannerTop(text);
}

void Poker::setBottomBannerText(string text) {
    GAME_DISPLAY.bannerBottom(text);
}

void Poker::removePlayer(int position) {
    Frame frame;

    switch (position) {
        case 0:
            frame = player0Frame;
            break;
        case 1:
            frame = player1Frame;
            break;
        case 2:
            frame = player2Frame;
            break;
        case 3:
            frame = player3Frame;
            break;
        default: return;
    }

    GAME_DISPLAY.eraseBox(frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight());
}

void Poker::drawHand(HandD1 *hand, bool hidden, Frame *frame) {
    int x = frame->getX(), y = frame->getY();

    if (hidden) { //top player
        for (int i = 0; i < 5; i++) {
            GAME_DISPLAY.displayCard(x + 1 + i*7, y + 2, 0, 0, 0);
        }
    } else if (hand != NULL) { //display cards for human player
        CardD1 *card;
        for (int i = 0; i < 5; i++) {
            card = hand->getCard(i);
            GAME_DISPLAY.displayCard(x + 1 + i*7, y + 2, card->getSuit() + 1, card->getNumber(), 0);
        }
    }
}

void Poker::updateHand(HandD1 *hand, Frame *frame) {
    if (hand != NULL) {
        GAME_DISPLAY.eraseBox(frame->getX(), frame->getY(), frame->getWidth(), frame->getHeight());
        drawHand(hand, false, frame);
    }
}

//called whenever any player money or pot changes, or when round round or style changes
void Poker::updateGameInfo() {
    stringstream bannerText;
    bannerText << bannerHeader << " || ";
    bannerText << "Me: $" << m_HumanPlayer.getMoney();
    bannerText << " | W: $" << m_AiPlayer_1.getMoney();
    bannerText << " | N: $" << m_AiPlayer_2.getMoney();
    bannerText << " | E: $" << m_AiPlayer_3.getMoney();
    bannerText << " | Pot: $" << m_PotMoney;
    setTopBannerText(bannerText.str());
}

void Poker::rotatePlayers() {
    PlayerD1 *tempPlayer = m_Players.front();
    m_Players.pop_front();
    m_Players.push_back(tempPlayer);
}

void Poker::removeCurrentPlayer() {
    removePlayer(((PlayerD1 *)m_Players.front())->getDisplayPosition());
    m_Players.pop_front();
}

void Poker::runAnte() {
    stringstream bannerText;
	Advertisement adGenerator;
	bannerText << adGenerator.getAd();
    //bannerText << "Round " << m_RoundCounter << ": Ante";
    bannerHeader = bannerText.str();
    updateGameInfo();

    int a = ante();

    for (int i = 0; i < (int)m_Players.size(); i++) {
        PlayerD1 *player = m_Players.front();

        if (typeid(*player) == typeid(HumanPlayer)) {
            HumanPlayer *hPlayer = (HumanPlayer *) player;

            if (hPlayer->ante(a, GAME_DISPLAY) == PlayerD1::FOLD) { //didn't ante, remove human player from game
				m_Players.clear();
                endGame("You didn't ante!? You gotta go. :(");
				return;
            }
        } else {
            AI *cPlayer = (AI *) player;
            if(cPlayer->ante(a, GAME_DISPLAY) == PlayerD1::FOLD) {
                removeCurrentPlayer();
                i--;
                continue;
            }
        }

        m_PotMoney += player->getMoneyInPot();
        updateGameInfo();

        rotatePlayers();
    }
}

void Poker::runDeal() {
    int i;

    for (i = 0; i < rand() %1000; i++)
        m_Deck.shuffle();

    for (i = 0; i < (int)m_Players.size(); i++) {
        CardD1 *c1 = m_Deck.drawCard();
        CardD1 *c2 = m_Deck.drawCard();
        CardD1 *c3 = m_Deck.drawCard();
        CardD1 *c4 = m_Deck.drawCard();
        CardD1 *c5 = m_Deck.drawCard();
        m_Players[i]->setHand( new HandD1(c1, c2, c3, c4, c5) );

        drawHand(NULL, true, m_Players[i]->getFrame());
    }

    updateHand(m_HumanPlayer.getHand(), &player0Frame);
}

void Poker::runBetting(int bettingCycle) {
    stringstream bannerText;
    bannerText << "Round " << m_RoundCounter << ": Betting Cycle " << bettingCycle;
    bannerHeader = bannerText.str();
    updateGameInfo();

    int bet, callCounter = 0, minBet;

    while (unfoldedPlayers() > 1) {
        PlayerD1 *player = m_Players.front();
        minBet = minimumBet(player);

        if (player->folded()) {
            callCounter++;
        } else {
            bet = player->bet(minBet, GAME_DISPLAY);
            callCounter++;

            if (bet != PlayerD1::FOLD) {
                m_PotMoney += bet;
                updateGameInfo();

                if (bet > minBet) {
                    callCounter = 1;
                }
            } else {
                removePlayer(player->getDisplayPosition());
            }
        }

        if (callCounter >= unfoldedPlayers() || allPlayersAllIn())
            break;

        rotatePlayers();
    }
}

int Poker::unfoldedPlayers() {
    int unfolded = 0;

    for (int i = 0; i < (int)m_Players.size(); i++) {
        unfolded += (int) !m_Players[i]->folded();
    }

    return unfolded;
}

int Poker::runCardExchange() {
	int discardCount = 0; //count how many cards the human discards
    stringstream bannerText;
    bannerText << "Round " << m_RoundCounter << ": Betting Cycle " << bettingCycle;
    bannerHeader = bannerText.str();
    updateGameInfo();

    //bringHumanToFront();
    for (int i = 0; i < (int)m_Players.size(); i++) {
        PlayerD1 *player = m_Players.front();

        if (!player->folded()) {
            player->discard(GAME_DISPLAY);

            for (int j = 0; j < 5; j++) {
                if (player->getHand()->getCard(j)->isDiscarded()) {
                    m_Deck.discardCard(player->getHand()->exchange(m_Deck.drawCard(), j));
					discardCount++;
                }
            }

            if (typeid(*player) == typeid(HumanPlayer)) {
                updateHand(player->getHand(), player->getFrame());
            }
        }

        rotatePlayers();
    }

	return discardCount;
}

void Poker::runShowdown() {
    for (int i = 0; i < (int)m_Players.size(); i++) {
        if (m_Players[i]->folded()) {
            removePlayer(m_Players[i]->getDisplayPosition());
        } else {
            updateHand(m_Players[i]->getHand(), m_Players[i]->getFrame());
        }
    }
}

bool Poker::roundIsOver() {
    if (m_Players.size() <= 1) return true;

    PlayerD1 *winner;

    if (unfoldedPlayers() == 1) {
        for (int i = 0; i < (int)m_Players.size(); i++) {
            if (!m_Players[i]->folded()) {
                winner = m_Players[i];
                break;
            }
        }
        winner->giveMoney(m_PotMoney);
        setBottomBannerText("Round over. <Press c to continue>");
        finalizeRound();
        return true;
    }

    return false;
}

int Poker::getRemainingPotMoney(){
    int sum = 0;
    for(int i = 0; i < (int)m_Players.size(); i++){
        sum += m_Players[i]->getMoneyInPot();
    }
    return sum;
}

bool Poker::finishRound() {

    PlayerD1* winner = NULL;
    int *score;

    for(int i = 0; i < (int)m_Players.size(); i++){
        if (!m_Players[i]->folded() && m_Players[i]->getMoneyInPot() > 0) {
            if (winner == NULL) {
                winner = m_Players[i];
                score = winner->getHand()->getScore();
            } else if (m_Players[i]->getHand()->isHigherScore(score)) {
                winner = m_Players[i];
                score = winner->getHand()->getScore();
            }
        }
    }

    string outcome = (&m_HumanPlayer != winner )?"You lost :(":"You Win :)";

    stringstream bannerText;
    bannerText << outcome << "; c: continue";
    setBottomBannerText(bannerText.str());

    while(getRemainingPotMoney() > 0){
        winner = NULL;
        int *highscore;

        //Determine the winningest player with non-zero pot money left
        for(int i = 0; i < (int)m_Players.size(); i++){
            if (!m_Players[i]->folded() && m_Players[i]->getMoneyInPot() > 0) {
                if (winner == NULL) {
                    winner = m_Players[i];
                    highscore = winner->getHand()->getScore();
                } else if (m_Players[i]->getHand()->isHigherScore(highscore)) {
                    winner = m_Players[i];
                    highscore = winner->getHand()->getScore();
                }
            }
        }

        //Add money to the bank
        for (int i = 0; i < (int)m_Players.size(); i++) {
            winner->giveMoney(min(winner->getMoneyInPot(), m_Players[i]->getMoneyInPot()));
        }

        vector<int> tmpPotMoney(m_Players.size());
        int winnerPotMoney = winner->getMoneyInPot();

        for (int i = 0; i < (int)m_Players.size(); i++) {
            tmpPotMoney[i] = m_Players[i]->getMoneyInPot();
        }

        //Updates remaining money in the pot
        for (int i = 0; i < (int)m_Players.size(); i++) {
            m_Players[i]->setMoneyInPot(max(tmpPotMoney[i] - winnerPotMoney, 0));
        }
    }

    finalizeRound();
    return true;
}

void Poker::finalizeRound() {
    for (int i = 0; i < (int)m_Players.size(); i++) {
        m_Players[i]->setMoneyInPot(0);
    }

    bettingCycle++;

    m_PotMoney = 0;
    bannerHeader = "";
    updateGameInfo();

    int input;
    while (1) {
        input = GAME_DISPLAY.captureInput();
        if (input == 'c' || input == 'C') {
            break;
        }
    }

    HandD1 *hand;
    for (int i = 0; i < (int)m_Players.size(); i++) {
        m_Players[i]->setFolded(false);
        removePlayer(m_Players[i]->getDisplayPosition());
        hand = m_Players[i]->getHand();

        for (int j = 0; j < 5; j++) {
            m_Deck.discardCard(hand->getCard(j));
        }
        //delete hands
    }
}

void Poker::endGame(string endReason) {
    int input;
    stringstream bannerText;
    bannerText << endReason << "; e:exit";
    setBottomBannerText(bannerText.str());

    while (1) {
        input = GAME_DISPLAY.captureInput();

        if (input == 'e' || input == 'E') {
			return;
        }
    }
}

int Poker::ante() {
    int num_players = m_Players.size();
    switch (num_players) {
        case 4:
            return (int) (0.015 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        case 3:
            return (int) (0.025 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        case 2:
            return (int) (0.15 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        default:
            return 0;
            break;
    }
}

int Poker::minimumBet(PlayerD1 *player) {
    return ( maxSinglePlayerMoney() - player->getMoneyInPot() );
}

int Poker::maxSinglePlayerMoney() {
    return max( m_HumanPlayer.getMoneyInPot(), max( m_AiPlayer_1.getMoneyInPot(), max( m_AiPlayer_2.getMoneyInPot(), m_AiPlayer_3.getMoneyInPot() ) ) );
}

bool Poker::allPlayersAllIn() {
    bool allIn = true;
    for (int i = 0; i <  (int)m_Players.size(); i++) {
        allIn = allIn && m_Players[i]->folded() || ( m_Players[i]->getMoney() == 0 );
    }

    return allIn;
}

void Poker::runGame(GameObject *game) {

	game->D1Timer.checkIn();
	m_HumanPlayer.setMoney(game->cash);

    while (m_Players.size() > 1) {
    //enter ante loop
        runAnte();
        if (roundIsOver()) continue;
    //enter deal loop
        runDeal();
		game->cardsPlayed += 5;
    //enter first betting loop
        runBetting(1);
        if (roundIsOver()) continue;
    //enter card exchnage loop
        game->cardsPlayed += runCardExchange();
    //enter second betting loop
        runBetting(2);
        if (roundIsOver()) continue;
    //enter showdown loop
        runShowdown();
        finishRound();
    }

    endGame("You didn't lose! Hooray!");
	game->cash = m_HumanPlayer.getMoney();
	game->D1Timer.checkOut();
}

void Poker::mostlyRedraw(int sig) {
	GAME_DISPLAY.handleResize(sig);
	GAME_DISPLAY.eraseBox(0, 0, GAME_DISPLAY.getCols(), GAME_DISPLAY.getLines());
    for (int i = 0; i < (int)m_Players.size(); i++) {
        if (!m_Players[i]->folded()) {
            Frame frame = m_Players[i]->getFrame();
			GAME_DISPLAY.eraseBox(frame->getX(), frame->getY(), frame->getWidth(), frame->getHeight());
			drawHand(m_Players[i]->getHand(), typeid(m_Players[i]) != typeid(HumanPlayer) , frame);
        }
    }
	updateGameInfo();
	setBottomBannerText("");
}
<commit_msg>Shows the players cards after resize...<commit_after>#include "Poker.h"
#include "../GameObject.h"
#include "../Timer.h"
#include "../Advertisement.h"

Poker::Poker() :
    m_InitialPlayers(4),
    m_InitialMoney(1000),
    m_RoundCounter(1),
    m_PotMoney(0),
    bettingCycle(1),
    player0Frame(20, 16, 38, 7),
    player1Frame(0 ,  9, 38, 7),
    player2Frame(20,  1, 38, 7),
    player3Frame(40,  9, 38, 7),
    m_HumanPlayer(0, m_InitialMoney, "Human"),
    m_AiPlayer_1(1, m_InitialMoney, "West"),
    m_AiPlayer_2(2, m_InitialMoney, "North"),
    m_AiPlayer_3(3, m_InitialMoney, "East"),
    m_Players(),
	GAME_DISPLAY()
{
    m_HumanPlayer.setFrame(&player0Frame);
    m_AiPlayer_1.setFrame(&player1Frame);
    m_AiPlayer_2.setFrame(&player2Frame);
    m_AiPlayer_3.setFrame(&player3Frame);

    m_Players.push_back(&m_AiPlayer_1);
    m_Players.push_back(&m_AiPlayer_2);
    m_Players.push_back(&m_AiPlayer_3);
    m_Players.push_back(&m_HumanPlayer);

    initializeDisplay();
}

Poker::~Poker() {}

void Poker::initializeDisplay() {
    updateGameInfo();
}

void Poker::setTopBannerText(string text) {
    GAME_DISPLAY.bannerTop(text);
}

void Poker::setBottomBannerText(string text) {
    GAME_DISPLAY.bannerBottom(text);
}

void Poker::removePlayer(int position) {
    Frame frame;

    switch (position) {
        case 0:
            frame = player0Frame;
            break;
        case 1:
            frame = player1Frame;
            break;
        case 2:
            frame = player2Frame;
            break;
        case 3:
            frame = player3Frame;
            break;
        default: return;
    }

    GAME_DISPLAY.eraseBox(frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight());
}

void Poker::drawHand(HandD1 *hand, bool hidden, Frame *frame) {
    int x = frame->getX(), y = frame->getY();

    if (hidden) { //top player
        for (int i = 0; i < 5; i++) {
            GAME_DISPLAY.displayCard(x + 1 + i*7, y + 2, 0, 0, 0);
        }
    } else if (hand != NULL) { //display cards for human player
        CardD1 *card;
        for (int i = 0; i < 5; i++) {
            card = hand->getCard(i);
            GAME_DISPLAY.displayCard(x + 1 + i*7, y + 2, card->getSuit() + 1, card->getNumber(), 0);
        }
    }
}

void Poker::updateHand(HandD1 *hand, Frame *frame) {
    if (hand != NULL) {
        GAME_DISPLAY.eraseBox(frame->getX(), frame->getY(), frame->getWidth(), frame->getHeight());
        drawHand(hand, false, frame);
    }
}

//called whenever any player money or pot changes, or when round round or style changes
void Poker::updateGameInfo() {
    stringstream bannerText;
    bannerText << bannerHeader << " || ";
    bannerText << "Me: $" << m_HumanPlayer.getMoney();
    bannerText << " | W: $" << m_AiPlayer_1.getMoney();
    bannerText << " | N: $" << m_AiPlayer_2.getMoney();
    bannerText << " | E: $" << m_AiPlayer_3.getMoney();
    bannerText << " | Pot: $" << m_PotMoney;
    setTopBannerText(bannerText.str());
}

void Poker::rotatePlayers() {
    PlayerD1 *tempPlayer = m_Players.front();
    m_Players.pop_front();
    m_Players.push_back(tempPlayer);
}

void Poker::removeCurrentPlayer() {
    removePlayer(((PlayerD1 *)m_Players.front())->getDisplayPosition());
    m_Players.pop_front();
}

void Poker::runAnte() {
    stringstream bannerText;
	Advertisement adGenerator;
	bannerText << adGenerator.getAd();
    //bannerText << "Round " << m_RoundCounter << ": Ante";
    bannerHeader = bannerText.str();
    updateGameInfo();

    int a = ante();

    for (int i = 0; i < (int)m_Players.size(); i++) {
        PlayerD1 *player = m_Players.front();

        if (typeid(*player) == typeid(HumanPlayer)) {
            HumanPlayer *hPlayer = (HumanPlayer *) player;

            if (hPlayer->ante(a, GAME_DISPLAY) == PlayerD1::FOLD) { //didn't ante, remove human player from game
				m_Players.clear();
                endGame("You didn't ante!? You gotta go. :(");
				return;
            }
        } else {
            AI *cPlayer = (AI *) player;
            if(cPlayer->ante(a, GAME_DISPLAY) == PlayerD1::FOLD) {
                removeCurrentPlayer();
                i--;
                continue;
            }
        }

        m_PotMoney += player->getMoneyInPot();
        updateGameInfo();

        rotatePlayers();
    }
}

void Poker::runDeal() {
    int i;

    for (i = 0; i < rand() %1000; i++)
        m_Deck.shuffle();

    for (i = 0; i < (int)m_Players.size(); i++) {
        CardD1 *c1 = m_Deck.drawCard();
        CardD1 *c2 = m_Deck.drawCard();
        CardD1 *c3 = m_Deck.drawCard();
        CardD1 *c4 = m_Deck.drawCard();
        CardD1 *c5 = m_Deck.drawCard();
        m_Players[i]->setHand( new HandD1(c1, c2, c3, c4, c5) );

        drawHand(NULL, true, m_Players[i]->getFrame());
    }

    updateHand(m_HumanPlayer.getHand(), &player0Frame);
}

void Poker::runBetting(int bettingCycle) {
    stringstream bannerText;
    bannerText << "Round " << m_RoundCounter << ": Betting Cycle " << bettingCycle;
    bannerHeader = bannerText.str();
    updateGameInfo();

    int bet, callCounter = 0, minBet;

    while (unfoldedPlayers() > 1) {
        PlayerD1 *player = m_Players.front();
        minBet = minimumBet(player);

        if (player->folded()) {
            callCounter++;
        } else {
            bet = player->bet(minBet, GAME_DISPLAY);
            callCounter++;

            if (bet != PlayerD1::FOLD) {
                m_PotMoney += bet;
                updateGameInfo();

                if (bet > minBet) {
                    callCounter = 1;
                }
            } else {
                removePlayer(player->getDisplayPosition());
            }
        }

        if (callCounter >= unfoldedPlayers() || allPlayersAllIn())
            break;

        rotatePlayers();
    }
}

int Poker::unfoldedPlayers() {
    int unfolded = 0;

    for (int i = 0; i < (int)m_Players.size(); i++) {
        unfolded += (int) !m_Players[i]->folded();
    }

    return unfolded;
}

int Poker::runCardExchange() {
	int discardCount = 0; //count how many cards the human discards
    stringstream bannerText;
    bannerText << "Round " << m_RoundCounter << ": Betting Cycle " << bettingCycle;
    bannerHeader = bannerText.str();
    updateGameInfo();

    //bringHumanToFront();
    for (int i = 0; i < (int)m_Players.size(); i++) {
        PlayerD1 *player = m_Players.front();

        if (!player->folded()) {
            player->discard(GAME_DISPLAY);

            for (int j = 0; j < 5; j++) {
                if (player->getHand()->getCard(j)->isDiscarded()) {
                    m_Deck.discardCard(player->getHand()->exchange(m_Deck.drawCard(), j));
					discardCount++;
                }
            }

            if (typeid(*player) == typeid(HumanPlayer)) {
                updateHand(player->getHand(), player->getFrame());
            }
        }

        rotatePlayers();
    }

	return discardCount;
}

void Poker::runShowdown() {
    for (int i = 0; i < (int)m_Players.size(); i++) {
        if (m_Players[i]->folded()) {
            removePlayer(m_Players[i]->getDisplayPosition());
        } else {
            updateHand(m_Players[i]->getHand(), m_Players[i]->getFrame());
        }
    }
}

bool Poker::roundIsOver() {
    if (m_Players.size() <= 1) return true;

    PlayerD1 *winner;

    if (unfoldedPlayers() == 1) {
        for (int i = 0; i < (int)m_Players.size(); i++) {
            if (!m_Players[i]->folded()) {
                winner = m_Players[i];
                break;
            }
        }
        winner->giveMoney(m_PotMoney);
        setBottomBannerText("Round over. <Press c to continue>");
        finalizeRound();
        return true;
    }

    return false;
}

int Poker::getRemainingPotMoney(){
    int sum = 0;
    for(int i = 0; i < (int)m_Players.size(); i++){
        sum += m_Players[i]->getMoneyInPot();
    }
    return sum;
}

bool Poker::finishRound() {

    PlayerD1* winner = NULL;
    int *score;

    for(int i = 0; i < (int)m_Players.size(); i++){
        if (!m_Players[i]->folded() && m_Players[i]->getMoneyInPot() > 0) {
            if (winner == NULL) {
                winner = m_Players[i];
                score = winner->getHand()->getScore();
            } else if (m_Players[i]->getHand()->isHigherScore(score)) {
                winner = m_Players[i];
                score = winner->getHand()->getScore();
            }
        }
    }

    string outcome = (&m_HumanPlayer != winner )?"You lost :(":"You Win :)";

    stringstream bannerText;
    bannerText << outcome << "; c: continue";
    setBottomBannerText(bannerText.str());

    while(getRemainingPotMoney() > 0){
        winner = NULL;
        int *highscore;

        //Determine the winningest player with non-zero pot money left
        for(int i = 0; i < (int)m_Players.size(); i++){
            if (!m_Players[i]->folded() && m_Players[i]->getMoneyInPot() > 0) {
                if (winner == NULL) {
                    winner = m_Players[i];
                    highscore = winner->getHand()->getScore();
                } else if (m_Players[i]->getHand()->isHigherScore(highscore)) {
                    winner = m_Players[i];
                    highscore = winner->getHand()->getScore();
                }
            }
        }

        //Add money to the bank
        for (int i = 0; i < (int)m_Players.size(); i++) {
            winner->giveMoney(min(winner->getMoneyInPot(), m_Players[i]->getMoneyInPot()));
        }

        vector<int> tmpPotMoney(m_Players.size());
        int winnerPotMoney = winner->getMoneyInPot();

        for (int i = 0; i < (int)m_Players.size(); i++) {
            tmpPotMoney[i] = m_Players[i]->getMoneyInPot();
        }

        //Updates remaining money in the pot
        for (int i = 0; i < (int)m_Players.size(); i++) {
            m_Players[i]->setMoneyInPot(max(tmpPotMoney[i] - winnerPotMoney, 0));
        }
    }

    finalizeRound();
    return true;
}

void Poker::finalizeRound() {
    for (int i = 0; i < (int)m_Players.size(); i++) {
        m_Players[i]->setMoneyInPot(0);
    }

    bettingCycle++;

    m_PotMoney = 0;
    bannerHeader = "";
    updateGameInfo();

    int input;
    while (1) {
        input = GAME_DISPLAY.captureInput();
        if (input == 'c' || input == 'C') {
            break;
        }
    }

    HandD1 *hand;
    for (int i = 0; i < (int)m_Players.size(); i++) {
        m_Players[i]->setFolded(false);
        removePlayer(m_Players[i]->getDisplayPosition());
        hand = m_Players[i]->getHand();

        for (int j = 0; j < 5; j++) {
            m_Deck.discardCard(hand->getCard(j));
        }
        //delete hands
    }
}

void Poker::endGame(string endReason) {
    int input;
    stringstream bannerText;
    bannerText << endReason << "; e:exit";
    setBottomBannerText(bannerText.str());

    while (1) {
        input = GAME_DISPLAY.captureInput();

        if (input == 'e' || input == 'E') {
			return;
        }
    }
}

int Poker::ante() {
    int num_players = m_Players.size();
    switch (num_players) {
        case 4:
            return (int) (0.015 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        case 3:
            return (int) (0.025 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        case 2:
            return (int) (0.15 * (double)m_InitialMoney * (double)m_InitialPlayers);
            break;
        default:
            return 0;
            break;
    }
}

int Poker::minimumBet(PlayerD1 *player) {
    return ( maxSinglePlayerMoney() - player->getMoneyInPot() );
}

int Poker::maxSinglePlayerMoney() {
    return max( m_HumanPlayer.getMoneyInPot(), max( m_AiPlayer_1.getMoneyInPot(), max( m_AiPlayer_2.getMoneyInPot(), m_AiPlayer_3.getMoneyInPot() ) ) );
}

bool Poker::allPlayersAllIn() {
    bool allIn = true;
    for (int i = 0; i <  (int)m_Players.size(); i++) {
        allIn = allIn && m_Players[i]->folded() || ( m_Players[i]->getMoney() == 0 );
    }

    return allIn;
}

void Poker::runGame(GameObject *game) {

	game->D1Timer.checkIn();
	m_HumanPlayer.setMoney(game->cash);

    while (m_Players.size() > 1) {
    //enter ante loop
        runAnte();
        if (roundIsOver()) continue;
    //enter deal loop
        runDeal();
		game->cardsPlayed += 5;
    //enter first betting loop
        runBetting(1);
        if (roundIsOver()) continue;
    //enter card exchnage loop
        game->cardsPlayed += runCardExchange();
    //enter second betting loop
        runBetting(2);
        if (roundIsOver()) continue;
    //enter showdown loop
        runShowdown();
        finishRound();
    }

    endGame("You didn't lose! Hooray!");
	game->cash = m_HumanPlayer.getMoney();
	game->D1Timer.checkOut();
}

void Poker::mostlyRedraw(int sig) {
	GAME_DISPLAY.handleResize(sig);
	GAME_DISPLAY.eraseBox(0, 0, GAME_DISPLAY.getCols(), GAME_DISPLAY.getLines());
    for (int i = 0; i < (int)m_Players.size(); i++) {
        if (!m_Players[i]->folded()) {
            Frame* frame = m_Players[i]->getFrame();
			GAME_DISPLAY.eraseBox(frame->getX(), frame->getY(), frame->getWidth(), frame->getHeight());
			drawHand(m_Players[i]->getHand(), typeid(*(m_Players[i])) != typeid(HumanPlayer) , frame);
        }
    }
	updateGameInfo();
	setBottomBannerText("");
}
<|endoftext|>