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

#include <limits>
#include <set>
#include <string>

#include "chrome/browser/history/text_database.h"

#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"

// There are two tables in each database, one full-text search (FTS) table which
// indexes the contents and title of the pages. The other is a regular SQLITE
// table which contains non-indexed information about the page. All columns of
// a FTS table are indexed using the text search algorithm, which isn't what we
// want for things like times. If this were in the FTS table, there would be
// different words in the index for each time number.
//
// "pages" FTS table:
//   url    URL of the page so searches will match the URL.
//   title  Title of the page.
//   body   Body of the page.
//
// "info" regular table:
//   time     Time the corresponding FTS entry was visited.
//
// We do joins across these two tables by using their internal rowids, which we
// keep in sync between the two tables. The internal rowid is the only part of
// an FTS table that is indexed like a normal table, and the index over it is
// free since sqlite always indexes the internal rowid.

namespace history {

namespace {

static const int kCurrentVersionNumber = 1;
static const int kCompatibleVersionNumber = 1;

// Snippet computation relies on the index of the columns in the original
// create statement. These are the 0-based indices (as strings) of the
// corresponding columns.
const char kTitleColumnIndex[] = "1";
const char kBodyColumnIndex[] = "2";

// The string prepended to the database identifier to generate the filename.
const FilePath::CharType kFilePrefix[] = FILE_PATH_LITERAL("History Index ");

}  // namespace

TextDatabase::TextDatabase(const FilePath& path,
                           DBIdent id,
                           bool allow_create)
    : path_(path),
      ident_(id),
      allow_create_(allow_create) {
  // Compute the file name.
  file_name_ = path_.Append(IDToFileName(ident_));
}

TextDatabase::~TextDatabase() {
}

// static
const FilePath::CharType* TextDatabase::file_base() {
  return kFilePrefix;
}

// static
FilePath TextDatabase::IDToFileName(DBIdent id) {
  // Identifiers are intended to be a combination of the year and month, for
  // example, 200801 for January 2008. We convert this to
  // "History Index 2008-01". However, we don't make assumptions about this
  // scheme: the caller should assign IDs as it feels fit with the knowledge
  // that they will apppear on disk in this form.
  FilePath::StringType filename(file_base());
  StringAppendF(&filename, FILE_PATH_LITERAL("%d-%02d"),
                id / 100, id % 100);
  return FilePath(filename);
}

// static
TextDatabase::DBIdent TextDatabase::FileNameToID(const FilePath& file_path) {
  FilePath::StringType file_name = file_path.BaseName().value();

  // We don't actually check the prefix here. Since the file system could
  // be case insensitive in ways we can't predict (NTFS), checking could
  // potentially be the wrong thing to do. Instead, we just look for a suffix.
  static const size_t kIDStringLength = 7;  // Room for "xxxx-xx".
  if (file_name.length() < kIDStringLength)
    return 0;
  const FilePath::StringType suffix(
      &file_name[file_name.length() - kIDStringLength]);

  if (suffix.length() != kIDStringLength ||
      suffix[4] != FILE_PATH_LITERAL('-')) {
    return 0;
  }

  int year = StringToInt(suffix.substr(0, 4));
  int month = StringToInt(suffix.substr(5, 2));

  return year * 100 + month;
}

bool TextDatabase::Init() {
  // Make sure, if we're not allowed to create the file, that it exists.
  if (!allow_create_) {
    if (!file_util::PathExists(file_name_))
      return false;
  }

  // Set the exceptional sqlite error handler.
  db_.set_error_delegate(GetErrorHandlerForTextDb());

  // Set the database page size to something a little larger to give us
  // better performance (we're typically seek rather than bandwidth limited).
  // This only has an effect before any tables have been created, otherwise
  // this is a NOP. Must be a power of 2 and a max of 8192.
  db_.set_page_size(2096);

  // The default cache size is 2000 which give >8MB of data. Since we will often
  // have 2-3 of these objects, each with their own 8MB, this adds up very fast.
  // We therefore reduce the size so when there are multiple objects, we're not
  // too big.
  db_.set_cache_size(512);

  // Run the database in exclusive mode. Nobody else should be accessing the
  // database while we're running, and this will give somewhat improved perf.
  db_.set_exclusive_locking();

  // Attach the database to our index file.
  if (!db_.Open(file_name_))
    return false;

  // Meta table tracking version information.
  if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
    return false;
  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
    // This version is too new. We don't bother notifying the user on this
    // error, and just fail to use the file. Normally if they have version skew,
    // they will get it for the main history file and it won't be necessary
    // here. If that's not the case, since this is only indexed data, it's
    // probably better to just not give FTS results than strange errors when
    // everything else is working OK.
    LOG(WARNING) << "Text database is too new.";
    return false;
  }

  return CreateTables();
}

void TextDatabase::BeginTransaction() {
  db_.BeginTransaction();
}

void TextDatabase::CommitTransaction() {
  db_.CommitTransaction();
}

bool TextDatabase::CreateTables() {
  // FTS table of page contents.
  if (!db_.DoesTableExist("pages")) {
    if (!db_.Execute("CREATE VIRTUAL TABLE pages USING fts2("
                     "TOKENIZE icu,"
                     "url LONGVARCHAR,"
                     "title LONGVARCHAR,"
                     "body LONGVARCHAR)"))
      return false;
  }

  // Non-FTS table containing URLs and times so we can efficiently find them
  // using a regular index (all FTS columns are special and are treated as
  // full-text-search, which is not what we want when retrieving this data).
  if (!db_.DoesTableExist("info")) {
    // Note that there is no point in creating an index over time. Since
    // we must always query the entire FTS table (it can not efficiently do
    // subsets), we will always end up doing that first, and joining the info
    // table off of that.
    if (!db_.Execute("CREATE TABLE info(time INTEGER NOT NULL)"))
      return false;
  }

  // Create the index. This will fail when the index already exists, so we just
  // ignore the error.
  db_.Execute("CREATE INDEX info_time ON info(time)");
  return true;
}

bool TextDatabase::AddPageData(base::Time time,
                               const std::string& url,
                               const std::string& title,
                               const std::string& contents) {
  sql::Transaction committer(&db_);
  if (!committer.Begin())
    return false;

  // Add to the pages table.
  sql::Statement add_to_pages(db_.GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO pages (url, title, body) VALUES (?,?,?)"));
  if (!add_to_pages) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }
  add_to_pages.BindString(0, url);
  add_to_pages.BindString(1, title);
  add_to_pages.BindString(2, contents);
  if (!add_to_pages.Run()) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }

  int64 rowid = db_.GetLastInsertRowId();

  // Add to the info table with the same rowid.
  sql::Statement add_to_info(db_.GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO info (rowid, time) VALUES (?,?)"));
  if (!add_to_info) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }
  add_to_info.BindInt64(0, rowid);
  add_to_info.BindInt64(1, time.ToInternalValue());
  if (!add_to_info.Run()) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }

  return committer.Commit();
}

void TextDatabase::DeletePageData(base::Time time, const std::string& url) {
  // First get all rows that match. Selecing on time (which has an index) allows
  // us to avoid brute-force searches on the full-text-index table (there will
  // generally be only one match per time).
  sql::Statement select_ids(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT info.rowid "
      "FROM info JOIN pages ON info.rowid = pages.rowid "
      "WHERE info.time=? AND pages.url=?"));
  if (!select_ids)
    return;
  select_ids.BindInt64(0, time.ToInternalValue());
  select_ids.BindString(1, url);
  std::set<int64> rows_to_delete;
  while (select_ids.Step())
    rows_to_delete.insert(select_ids.ColumnInt64(0));

  // Delete from the pages table.
  sql::Statement delete_page(db_.GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM pages WHERE rowid=?"));
  if (!delete_page)
    return;
  for (std::set<int64>::const_iterator i = rows_to_delete.begin();
       i != rows_to_delete.end(); ++i) {
    delete_page.BindInt64(0, *i);
    if (!delete_page.Run()) {
      NOTREACHED();
      return;
    }
    delete_page.Reset();
  }

  // Delete from the info table.
  sql::Statement delete_info(db_.GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM info WHERE rowid=?"));
  if (!delete_info)
    return;
  for (std::set<int64>::const_iterator i = rows_to_delete.begin();
       i != rows_to_delete.end(); ++i) {
    delete_info.BindInt64(0, *i);
    if (!delete_info.Run()) {
      NOTREACHED();
      return;
    }
    delete_info.Reset();
  }
}

void TextDatabase::Optimize() {
  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT OPTIMIZE(pages) FROM pages LIMIT 1"));
  if (!statement)
    return;
  statement.Run();
}

void TextDatabase::GetTextMatches(const std::string& query,
                                  const QueryOptions& options,
                                  std::vector<Match>* results,
                                  URLSet* found_urls,
                                  base::Time* first_time_searched) {
  *first_time_searched = options.begin_time;

  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
    "SELECT url, title, time, offsets(pages), body "
        "FROM pages LEFT OUTER JOIN info ON pages.rowid = info.rowid "
        "WHERE pages MATCH ? AND time >= ? AND time < ? "
        "ORDER BY time DESC "
        "LIMIT ?"));
  if (!statement)
    return;

  // When their values indicate "unspecified", saturate the numbers to the max
  // or min to get the correct result.
  int64 effective_begin_time = options.begin_time.is_null() ?
      0 : options.begin_time.ToInternalValue();
  int64 effective_end_time = options.end_time.is_null() ?
      std::numeric_limits<int64>::max() : options.end_time.ToInternalValue();
  int effective_max_count = options.max_count ?
      options.max_count : std::numeric_limits<int>::max();

  statement.BindString(0, query);
  statement.BindInt64(1, effective_begin_time);
  statement.BindInt64(2, effective_end_time);
  statement.BindInt(3, effective_max_count);

  while (statement.Step()) {
    // TODO(brettw) allow canceling the query in the middle.
    // if (canceled_or_something)
    //   break;

    GURL url(statement.ColumnString(0));
    URLSet::const_iterator found_url = found_urls->find(url);
    if (found_url != found_urls->end())
      continue;  // Don't add this duplicate.

    // Fill the results into the vector (avoid copying the URL with Swap()).
    results->resize(results->size() + 1);
    Match& match = results->at(results->size() - 1);
    match.url.Swap(&url);

    match.title = UTF8ToWide(statement.ColumnString(1));
    match.time = base::Time::FromInternalValue(statement.ColumnInt64(2));

    // Extract any matches in the title.
    std::string offsets_str = statement.ColumnString(3);
    Snippet::ExtractMatchPositions(offsets_str, kTitleColumnIndex,
                                   &match.title_match_positions);
    Snippet::ConvertMatchPositionsToWide(statement.ColumnString(1),
                                         &match.title_match_positions);

    // Extract the matches in the body.
    Snippet::MatchPositions match_positions;
    Snippet::ExtractMatchPositions(offsets_str, kBodyColumnIndex,
                                   &match_positions);

    // Compute the snippet based on those matches.
    std::string body = statement.ColumnString(4);
    match.snippet.ComputeSnippet(match_positions, body);
  }

  // When we have returned all the results possible (or determined that there
  // are none), then we have searched all the time requested, so we can
  // set the first_time_searched to that value.
  if (results->size() == 0 ||
      options.max_count == 0 ||  // Special case for wanting all the results.
      static_cast<int>(results->size()) < options.max_count) {
    *first_time_searched = options.begin_time;
  } else {
    // Since we got the results in order, we know the last item is the last
    // time we considered.
    *first_time_searched = results->back().time;
  }

  statement.Reset();
}

}  // namespace history
<commit_msg>Make all new history index files use FTS3 instead of FTS2.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits>
#include <set>
#include <string>

#include "chrome/browser/history/text_database.h"

#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"

// There are two tables in each database, one full-text search (FTS) table which
// indexes the contents and title of the pages. The other is a regular SQLITE
// table which contains non-indexed information about the page. All columns of
// a FTS table are indexed using the text search algorithm, which isn't what we
// want for things like times. If this were in the FTS table, there would be
// different words in the index for each time number.
//
// "pages" FTS table:
//   url    URL of the page so searches will match the URL.
//   title  Title of the page.
//   body   Body of the page.
//
// "info" regular table:
//   time     Time the corresponding FTS entry was visited.
//
// We do joins across these two tables by using their internal rowids, which we
// keep in sync between the two tables. The internal rowid is the only part of
// an FTS table that is indexed like a normal table, and the index over it is
// free since sqlite always indexes the internal rowid.

namespace history {

namespace {

static const int kCurrentVersionNumber = 1;
static const int kCompatibleVersionNumber = 1;

// Snippet computation relies on the index of the columns in the original
// create statement. These are the 0-based indices (as strings) of the
// corresponding columns.
const char kTitleColumnIndex[] = "1";
const char kBodyColumnIndex[] = "2";

// The string prepended to the database identifier to generate the filename.
const FilePath::CharType kFilePrefix[] = FILE_PATH_LITERAL("History Index ");

}  // namespace

TextDatabase::TextDatabase(const FilePath& path,
                           DBIdent id,
                           bool allow_create)
    : path_(path),
      ident_(id),
      allow_create_(allow_create) {
  // Compute the file name.
  file_name_ = path_.Append(IDToFileName(ident_));
}

TextDatabase::~TextDatabase() {
}

// static
const FilePath::CharType* TextDatabase::file_base() {
  return kFilePrefix;
}

// static
FilePath TextDatabase::IDToFileName(DBIdent id) {
  // Identifiers are intended to be a combination of the year and month, for
  // example, 200801 for January 2008. We convert this to
  // "History Index 2008-01". However, we don't make assumptions about this
  // scheme: the caller should assign IDs as it feels fit with the knowledge
  // that they will apppear on disk in this form.
  FilePath::StringType filename(file_base());
  StringAppendF(&filename, FILE_PATH_LITERAL("%d-%02d"),
                id / 100, id % 100);
  return FilePath(filename);
}

// static
TextDatabase::DBIdent TextDatabase::FileNameToID(const FilePath& file_path) {
  FilePath::StringType file_name = file_path.BaseName().value();

  // We don't actually check the prefix here. Since the file system could
  // be case insensitive in ways we can't predict (NTFS), checking could
  // potentially be the wrong thing to do. Instead, we just look for a suffix.
  static const size_t kIDStringLength = 7;  // Room for "xxxx-xx".
  if (file_name.length() < kIDStringLength)
    return 0;
  const FilePath::StringType suffix(
      &file_name[file_name.length() - kIDStringLength]);

  if (suffix.length() != kIDStringLength ||
      suffix[4] != FILE_PATH_LITERAL('-')) {
    return 0;
  }

  int year = StringToInt(suffix.substr(0, 4));
  int month = StringToInt(suffix.substr(5, 2));

  return year * 100 + month;
}

bool TextDatabase::Init() {
  // Make sure, if we're not allowed to create the file, that it exists.
  if (!allow_create_) {
    if (!file_util::PathExists(file_name_))
      return false;
  }

  // Set the exceptional sqlite error handler.
  db_.set_error_delegate(GetErrorHandlerForTextDb());

  // Set the database page size to something a little larger to give us
  // better performance (we're typically seek rather than bandwidth limited).
  // This only has an effect before any tables have been created, otherwise
  // this is a NOP. Must be a power of 2 and a max of 8192.
  db_.set_page_size(2096);

  // The default cache size is 2000 which give >8MB of data. Since we will often
  // have 2-3 of these objects, each with their own 8MB, this adds up very fast.
  // We therefore reduce the size so when there are multiple objects, we're not
  // too big.
  db_.set_cache_size(512);

  // Run the database in exclusive mode. Nobody else should be accessing the
  // database while we're running, and this will give somewhat improved perf.
  db_.set_exclusive_locking();

  // Attach the database to our index file.
  if (!db_.Open(file_name_))
    return false;

  // Meta table tracking version information.
  if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
    return false;
  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
    // This version is too new. We don't bother notifying the user on this
    // error, and just fail to use the file. Normally if they have version skew,
    // they will get it for the main history file and it won't be necessary
    // here. If that's not the case, since this is only indexed data, it's
    // probably better to just not give FTS results than strange errors when
    // everything else is working OK.
    LOG(WARNING) << "Text database is too new.";
    return false;
  }

  return CreateTables();
}

void TextDatabase::BeginTransaction() {
  db_.BeginTransaction();
}

void TextDatabase::CommitTransaction() {
  db_.CommitTransaction();
}

bool TextDatabase::CreateTables() {
  // FTS table of page contents.
  if (!db_.DoesTableExist("pages")) {
    if (!db_.Execute("CREATE VIRTUAL TABLE pages USING fts3("
                     "TOKENIZE icu,"
                     "url LONGVARCHAR,"
                     "title LONGVARCHAR,"
                     "body LONGVARCHAR)"))
      return false;
  }

  // Non-FTS table containing URLs and times so we can efficiently find them
  // using a regular index (all FTS columns are special and are treated as
  // full-text-search, which is not what we want when retrieving this data).
  if (!db_.DoesTableExist("info")) {
    // Note that there is no point in creating an index over time. Since
    // we must always query the entire FTS table (it can not efficiently do
    // subsets), we will always end up doing that first, and joining the info
    // table off of that.
    if (!db_.Execute("CREATE TABLE info(time INTEGER NOT NULL)"))
      return false;
  }

  // Create the index. This will fail when the index already exists, so we just
  // ignore the error.
  db_.Execute("CREATE INDEX info_time ON info(time)");
  return true;
}

bool TextDatabase::AddPageData(base::Time time,
                               const std::string& url,
                               const std::string& title,
                               const std::string& contents) {
  sql::Transaction committer(&db_);
  if (!committer.Begin())
    return false;

  // Add to the pages table.
  sql::Statement add_to_pages(db_.GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO pages (url, title, body) VALUES (?,?,?)"));
  if (!add_to_pages) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }
  add_to_pages.BindString(0, url);
  add_to_pages.BindString(1, title);
  add_to_pages.BindString(2, contents);
  if (!add_to_pages.Run()) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }

  int64 rowid = db_.GetLastInsertRowId();

  // Add to the info table with the same rowid.
  sql::Statement add_to_info(db_.GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO info (rowid, time) VALUES (?,?)"));
  if (!add_to_info) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }
  add_to_info.BindInt64(0, rowid);
  add_to_info.BindInt64(1, time.ToInternalValue());
  if (!add_to_info.Run()) {
    NOTREACHED() << db_.GetErrorMessage();
    return false;
  }

  return committer.Commit();
}

void TextDatabase::DeletePageData(base::Time time, const std::string& url) {
  // First get all rows that match. Selecing on time (which has an index) allows
  // us to avoid brute-force searches on the full-text-index table (there will
  // generally be only one match per time).
  sql::Statement select_ids(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT info.rowid "
      "FROM info JOIN pages ON info.rowid = pages.rowid "
      "WHERE info.time=? AND pages.url=?"));
  if (!select_ids)
    return;
  select_ids.BindInt64(0, time.ToInternalValue());
  select_ids.BindString(1, url);
  std::set<int64> rows_to_delete;
  while (select_ids.Step())
    rows_to_delete.insert(select_ids.ColumnInt64(0));

  // Delete from the pages table.
  sql::Statement delete_page(db_.GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM pages WHERE rowid=?"));
  if (!delete_page)
    return;
  for (std::set<int64>::const_iterator i = rows_to_delete.begin();
       i != rows_to_delete.end(); ++i) {
    delete_page.BindInt64(0, *i);
    if (!delete_page.Run()) {
      NOTREACHED();
      return;
    }
    delete_page.Reset();
  }

  // Delete from the info table.
  sql::Statement delete_info(db_.GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM info WHERE rowid=?"));
  if (!delete_info)
    return;
  for (std::set<int64>::const_iterator i = rows_to_delete.begin();
       i != rows_to_delete.end(); ++i) {
    delete_info.BindInt64(0, *i);
    if (!delete_info.Run()) {
      NOTREACHED();
      return;
    }
    delete_info.Reset();
  }
}

void TextDatabase::Optimize() {
  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT OPTIMIZE(pages) FROM pages LIMIT 1"));
  if (!statement)
    return;
  statement.Run();
}

void TextDatabase::GetTextMatches(const std::string& query,
                                  const QueryOptions& options,
                                  std::vector<Match>* results,
                                  URLSet* found_urls,
                                  base::Time* first_time_searched) {
  *first_time_searched = options.begin_time;

  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
    "SELECT url, title, time, offsets(pages), body "
        "FROM pages LEFT OUTER JOIN info ON pages.rowid = info.rowid "
        "WHERE pages MATCH ? AND time >= ? AND time < ? "
        "ORDER BY time DESC "
        "LIMIT ?"));
  if (!statement)
    return;

  // When their values indicate "unspecified", saturate the numbers to the max
  // or min to get the correct result.
  int64 effective_begin_time = options.begin_time.is_null() ?
      0 : options.begin_time.ToInternalValue();
  int64 effective_end_time = options.end_time.is_null() ?
      std::numeric_limits<int64>::max() : options.end_time.ToInternalValue();
  int effective_max_count = options.max_count ?
      options.max_count : std::numeric_limits<int>::max();

  statement.BindString(0, query);
  statement.BindInt64(1, effective_begin_time);
  statement.BindInt64(2, effective_end_time);
  statement.BindInt(3, effective_max_count);

  while (statement.Step()) {
    // TODO(brettw) allow canceling the query in the middle.
    // if (canceled_or_something)
    //   break;

    GURL url(statement.ColumnString(0));
    URLSet::const_iterator found_url = found_urls->find(url);
    if (found_url != found_urls->end())
      continue;  // Don't add this duplicate.

    // Fill the results into the vector (avoid copying the URL with Swap()).
    results->resize(results->size() + 1);
    Match& match = results->at(results->size() - 1);
    match.url.Swap(&url);

    match.title = UTF8ToWide(statement.ColumnString(1));
    match.time = base::Time::FromInternalValue(statement.ColumnInt64(2));

    // Extract any matches in the title.
    std::string offsets_str = statement.ColumnString(3);
    Snippet::ExtractMatchPositions(offsets_str, kTitleColumnIndex,
                                   &match.title_match_positions);
    Snippet::ConvertMatchPositionsToWide(statement.ColumnString(1),
                                         &match.title_match_positions);

    // Extract the matches in the body.
    Snippet::MatchPositions match_positions;
    Snippet::ExtractMatchPositions(offsets_str, kBodyColumnIndex,
                                   &match_positions);

    // Compute the snippet based on those matches.
    std::string body = statement.ColumnString(4);
    match.snippet.ComputeSnippet(match_positions, body);
  }

  // When we have returned all the results possible (or determined that there
  // are none), then we have searched all the time requested, so we can
  // set the first_time_searched to that value.
  if (results->size() == 0 ||
      options.max_count == 0 ||  // Special case for wanting all the results.
      static_cast<int>(results->size()) < options.max_count) {
    *first_time_searched = options.begin_time;
  } else {
    // Since we got the results in order, we know the last item is the last
    // time we considered.
    *first_time_searched = results->back().time;
  }

  statement.Reset();
}

}  // namespace history
<|endoftext|>


<commit_before>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nuiPopupValueAttributeEditor.h"
#include "nuiEditLine.h"

nuiPopupValueAttributeEditor::nuiPopupValueAttributeEditor(const nuiAttrib<uint32>& rAttribute, const nuiRange& rRange)
: nuiAttributeEditor(), mAttribute(rAttribute), mRange(rRange), mEventSink(this)
{
  SetObjectClass(_T("nuiPopupValueAttributeEditor"));

  mpEditLine = new nuiEditLine();
  mpEditLine->SetObjectName(_T("NameAttributeEditor::EditLine"));

  AddChild(mpEditLine);

  nglString str;
  mAttribute.ToString(str);
  mpEditLine->SetText(str);

  mpEditLine->Focus();
  mpEditLine->Do(nuiEditLine::eSelectAll,NULL);

  mEventSink.Connect(mpEditLine->Activated, &nuiPopupValueAttributeEditor::OnValidated);
  mEventSink.Connect(mpEditLine->Aborted, &nuiPopupValueAttributeEditor::OnCanceled);
  mEventSink.Connect(mAttribute.GetChangedEvent(), &nuiPopupValueAttributeEditor::OnAttributeChanged);
}

nuiPopupValueAttributeEditor::~nuiPopupValueAttributeEditor()
{

}

bool nuiPopupValueAttributeEditor::OnValidated(const nuiEvent& rEvent)
{
  nglString userStrValue = mpEditLine->GetText();
  double value = userStrValue.GetCDouble();

  nglString finalStrValue = userStrValue;
  double min = mRange.GetMinimum();
  double max = mRange.GetMaximum();
  if (value < min)
  {
    finalStrValue.SetCDouble(min);
  }
  else if (value > max)
  {
    finalStrValue.SetCDouble(max);
  }

  // auto trash
  Trash();

  return true;
}

bool nuiPopupValueAttributeEditor::OnCanceled(const nuiEvent& rEvent)
{
  // auto trash
  Trash();
  return true;
}

bool nuiPopupValueAttributeEditor::OnAttributeChanged(const nuiEvent& rEvent)
{
  nglString str;
  mAttribute.ToString(str);
  mpEditLine->SetText(str);
  return false;
}
<commit_msg>fixed the fix<commit_after>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiPopupValueAttributeEditor.h"
#include "nuiEditLine.h"

nuiPopupValueAttributeEditor::nuiPopupValueAttributeEditor(const nuiAttrib<uint32>& rAttribute, const nuiRange& rRange)
: nuiAttributeEditor(), mAttribute(rAttribute), mRange(rRange), mEventSink(this)
{
  SetObjectClass(_T("nuiPopupValueAttributeEditor"));

  mpEditLine = new nuiEditLine();
  mpEditLine->SetObjectName(_T("NameAttributeEditor::EditLine"));

  AddChild(mpEditLine);

  nglString str;
  mAttribute.ToString(str);
  mpEditLine->SetText(str);

  mpEditLine->Focus();
  mpEditLine->Do(nuiEditLine::eSelectAll,NULL);

  mEventSink.Connect(mpEditLine->Activated, &nuiPopupValueAttributeEditor::OnValidated);
  mEventSink.Connect(mpEditLine->Aborted, &nuiPopupValueAttributeEditor::OnCanceled);
  mEventSink.Connect(mAttribute.GetChangedEvent(), &nuiPopupValueAttributeEditor::OnAttributeChanged);
}

nuiPopupValueAttributeEditor::~nuiPopupValueAttributeEditor()
{

}

bool nuiPopupValueAttributeEditor::OnValidated(const nuiEvent& rEvent)
{
  nglString userStrValue = mpEditLine->GetText();
  double value = userStrValue.GetCDouble();

  nglString finalStrValue = userStrValue;
  double min = mRange.GetMinimum();
  double max = mRange.GetMaximum();
  if (value < min)
  {
    finalStrValue.SetCDouble(min);
  }
  else if (value > max)
  {
    finalStrValue.SetCDouble(max);
  }

  // auto trash
  Trash();

  return true;
}

bool nuiPopupValueAttributeEditor::OnCanceled(const nuiEvent& rEvent)
{
  // auto trash
  Trash();
  return true;
}

bool nuiPopupValueAttributeEditor::OnAttributeChanged(const nuiEvent& rEvent)
{
  nglString str;
  mAttribute.ToString(str);
  mpEditLine->SetText(str);
  return false;
}
<|endoftext|>


<commit_before>/*
  Q Light Controller
  audio.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

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

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <QDomDocument>
#include <QDomElement>
#include <QDebug>
#include <QFile>

#include <QMessageBox>

#ifdef QT_PHONON_LIB
#include <phonon/mediaobject.h>
#include <phonon/backendcapabilities.h>
#endif

#include "audiodecoder.h"
#ifdef HAS_LIBSNDFILE
  #include "audiodecoder_sndfile.h"
#endif
#ifdef HAS_LIBMAD
  #include "audiodecoder_mad.h"
#endif

#include "audiorenderer.h"

#if defined(__APPLE__)
  //#include "audiorenderer_coreaudio.h"
  #include "audiorenderer_portaudio.h"
#elif defined(WIN32)
  #include "audiorenderer_waveout.h"
#else
  #include "audiorenderer_alsa.h"
#endif
#include "audio.h"
#include "doc.h"

#define KXMLQLCAudioSource "Source"
#define KXMLQLCAudioStartTime "StartTime"
#define KXMLQLCAudioColor "Color"

/*****************************************************************************
 * Initialization
 *****************************************************************************/

Audio::Audio(Doc* doc)
  : Function(doc, Function::Audio)
  , m_doc(doc)
#ifdef QT_PHONON_LIB
  , m_object(NULL)
#endif
  , m_decoder(NULL)
  , m_audio_out(NULL)
  , m_startTime(UINT_MAX)
  , m_color(96, 128, 83)
  , m_sourceFileName("")
  , m_audioDuration(0)
{
    setName(tr("New Audio"));

    // Listen to member Function removals
    connect(doc, SIGNAL(functionRemoved(quint32)),
            this, SLOT(slotFunctionRemoved(quint32)));
}

Audio::~Audio()
{
    if (m_audio_out != NULL)
    {
        m_audio_out->stop();
        delete m_audio_out;
    }
    if (m_decoder != NULL)
        delete m_decoder;
}

/*****************************************************************************
 * Copying
 *****************************************************************************/

Function* Audio::createCopy(Doc* doc, bool addToDoc)
{
    Q_ASSERT(doc != NULL);

    Function* copy = new Audio(doc);
    if (copy->copyFrom(this) == false)
    {
        delete copy;
        copy = NULL;
    }
    if (addToDoc == true && doc->addFunction(copy) == false)
    {
        delete copy;
        copy = NULL;
    }

    return copy;
}

bool Audio::copyFrom(const Function* function)
{
    const Audio* aud = qobject_cast<const Audio*> (function);
    if (aud == NULL)
        return false;

    setSourceFileName(aud->m_sourceFileName);
    m_audioDuration = aud->m_audioDuration;
    m_color = aud->m_color;

    return Function::copyFrom(function);
}

QStringList Audio::getCapabilities()
{
    QStringList cap;
#ifdef QT_PHONON_LIB
    return Phonon::BackendCapabilities::availableMimeTypes();
#endif
#ifdef HAS_LIBSNDFILE
    cap << AudioDecoderSndFile::getSupportedFormats();
#endif
#ifdef HAS_LIBMAD
    cap << AudioDecoderMAD::getSupportedFormats();
#endif
    return cap;
}

/*********************************************************************
 * Properties
 *********************************************************************/
void Audio::setStartTime(quint32 time)
{
    m_startTime = time;
}

quint32 Audio::getStartTime() const
{
    return m_startTime;
}

qint64 Audio::getDuration()
{
    return m_audioDuration;
}

void Audio::setColor(QColor color)
{
    m_color = color;
}

QColor Audio::getColor()
{
    return m_color;
}

bool Audio::setSourceFileName(QString filename)
{
    if (m_sourceFileName.isEmpty() == false)
    {
        // unload previous source
        if (m_decoder != NULL)
        {
            delete m_decoder;
            m_decoder = NULL;
        }
    }

#ifdef QT_PHONON_LIB
    m_object = Phonon::createPlayer(Phonon::MusicCategory,
                                    Phonon::MediaSource(filename));
    if (m_object == NULL)
        return false;
#endif
    m_sourceFileName = filename;

    //QMessageBox::warning(0,"Warning", QString("File complete path: %1").arg(m_sourceFileName));

    if (QFile(m_sourceFileName).exists())
        setName(QFileInfo(m_sourceFileName).fileName());
    else
    {
        setName(tr("File not found"));
        return true;
    }

#ifdef QT_PHONON_LIB
    connect(m_object, SIGNAL(totalTimeChanged(qint64)), this, SLOT(slotTotalTimeChanged(qint64)));
#endif

#ifdef HAS_LIBSNDFILE
    m_decoder = new AudioDecoderSndFile(m_sourceFileName);
    if (m_decoder->initialize() == false)
    {
        delete m_decoder;
        m_decoder = NULL;
    }
    else
    {
        m_audioDuration = m_decoder->totalTime();
        return true;
    }
#endif
#ifdef HAS_LIBMAD
    m_decoder = new AudioDecoderMAD(m_sourceFileName);
    if (m_decoder->initialize() == false)
    {
        delete m_decoder;
        m_decoder = NULL;
    }
    else
    {
        m_audioDuration = m_decoder->totalTime();
        return true;
    }
#endif
    return false;
}

QString Audio::getSourceFileName()
{
    return m_sourceFileName;
}

AudioDecoder* Audio::getAudioDecoder()
{
    return m_decoder;
}

void Audio::adjustAttribute(qreal fraction, int)
{
    if (m_audio_out != NULL)
        m_audio_out->adjustIntensity(fraction);
    Function::adjustAttribute(fraction);
}

void Audio::slotTotalTimeChanged(qint64)
{
#ifdef QT_PHONON_LIB
    m_audioDuration = m_object->totalTime();
#endif
    qDebug() << "Audio duration: " << m_audioDuration;
    emit totalTimeChanged(m_audioDuration);
}

void Audio::slotFunctionRemoved(quint32 fid)
{
    Q_UNUSED(fid)
}

bool Audio::saveXML(QDomDocument* doc, QDomElement* wksp_root)
{
    QDomElement root;
    QDomText text;

    Q_ASSERT(doc != NULL);
    Q_ASSERT(wksp_root != NULL);

    /* Function tag */
    root = doc->createElement(KXMLQLCFunction);
    wksp_root->appendChild(root);

    root.setAttribute(KXMLQLCFunctionID, id());
    root.setAttribute(KXMLQLCFunctionType, Function::typeToString(type()));
    root.setAttribute(KXMLQLCFunctionName, name());

    QDomElement source = doc->createElement(KXMLQLCAudioSource);
    source.setAttribute(KXMLQLCAudioStartTime, m_startTime);
    source.setAttribute(KXMLQLCAudioColor, m_color.name());

    text = doc->createTextNode(m_doc->normalizeComponentPath(m_sourceFileName));

    source.appendChild(text);
    root.appendChild(source);

    return true;
}

bool Audio::loadXML(const QDomElement& root)
{
    if (root.tagName() != KXMLQLCFunction)
    {
        qWarning() << Q_FUNC_INFO << "Function node not found";
        return false;
    }

    if (root.attribute(KXMLQLCFunctionType) != typeToString(Function::Audio))
    {
        qWarning() << Q_FUNC_INFO << root.attribute(KXMLQLCFunctionType)
                   << "is not Audio";
        return false;
    }

    QDomNode node = root.firstChild();
    while (node.isNull() == false)
    {
        QDomElement tag = node.toElement();
        if (tag.tagName() == KXMLQLCAudioSource)
        {
            if (tag.hasAttribute(KXMLQLCAudioStartTime))
                m_startTime = tag.attribute(KXMLQLCAudioStartTime).toUInt();
            if (tag.hasAttribute(KXMLQLCAudioColor))
                m_color = QColor(tag.attribute(KXMLQLCAudioColor));
            setSourceFileName(m_doc->denormalizeComponentPath(tag.text()));
        }
        node = node.nextSibling();
    }

    return true;
}

void Audio::postLoad()
{
}

/*********************************************************************
 * Running
 *********************************************************************/
void Audio::preRun(MasterTimer* timer)
{
#ifdef QT_PHONON_LIB
    if (m_object != NULL)
    {
        m_object->play();
        return;
    }
#endif
    if (m_decoder != NULL)
    {
        m_decoder->seek(elapsed());
        AudioParameters ap = m_decoder->audioParameters();
#if defined(__APPLE__)
        //m_audio_out = new AudioRendererCoreAudio();
        m_audio_out = new AudioRendererPortAudio();
#elif defined(WIN32)
        m_audio_out = new AudioRendererWaveOut();
#else
        m_audio_out = new AudioRendererAlsa();
#endif
        m_audio_out->setDecoder(m_decoder);
        m_audio_out->initialize(ap.sampleRate(), ap.channels(), ap.format());
        m_audio_out->start();
    }
    Function::preRun(timer);
}

void Audio::write(MasterTimer* timer, UniverseArray* universes)
{
    Q_UNUSED(timer)
    Q_UNUSED(universes)
}

void Audio::postRun(MasterTimer* timer, UniverseArray* universes)
{
    Q_UNUSED(timer)
    Q_UNUSED(universes)
#ifdef QT_PHONON_LIB
    if (m_object != NULL)
        m_object->stop();
#endif
    if (m_audio_out != NULL)
    {
        m_audio_out->stop();
        delete m_audio_out;
        m_audio_out = NULL;
        m_decoder->seek(0);
    }
    Function::postRun(timer, universes);
}
<commit_msg>Fixed audio volume setting before playback<commit_after>/*
  Q Light Controller
  audio.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

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

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <QDomDocument>
#include <QDomElement>
#include <QDebug>
#include <QFile>

#include <QMessageBox>

#ifdef QT_PHONON_LIB
#include <phonon/mediaobject.h>
#include <phonon/backendcapabilities.h>
#endif

#include "audiodecoder.h"
#ifdef HAS_LIBSNDFILE
  #include "audiodecoder_sndfile.h"
#endif
#ifdef HAS_LIBMAD
  #include "audiodecoder_mad.h"
#endif

#include "audiorenderer.h"

#if defined(__APPLE__)
  //#include "audiorenderer_coreaudio.h"
  #include "audiorenderer_portaudio.h"
#elif defined(WIN32)
  #include "audiorenderer_waveout.h"
#else
  #include "audiorenderer_alsa.h"
#endif
#include "audio.h"
#include "doc.h"

#define KXMLQLCAudioSource "Source"
#define KXMLQLCAudioStartTime "StartTime"
#define KXMLQLCAudioColor "Color"

/*****************************************************************************
 * Initialization
 *****************************************************************************/

Audio::Audio(Doc* doc)
  : Function(doc, Function::Audio)
  , m_doc(doc)
#ifdef QT_PHONON_LIB
  , m_object(NULL)
#endif
  , m_decoder(NULL)
  , m_audio_out(NULL)
  , m_startTime(UINT_MAX)
  , m_color(96, 128, 83)
  , m_sourceFileName("")
  , m_audioDuration(0)
{
    setName(tr("New Audio"));

    // Listen to member Function removals
    connect(doc, SIGNAL(functionRemoved(quint32)),
            this, SLOT(slotFunctionRemoved(quint32)));
}

Audio::~Audio()
{
    if (m_audio_out != NULL)
    {
        m_audio_out->stop();
        delete m_audio_out;
    }
    if (m_decoder != NULL)
        delete m_decoder;
}

/*****************************************************************************
 * Copying
 *****************************************************************************/

Function* Audio::createCopy(Doc* doc, bool addToDoc)
{
    Q_ASSERT(doc != NULL);

    Function* copy = new Audio(doc);
    if (copy->copyFrom(this) == false)
    {
        delete copy;
        copy = NULL;
    }
    if (addToDoc == true && doc->addFunction(copy) == false)
    {
        delete copy;
        copy = NULL;
    }

    return copy;
}

bool Audio::copyFrom(const Function* function)
{
    const Audio* aud = qobject_cast<const Audio*> (function);
    if (aud == NULL)
        return false;

    setSourceFileName(aud->m_sourceFileName);
    m_audioDuration = aud->m_audioDuration;
    m_color = aud->m_color;

    return Function::copyFrom(function);
}

QStringList Audio::getCapabilities()
{
    QStringList cap;
#ifdef QT_PHONON_LIB
    return Phonon::BackendCapabilities::availableMimeTypes();
#endif
#ifdef HAS_LIBSNDFILE
    cap << AudioDecoderSndFile::getSupportedFormats();
#endif
#ifdef HAS_LIBMAD
    cap << AudioDecoderMAD::getSupportedFormats();
#endif
    return cap;
}

/*********************************************************************
 * Properties
 *********************************************************************/
void Audio::setStartTime(quint32 time)
{
    m_startTime = time;
}

quint32 Audio::getStartTime() const
{
    return m_startTime;
}

qint64 Audio::getDuration()
{
    return m_audioDuration;
}

void Audio::setColor(QColor color)
{
    m_color = color;
}

QColor Audio::getColor()
{
    return m_color;
}

bool Audio::setSourceFileName(QString filename)
{
    if (m_sourceFileName.isEmpty() == false)
    {
        // unload previous source
        if (m_decoder != NULL)
        {
            delete m_decoder;
            m_decoder = NULL;
        }
    }

#ifdef QT_PHONON_LIB
    m_object = Phonon::createPlayer(Phonon::MusicCategory,
                                    Phonon::MediaSource(filename));
    if (m_object == NULL)
        return false;
#endif
    m_sourceFileName = filename;

    //QMessageBox::warning(0,"Warning", QString("File complete path: %1").arg(m_sourceFileName));

    if (QFile(m_sourceFileName).exists())
        setName(QFileInfo(m_sourceFileName).fileName());
    else
    {
        setName(tr("File not found"));
        return true;
    }

#ifdef QT_PHONON_LIB
    connect(m_object, SIGNAL(totalTimeChanged(qint64)), this, SLOT(slotTotalTimeChanged(qint64)));
#endif

#ifdef HAS_LIBSNDFILE
    m_decoder = new AudioDecoderSndFile(m_sourceFileName);
    if (m_decoder->initialize() == false)
    {
        delete m_decoder;
        m_decoder = NULL;
    }
    else
    {
        m_audioDuration = m_decoder->totalTime();
        return true;
    }
#endif
#ifdef HAS_LIBMAD
    m_decoder = new AudioDecoderMAD(m_sourceFileName);
    if (m_decoder->initialize() == false)
    {
        delete m_decoder;
        m_decoder = NULL;
    }
    else
    {
        m_audioDuration = m_decoder->totalTime();
        return true;
    }
#endif
    return false;
}

QString Audio::getSourceFileName()
{
    return m_sourceFileName;
}

AudioDecoder* Audio::getAudioDecoder()
{
    return m_decoder;
}

void Audio::adjustAttribute(qreal fraction, int)
{
    if (m_audio_out != NULL)
        m_audio_out->adjustIntensity(fraction);
    Function::adjustAttribute(fraction);
}

void Audio::slotTotalTimeChanged(qint64)
{
#ifdef QT_PHONON_LIB
    m_audioDuration = m_object->totalTime();
#endif
    qDebug() << "Audio duration: " << m_audioDuration;
    emit totalTimeChanged(m_audioDuration);
}

void Audio::slotFunctionRemoved(quint32 fid)
{
    Q_UNUSED(fid)
}

bool Audio::saveXML(QDomDocument* doc, QDomElement* wksp_root)
{
    QDomElement root;
    QDomText text;

    Q_ASSERT(doc != NULL);
    Q_ASSERT(wksp_root != NULL);

    /* Function tag */
    root = doc->createElement(KXMLQLCFunction);
    wksp_root->appendChild(root);

    root.setAttribute(KXMLQLCFunctionID, id());
    root.setAttribute(KXMLQLCFunctionType, Function::typeToString(type()));
    root.setAttribute(KXMLQLCFunctionName, name());

    QDomElement source = doc->createElement(KXMLQLCAudioSource);
    source.setAttribute(KXMLQLCAudioStartTime, m_startTime);
    source.setAttribute(KXMLQLCAudioColor, m_color.name());

    text = doc->createTextNode(m_doc->normalizeComponentPath(m_sourceFileName));

    source.appendChild(text);
    root.appendChild(source);

    return true;
}

bool Audio::loadXML(const QDomElement& root)
{
    if (root.tagName() != KXMLQLCFunction)
    {
        qWarning() << Q_FUNC_INFO << "Function node not found";
        return false;
    }

    if (root.attribute(KXMLQLCFunctionType) != typeToString(Function::Audio))
    {
        qWarning() << Q_FUNC_INFO << root.attribute(KXMLQLCFunctionType)
                   << "is not Audio";
        return false;
    }

    QDomNode node = root.firstChild();
    while (node.isNull() == false)
    {
        QDomElement tag = node.toElement();
        if (tag.tagName() == KXMLQLCAudioSource)
        {
            if (tag.hasAttribute(KXMLQLCAudioStartTime))
                m_startTime = tag.attribute(KXMLQLCAudioStartTime).toUInt();
            if (tag.hasAttribute(KXMLQLCAudioColor))
                m_color = QColor(tag.attribute(KXMLQLCAudioColor));
            setSourceFileName(m_doc->denormalizeComponentPath(tag.text()));
        }
        node = node.nextSibling();
    }

    return true;
}

void Audio::postLoad()
{
}

/*********************************************************************
 * Running
 *********************************************************************/
void Audio::preRun(MasterTimer* timer)
{
#ifdef QT_PHONON_LIB
    if (m_object != NULL)
    {
        m_object->play();
        return;
    }
#endif
    if (m_decoder != NULL)
    {
        m_decoder->seek(elapsed());
        AudioParameters ap = m_decoder->audioParameters();
#if defined(__APPLE__)
        //m_audio_out = new AudioRendererCoreAudio();
        m_audio_out = new AudioRendererPortAudio();
#elif defined(WIN32)
        m_audio_out = new AudioRendererWaveOut();
#else
        m_audio_out = new AudioRendererAlsa();
#endif
        m_audio_out->setDecoder(m_decoder);
        m_audio_out->initialize(ap.sampleRate(), ap.channels(), ap.format());
        m_audio_out->start();
        m_audio_out->adjustIntensity(getAttributeValue());
    }
    Function::preRun(timer);
}

void Audio::write(MasterTimer* timer, UniverseArray* universes)
{
    Q_UNUSED(timer)
    Q_UNUSED(universes)
}

void Audio::postRun(MasterTimer* timer, UniverseArray* universes)
{
    Q_UNUSED(timer)
    Q_UNUSED(universes)
#ifdef QT_PHONON_LIB
    if (m_object != NULL)
        m_object->stop();
#endif
    if (m_audio_out != NULL)
    {
        m_audio_out->stop();
        delete m_audio_out;
        m_audio_out = NULL;
        m_decoder->seek(0);
    }
    Function::postRun(timer, universes);
}
<|endoftext|>


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

#include "amd_isa.h"
#include "driver/shaders/dxbc/dxbc_inspect.h"
#include "official/RGA/Common/AmdDxGsaCompile.h"
#include "official/RGA/elf/elf32.h"
#include "amd_isa_devices.h"

static const char *driverDllErrorMessage = R"(Error loading atidxx64.dll.

Currently atidxx64.dll from AMD's driver package is required for GCN disassembly and it cannot be
distributed with RenderDoc.

To see instructions on how to download and configure it on your system, go to:
https://github.com/baldurk/renderdoc/wiki/GCN_ISA)";

namespace GCNISA
{
std::string LocatePlugin(const std::string &fileName);
};

static HMODULE GetAMDModule()
{
  // first try in the plugin locations
  HMODULE module = LoadLibraryA(GCNISA::LocatePlugin("atidxx64.dll").c_str());

  // if that failed then try checking for it just in the default search path
  if(module == NULL)
    module = LoadLibraryA("atidxx64.dll");

  return module;
}

std::string GCNISA::Disassemble(const DXBC::DXBCFile *dxbc, const std::string &target)
{
  HMODULE mod = GetAMDModule();

  if(mod == NULL)
    return driverDllErrorMessage;

  // if DXBC is NULL we're testing support, so return empty string - indicating no error
  // initialising
  if(dxbc == NULL || target == "")
    return "";

  PfnAmdDxGsaCompileShader compileShader =
      (PfnAmdDxGsaCompileShader)GetProcAddress(mod, "AmdDxGsaCompileShader");
  PfnAmdDxGsaFreeCompiledShader freeShader =
      (PfnAmdDxGsaFreeCompiledShader)GetProcAddress(mod, "AmdDxGsaFreeCompiledShader");

  AmdDxGsaCompileShaderInput in = {};
  AmdDxGsaCompileShaderOutput out = {};

  AmdDxGsaCompileOption opts[1] = {};

  in.inputType = GsaInputDxAsmBin;
  in.numCompileOptions = 0;
  in.pCompileOptions = opts;

  for(const asic &a : asicInfo)
  {
    if(target == a.name)
    {
      in.chipFamily = a.chipFamily;
      in.chipRevision = a.chipRevision;
      break;
    }
  }

  bool amdil = false;
  if(target == "AMDIL")
  {
    in.chipFamily = asicInfo[0].chipFamily;
    in.chipRevision = asicInfo[0].chipRevision;
    amdil = true;
  }

  if(in.chipFamily == 0)
    return "; Invalid ISA Target specified";

  in.pShaderByteCode = dxbc->m_HexDump.data();
  in.byteCodeLength = dxbc->m_HexDump.size();

  out.size = sizeof(out);

  compileShader(&in, &out);

  const uint8_t *elf = (const uint8_t *)out.pShaderBinary;

  const Elf32_Ehdr *elfHeader = (const Elf32_Ehdr *)elf;

  std::string ret;

  // minimal code to extract data from ELF. We assume the ELF we got back is well-formed.
  if(IS_ELF(*elfHeader) && elfHeader->e_ident[EI_CLASS] == ELFCLASS32)
  {
    const Elf32_Shdr *strtab =
        (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * elfHeader->e_shstrndx);

    const uint8_t *strtabData = elf + strtab->sh_offset;

    const AmdDxGsaCompileStats *stats = NULL;

    for(int section = 1; section < elfHeader->e_shnum; section++)
    {
      if(section == elfHeader->e_shstrndx)
        continue;

      const Elf32_Shdr *sectHeader =
          (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * section);

      const char *name = (const char *)(strtabData + sectHeader->sh_name);

      const uint8_t *data = elf + sectHeader->sh_offset;

      if(!strcmp(name, ".stats"))
      {
        stats = (const AmdDxGsaCompileStats *)data;
      }
      else if(amdil && !strcmp(name, ".amdil_disassembly"))
      {
        ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size);
      }
      else if(!amdil && !strcmp(name, ".disassembly"))
      {
        ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size);
      }
    }

    if(stats && !amdil)
    {
      std::string statStr = StringFormat::Fmt(
          R"(; -------- Statistics ---------------------
; SGPRs: %u out of %u used
; VGPRs: %u out of %u used
; LDS: %u out of %u bytes used
; %u bytes scratch space used
; Instructions: %u ALU, %u Control Flow, %u TFETCH

)",
          stats->numSgprsUsed, stats->availableSgprs, stats->numVgprsUsed, stats->availableVgprs,
          stats->usedLdsBytes, stats->availableLdsBytes, stats->usedScratchBytes, stats->numAluInst,
          stats->numControlFlowInst, stats->numTfetchInst);

      ret.insert(ret.begin(), statStr.begin(), statStr.end());
    }

    std::string header = StringFormat::Fmt("; Disassembly for %s\n\n", target.c_str());

    ret.insert(ret.begin(), header.begin(), header.end());
  }
  else
  {
    ret = "; Invalid ELF file generated";
  }

  freeShader(out.pShaderBinary);

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

#include "amd_isa.h"
#include "driver/shaders/dxbc/dxbc_inspect.h"
#include "official/RGA/Common/AmdDxGsaCompile.h"
#include "official/RGA/elf/elf32.h"
#include "amd_isa_devices.h"

#if ENABLED(RDOC_X64)
#define DLL_NAME "atidxx64.dll"
#else
#define DLL_NAME "atidxx32.dll"
#endif

static const char *driverDllErrorMessage = R"(Error loading atidxx64.dll.

Currently atidxx64.dll from AMD's driver package is required for GCN disassembly and it cannot be
distributed with RenderDoc.

To see instructions on how to download and configure it on your system, go to:
https://github.com/baldurk/renderdoc/wiki/GCN_ISA)";

namespace GCNISA
{
std::string LocatePlugin(const std::string &fileName);
};

static HMODULE GetAMDModule()
{
  // first try in the plugin locations
  HMODULE module = LoadLibraryA(GCNISA::LocatePlugin(DLL_NAME).c_str());

  // if that failed then try checking for it just in the default search path
  if(module == NULL)
    module = LoadLibraryA(DLL_NAME);

  return module;
}

std::string GCNISA::Disassemble(const DXBC::DXBCFile *dxbc, const std::string &target)
{
  HMODULE mod = GetAMDModule();

  if(mod == NULL)
    return "; Error loading " DLL_NAME R"(.

; Currently atidxx64.dll from AMD's driver package is required for GCN disassembly and it cannot be
; distributed with RenderDoc.

; To see instructions on how to download and configure it on your system, go to:
; https://github.com/baldurk/renderdoc/wiki/GCN_ISA)";

  // if DXBC is NULL we're testing support, so return empty string - indicating no error
  // initialising
  if(dxbc == NULL || target == "")
    return "";

  PfnAmdDxGsaCompileShader compileShader =
      (PfnAmdDxGsaCompileShader)GetProcAddress(mod, "AmdDxGsaCompileShader");
  PfnAmdDxGsaFreeCompiledShader freeShader =
      (PfnAmdDxGsaFreeCompiledShader)GetProcAddress(mod, "AmdDxGsaFreeCompiledShader");

  AmdDxGsaCompileShaderInput in = {};
  AmdDxGsaCompileShaderOutput out = {};

  AmdDxGsaCompileOption opts[1] = {};

  in.inputType = GsaInputDxAsmBin;
  in.numCompileOptions = 0;
  in.pCompileOptions = opts;

  for(const asic &a : asicInfo)
  {
    if(target == a.name)
    {
      in.chipFamily = a.chipFamily;
      in.chipRevision = a.chipRevision;
      break;
    }
  }

  bool amdil = false;
  if(target == "AMDIL")
  {
    in.chipFamily = asicInfo[0].chipFamily;
    in.chipRevision = asicInfo[0].chipRevision;
    amdil = true;
  }

  if(in.chipFamily == 0)
    return "; Invalid ISA Target specified";

  in.pShaderByteCode = dxbc->m_HexDump.data();
  in.byteCodeLength = dxbc->m_HexDump.size();

  out.size = sizeof(out);

  compileShader(&in, &out);

  const uint8_t *elf = (const uint8_t *)out.pShaderBinary;

  const Elf32_Ehdr *elfHeader = (const Elf32_Ehdr *)elf;

  std::string ret;

  // minimal code to extract data from ELF. We assume the ELF we got back is well-formed.
  if(IS_ELF(*elfHeader) && elfHeader->e_ident[EI_CLASS] == ELFCLASS32)
  {
    const Elf32_Shdr *strtab =
        (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * elfHeader->e_shstrndx);

    const uint8_t *strtabData = elf + strtab->sh_offset;

    const AmdDxGsaCompileStats *stats = NULL;

    for(int section = 1; section < elfHeader->e_shnum; section++)
    {
      if(section == elfHeader->e_shstrndx)
        continue;

      const Elf32_Shdr *sectHeader =
          (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * section);

      const char *name = (const char *)(strtabData + sectHeader->sh_name);

      const uint8_t *data = elf + sectHeader->sh_offset;

      if(!strcmp(name, ".stats"))
      {
        stats = (const AmdDxGsaCompileStats *)data;
      }
      else if(amdil && !strcmp(name, ".amdil_disassembly"))
      {
        ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size);
      }
      else if(!amdil && !strcmp(name, ".disassembly"))
      {
        ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size);
      }
    }

    if(stats && !amdil)
    {
      std::string statStr = StringFormat::Fmt(
          R"(; -------- Statistics ---------------------
; SGPRs: %u out of %u used
; VGPRs: %u out of %u used
; LDS: %u out of %u bytes used
; %u bytes scratch space used
; Instructions: %u ALU, %u Control Flow, %u TFETCH

)",
          stats->numSgprsUsed, stats->availableSgprs, stats->numVgprsUsed, stats->availableVgprs,
          stats->usedLdsBytes, stats->availableLdsBytes, stats->usedScratchBytes, stats->numAluInst,
          stats->numControlFlowInst, stats->numTfetchInst);

      ret.insert(ret.begin(), statStr.begin(), statStr.end());
    }

    std::string header = StringFormat::Fmt("; Disassembly for %s\n\n", target.c_str());

    ret.insert(ret.begin(), header.begin(), header.end());
  }
  else
  {
    ret = "; Invalid ELF file generated";
  }

  freeShader(out.pShaderBinary);

  return ret;
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2018 The Dash Core developers
// Copyright (c) 2018-2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "hash.h"
#include "main.h" // For strMessageMagic
#include "messagesigner.h"
#include "masternodeman.h"  // For GetPublicKey (of MN from its vin)
#include "tinyformat.h"
#include "utilstrencodings.h"

bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet)
{
    CBitcoinSecret vchSecret;

    if(!vchSecret.SetString(strSecret)) return false;

    keyRet = vchSecret.GetKey();
    pubkeyRet = keyRet.GetPubKey();

    return true;
}

uint256 CMessageSigner::GetMessageHash(const std::string& strMessage)
{
    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;
    return ss.GetHash();
}

bool CMessageSigner::SignMessage(const std::string& strMessage, std::vector<unsigned char>& vchSigRet, const CKey& key)
{
    return CHashSigner::SignHash(GetMessageHash(strMessage), key, vchSigRet);
}

bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, const std::string& strMessage, std::string& strErrorRet)
{
    return VerifyMessage(pubkey.GetID(), vchSig, strMessage, strErrorRet);
}

bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector<unsigned char>& vchSig, const std::string& strMessage, std::string& strErrorRet)
{
    return CHashSigner::VerifyHash(GetMessageHash(strMessage), keyID, vchSig, strErrorRet);
}

bool CHashSigner::SignHash(const uint256& hash, const CKey& key, std::vector<unsigned char>& vchSigRet)
{
    return key.SignCompact(hash, vchSigRet);
}

bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
    return VerifyHash(hash, pubkey.GetID(), vchSig, strErrorRet);
}

bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
    CPubKey pubkeyFromSig;
    if(!pubkeyFromSig.RecoverCompact(hash, vchSig)) {
        strErrorRet = "Error recovering public key.";
        return false;
    }

    if(pubkeyFromSig.GetID() != keyID) {
        strErrorRet = strprintf("Keys don't match: pubkey=%s, pubkeyFromSig=%s, hash=%s, vchSig=%s",
                    keyID.ToString(), pubkeyFromSig.GetID().ToString(), hash.ToString(),
                    EncodeBase64(&vchSig[0], vchSig.size()));
        return false;
    }

    return true;
}

/** CSignedMessage Class
 *  Functions inherited by network signed-messages
 */

bool CSignedMessage::Sign(const CKey& key, const CPubKey& pubKey, const bool fNewSigs)
{
    std::string strError = "";

    if (fNewSigs) {
        nMessVersion = MessageVersion::MESS_VER_HASH;
        uint256 hash = GetSignatureHash();

        if(!CHashSigner::SignHash(hash, key, vchSig)) {
            return error("%s : SignHash() failed", __func__);
        }

        if (!CHashSigner::VerifyHash(hash, pubKey, vchSig, strError)) {
            return error("%s : VerifyHash() failed, error: %s", __func__, strError);
        }

    } else {
        nMessVersion = MessageVersion::MESS_VER_STRMESS;
        std::string strMessage = GetStrMessage();

        if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
            return error("%s : SignMessage() failed", __func__);
        }

        if (!CMessageSigner::VerifyMessage(pubKey, vchSig, strMessage, strError)) {
            return error("%s : VerifyMessage() failed, error: %s\n", __func__, strError);
        }
    }

    return true;
}

bool CSignedMessage::Sign(const std::string strSignKey, const bool fNewSigs)
{
    CKey key;
    CPubKey pubkey;

    if (!CMessageSigner::GetKeysFromSecret(strSignKey, key, pubkey)) {
        return error("%s : Invalid strSignKey", __func__);
    }

    return Sign(key, pubkey, fNewSigs);
}

bool CSignedMessage::CheckSignature(const CPubKey& pubKey) const
{
    std::string strError = "";

    if (nMessVersion == MessageVersion::MESS_VER_HASH) {
        uint256 hash = GetSignatureHash();
        if(!CHashSigner::VerifyHash(hash, pubKey, vchSig, strError))
            return error("%s : VerifyHash failed: %s", __func__, strError);

    } else {
        std::string strMessage = GetStrMessage();
        if(!CMessageSigner::VerifyMessage(pubKey, vchSig, strMessage, strError))
            return error("%s : VerifyMessage failed: %s", __func__, strError);
    }

    return true;
}

bool CSignedMessage::CheckSignature(const bool fSignatureCheck) const
{
    std::string strError = "";

    const CPubKey pubkey = GetPublicKey(strError);
    if (pubkey == CPubKey())
        return error("%s : ERROR: %s", __func__, strError);

    return !fSignatureCheck || CheckSignature(pubkey);
}

const CPubKey CSignedMessage::GetPublicKey(std::string& strErrorRet) const
{
    const CTxIn vin = GetVin();
    CMasternode* pmn = mnodeman.Find(vin);
    if(pmn) {
        return pmn->pubKeyMasternode;
    }
    strErrorRet = strprintf("Unable to find masternode vin %s", vin.prevout.hash.GetHex());
    return CPubKey();
}

std::string CSignedMessage::GetSignatureBase64() const
{
    return EncodeBase64(&vchSig[0], vchSig.size());
}

void CSignedMessage::swap(CSignedMessage& first, CSignedMessage& second) // nothrow
{
    // enable ADL (not necessary in our case, but good practice)
    using std::swap;

    // by swapping the members of two classes,
    // the two classes are effectively swapped
    swap(first.vchSig, second.vchSig);
    swap(first.nMessVersion, second.nMessVersion);
}

<commit_msg>[Trivial] better log for CHashSigner::VerifyHash failures<commit_after>// Copyright (c) 2014-2018 The Dash Core developers
// Copyright (c) 2018-2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"
#include "hash.h"
#include "main.h" // For strMessageMagic
#include "messagesigner.h"
#include "masternodeman.h"  // For GetPublicKey (of MN from its vin)
#include "tinyformat.h"
#include "utilstrencodings.h"

bool CMessageSigner::GetKeysFromSecret(const std::string& strSecret, CKey& keyRet, CPubKey& pubkeyRet)
{
    CBitcoinSecret vchSecret;

    if(!vchSecret.SetString(strSecret)) return false;

    keyRet = vchSecret.GetKey();
    pubkeyRet = keyRet.GetPubKey();

    return true;
}

uint256 CMessageSigner::GetMessageHash(const std::string& strMessage)
{
    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;
    return ss.GetHash();
}

bool CMessageSigner::SignMessage(const std::string& strMessage, std::vector<unsigned char>& vchSigRet, const CKey& key)
{
    return CHashSigner::SignHash(GetMessageHash(strMessage), key, vchSigRet);
}

bool CMessageSigner::VerifyMessage(const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, const std::string& strMessage, std::string& strErrorRet)
{
    return VerifyMessage(pubkey.GetID(), vchSig, strMessage, strErrorRet);
}

bool CMessageSigner::VerifyMessage(const CKeyID& keyID, const std::vector<unsigned char>& vchSig, const std::string& strMessage, std::string& strErrorRet)
{
    return CHashSigner::VerifyHash(GetMessageHash(strMessage), keyID, vchSig, strErrorRet);
}

bool CHashSigner::SignHash(const uint256& hash, const CKey& key, std::vector<unsigned char>& vchSigRet)
{
    return key.SignCompact(hash, vchSigRet);
}

bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
    return VerifyHash(hash, pubkey.GetID(), vchSig, strErrorRet);
}

bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
    CPubKey pubkeyFromSig;
    if(!pubkeyFromSig.RecoverCompact(hash, vchSig)) {
        strErrorRet = "Error recovering public key.";
        return false;
    }

    if(pubkeyFromSig.GetID() != keyID) {
        strErrorRet = strprintf("Keys don't match: pubkey=%s, pubkeyFromSig=%s, hash=%s, vchSig=%s",
                CBitcoinAddress(keyID).ToString(), CBitcoinAddress(pubkeyFromSig.GetID()).ToString(),
                hash.ToString(), EncodeBase64(&vchSig[0], vchSig.size()));
        return false;
    }

    return true;
}

/** CSignedMessage Class
 *  Functions inherited by network signed-messages
 */

bool CSignedMessage::Sign(const CKey& key, const CPubKey& pubKey, const bool fNewSigs)
{
    std::string strError = "";

    if (fNewSigs) {
        nMessVersion = MessageVersion::MESS_VER_HASH;
        uint256 hash = GetSignatureHash();

        if(!CHashSigner::SignHash(hash, key, vchSig)) {
            return error("%s : SignHash() failed", __func__);
        }

        if (!CHashSigner::VerifyHash(hash, pubKey, vchSig, strError)) {
            return error("%s : VerifyHash() failed, error: %s", __func__, strError);
        }

    } else {
        nMessVersion = MessageVersion::MESS_VER_STRMESS;
        std::string strMessage = GetStrMessage();

        if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
            return error("%s : SignMessage() failed", __func__);
        }

        if (!CMessageSigner::VerifyMessage(pubKey, vchSig, strMessage, strError)) {
            return error("%s : VerifyMessage() failed, error: %s\n", __func__, strError);
        }
    }

    return true;
}

bool CSignedMessage::Sign(const std::string strSignKey, const bool fNewSigs)
{
    CKey key;
    CPubKey pubkey;

    if (!CMessageSigner::GetKeysFromSecret(strSignKey, key, pubkey)) {
        return error("%s : Invalid strSignKey", __func__);
    }

    return Sign(key, pubkey, fNewSigs);
}

bool CSignedMessage::CheckSignature(const CPubKey& pubKey) const
{
    std::string strError = "";

    if (nMessVersion == MessageVersion::MESS_VER_HASH) {
        uint256 hash = GetSignatureHash();
        if(!CHashSigner::VerifyHash(hash, pubKey, vchSig, strError))
            return error("%s : VerifyHash failed: %s", __func__, strError);

    } else {
        std::string strMessage = GetStrMessage();
        if(!CMessageSigner::VerifyMessage(pubKey, vchSig, strMessage, strError))
            return error("%s : VerifyMessage failed: %s", __func__, strError);
    }

    return true;
}

bool CSignedMessage::CheckSignature(const bool fSignatureCheck) const
{
    std::string strError = "";

    const CPubKey pubkey = GetPublicKey(strError);
    if (pubkey == CPubKey())
        return error("%s : ERROR: %s", __func__, strError);

    return !fSignatureCheck || CheckSignature(pubkey);
}

const CPubKey CSignedMessage::GetPublicKey(std::string& strErrorRet) const
{
    const CTxIn vin = GetVin();
    CMasternode* pmn = mnodeman.Find(vin);
    if(pmn) {
        return pmn->pubKeyMasternode;
    }
    strErrorRet = strprintf("Unable to find masternode vin %s", vin.prevout.hash.GetHex());
    return CPubKey();
}

std::string CSignedMessage::GetSignatureBase64() const
{
    return EncodeBase64(&vchSig[0], vchSig.size());
}

void CSignedMessage::swap(CSignedMessage& first, CSignedMessage& second) // nothrow
{
    // enable ADL (not necessary in our case, but good practice)
    using std::swap;

    // by swapping the members of two classes,
    // the two classes are effectively swapped
    swap(first.vchSig, second.vchSig);
    swap(first.nMessVersion, second.nMessVersion);
}

<|endoftext|>


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

#include "sandbox/win/src/process_mitigations.h"

#include "base/logging.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/nt_internals.h"
#include "sandbox/win/src/sandbox_utils.h"
#include "sandbox/win/src/win_utils.h"

namespace {

// Functions for enabling policies.
typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags);

typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)(
    PROCESS_MITIGATION_POLICY mitigation_policy,
    PVOID buffer,
    SIZE_T length);

typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)(
    DWORD DirectoryFlags);

}  // namespace

namespace sandbox {

bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
  if (!CanSetProcessMitigationsPostStartup(flags))
    return false;

  // We can't apply anything before Win XP, so just return cleanly.
  if (!IsXPSP2OrLater())
    return true;

  base::win::Version version = base::win::GetVersion();
  HMODULE module = ::GetModuleHandleA("kernel32.dll");

  if (version >= base::win::VERSION_VISTA &&
      (flags & MITIGATION_DLL_SEARCH_ORDER)) {
    SetDefaultDllDirectoriesFunction set_default_dll_directories =
        reinterpret_cast<SetDefaultDllDirectoriesFunction>(
            ::GetProcAddress(module, "SetDefaultDllDirectories"));

    // Check for SetDefaultDllDirectories since it requires KB2533623.
    if (set_default_dll_directories) {
      if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) {
        CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
      }
    }
  }

  // Set the heap to terminate on corruption
  if (version >= base::win::VERSION_VISTA &&
      (flags & MITIGATION_HEAP_TERMINATE)) {
    if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption,
                              NULL, 0)) {
      CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
    }
  }

#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
  if (flags & MITIGATION_DEP) {
    DWORD dep_flags = PROCESS_DEP_ENABLE;
    // DEP support is quirky on XP, so don't force a failure in that case.
    const bool return_on_fail = version >= base::win::VERSION_VISTA;

    if (flags & MITIGATION_DEP_NO_ATL_THUNK)
      dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;

    SetProcessDEPPolicyFunction set_process_dep_policy =
        reinterpret_cast<SetProcessDEPPolicyFunction>(
            ::GetProcAddress(module, "SetProcessDEPPolicy"));
    if (set_process_dep_policy) {
      if (!set_process_dep_policy(dep_flags) && return_on_fail) {
        CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
      }
    } else {
      // We're on XP sp2, so use the less standard approach.
      // For reference: http://www.uninformed.org/?v=2&a=4
      const int MEM_EXECUTE_OPTION_ENABLE = 1;
      const int MEM_EXECUTE_OPTION_DISABLE = 2;
      const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
      const int MEM_EXECUTE_OPTION_PERMANENT = 8;

      NtSetInformationProcessFunction set_information_process = NULL;
      ResolveNTFunctionPtr("NtSetInformationProcess",
                           &set_information_process);
      if (!set_information_process)
        return false;
      ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT;
      if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION))
        dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION;
      if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
                                             ProcessExecuteFlags,
                                             &dep, sizeof(dep))) &&
          return_on_fail) {
        CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
      }
    }
  }
#endif

  // This is all we can do in Win7 and below.
  if (version < base::win::VERSION_WIN8)
    return true;

  SetProcessMitigationPolicyFunction set_process_mitigation_policy =
      reinterpret_cast<SetProcessMitigationPolicyFunction>(
          ::GetProcAddress(module, "SetProcessMitigationPolicy"));
  if (!set_process_mitigation_policy)
    return false;

  // Enable ASLR policies.
  if (flags & MITIGATION_RELOCATE_IMAGE) {
    PROCESS_MITIGATION_ASLR_POLICY policy = { 0 };
    policy.EnableForceRelocateImages = true;
    policy.DisallowStrippedImages = (flags &
        MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
        MITIGATION_RELOCATE_IMAGE_REQUIRED;

    if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
                                       sizeof(policy))) {
      CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
    }
  }

  // Enable strict handle policies.
  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
    policy.HandleExceptionsPermanentlyEnabled =
        policy.RaiseExceptionOnInvalidHandleReference = true;

    if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
                                       sizeof(policy))) {
      CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
    }
  }

  // Enable system call policies.
  if (flags & MITIGATION_WIN32K_DISABLE) {
    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
    policy.DisallowWin32kSystemCalls = true;

    if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
                                       sizeof(policy))) {
      CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
    }
  }

  // Enable system call policies.
  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 };
    policy.DisableExtensionPoints = true;

    if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
                                       &policy, sizeof(policy))) {
      CHECK_EQ(ERROR_ACCESS_DENIED, static_cast<long>(::GetLastError()));
    }
  }

  return true;
}

void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
                                       DWORD64* policy_flags, size_t* size) {
  base::win::Version version = base::win::GetVersion();

  *policy_flags = 0;
#if defined(_WIN64)
  *size = sizeof(*policy_flags);
#elif defined(_M_IX86)
  // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
  if (version < base::win::VERSION_WIN8)
    *size = sizeof(DWORD);
  else
    *size = sizeof(*policy_flags);
#else
#error This platform is not supported.
#endif

  // Nothing for Win XP or Vista.
  if (version <= base::win::VERSION_VISTA)
    return;

  if (flags & MITIGATION_DEP) {
    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
    if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
      *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
  }

  if (flags & MITIGATION_SEHOP)
    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;

  // Win 7
  if (version < base::win::VERSION_WIN8)
    return;

  if (flags & MITIGATION_RELOCATE_IMAGE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
    if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
      *policy_flags |=
          PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
    }
  }

  if (flags & MITIGATION_HEAP_TERMINATE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
  }

  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
  }

  if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
  }

  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
  }

  if (flags & MITIGATION_WIN32K_DISABLE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
  }

  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
  }
}

MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
  // Anything prior to XP SP2.
  if (!IsXPSP2OrLater())
    return 0;

  base::win::Version version = base::win::GetVersion();

  // Windows XP SP2+.
  if (version < base::win::VERSION_VISTA) {
    return flags & (MITIGATION_DEP |
                    MITIGATION_DEP_NO_ATL_THUNK);

  // Windows Vista
  if (version < base::win::VERSION_WIN7) {
    return flags & (MITIGATION_DEP |
                    MITIGATION_DEP_NO_ATL_THUNK |
                    MITIGATION_BOTTOM_UP_ASLR |
                    MITIGATION_DLL_SEARCH_ORDER |
                    MITIGATION_HEAP_TERMINATE);
  }

  // Windows 7 and Vista.
  } else if (version < base::win::VERSION_WIN8) {
    return flags & (MITIGATION_BOTTOM_UP_ASLR |
                    MITIGATION_DLL_SEARCH_ORDER |
                    MITIGATION_HEAP_TERMINATE);
  }

  // Windows 8 and above.
  return flags & (MITIGATION_BOTTOM_UP_ASLR |
                  MITIGATION_DLL_SEARCH_ORDER);
}

bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
                                               MitigationFlags flags) {
// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
#if !defined(_WIN64)
  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    unsigned int limit;
    rand_s(&limit);
    char* ptr = 0;
    const size_t kMask64k = 0xFFFF;
    // Random range (512k-16.5mb) in 64k steps.
    const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
    while (ptr < end) {
      MEMORY_BASIC_INFORMATION memory_info;
      if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
        break;
      size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
                             static_cast<SIZE_T>(end - ptr));
      if (ptr && memory_info.State == MEM_FREE)
        ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
      ptr += size;
    }
  }
#endif

  return true;
}

bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
  // All of these mitigations can be enabled after startup.
  return !(flags & ~(MITIGATION_HEAP_TERMINATE |
                     MITIGATION_DEP |
                     MITIGATION_DEP_NO_ATL_THUNK |
                     MITIGATION_RELOCATE_IMAGE |
                     MITIGATION_RELOCATE_IMAGE_REQUIRED |
                     MITIGATION_BOTTOM_UP_ASLR |
                     MITIGATION_STRICT_HANDLE_CHECKS |
                     MITIGATION_WIN32K_DISABLE |
                     MITIGATION_EXTENSION_DLL_DISABLE |
                     MITIGATION_DLL_SEARCH_ORDER));
}

bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
  // These mitigations cannot be enabled prior to startup.
  return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS |
                    MITIGATION_WIN32K_DISABLE |
                    MITIGATION_DLL_SEARCH_ORDER));
}

}  // namespace sandbox

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

#include "sandbox/win/src/process_mitigations.h"

#include "base/win/windows_version.h"
#include "sandbox/win/src/nt_internals.h"
#include "sandbox/win/src/sandbox_utils.h"
#include "sandbox/win/src/win_utils.h"

namespace {

// Functions for enabling policies.
typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags);

typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)(
    PROCESS_MITIGATION_POLICY mitigation_policy,
    PVOID buffer,
    SIZE_T length);

typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)(
    DWORD DirectoryFlags);

}  // namespace

namespace sandbox {

bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
  if (!CanSetProcessMitigationsPostStartup(flags))
    return false;

  // We can't apply anything before Win XP, so just return cleanly.
  if (!IsXPSP2OrLater())
    return true;

  base::win::Version version = base::win::GetVersion();
  HMODULE module = ::GetModuleHandleA("kernel32.dll");

  if (version >= base::win::VERSION_VISTA &&
      (flags & MITIGATION_DLL_SEARCH_ORDER)) {
    SetDefaultDllDirectoriesFunction set_default_dll_directories =
        reinterpret_cast<SetDefaultDllDirectoriesFunction>(
            ::GetProcAddress(module, "SetDefaultDllDirectories"));

    // Check for SetDefaultDllDirectories since it requires KB2533623.
    if (set_default_dll_directories) {
      if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) &&
          ERROR_ACCESS_DENIED != ::GetLastError()) {
        return false;
      }
    }
  }

  // Set the heap to terminate on corruption
  if (version >= base::win::VERSION_VISTA &&
      (flags & MITIGATION_HEAP_TERMINATE)) {
    if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption,
                              NULL, 0) &&
        ERROR_ACCESS_DENIED != ::GetLastError()) {
      return false;
    }
  }

#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
  if (flags & MITIGATION_DEP) {
    DWORD dep_flags = PROCESS_DEP_ENABLE;
    // DEP support is quirky on XP, so don't force a failure in that case.
    const bool return_on_fail = version >= base::win::VERSION_VISTA;

    if (flags & MITIGATION_DEP_NO_ATL_THUNK)
      dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;

    SetProcessDEPPolicyFunction set_process_dep_policy =
        reinterpret_cast<SetProcessDEPPolicyFunction>(
            ::GetProcAddress(module, "SetProcessDEPPolicy"));
    if (set_process_dep_policy) {
      if (!set_process_dep_policy(dep_flags) &&
          ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
        return false;
      }
    } else {
      // We're on XP sp2, so use the less standard approach.
      // For reference: http://www.uninformed.org/?v=2&a=4
      const int MEM_EXECUTE_OPTION_ENABLE = 1;
      const int MEM_EXECUTE_OPTION_DISABLE = 2;
      const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
      const int MEM_EXECUTE_OPTION_PERMANENT = 8;

      NtSetInformationProcessFunction set_information_process = NULL;
      ResolveNTFunctionPtr("NtSetInformationProcess",
                           &set_information_process);
      if (!set_information_process)
        return false;
      ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT;
      if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION))
        dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION;
      if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
                                             ProcessExecuteFlags,
                                             &dep, sizeof(dep))) &&
          ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
        return false;
      }
    }
  }
#endif

  // This is all we can do in Win7 and below.
  if (version < base::win::VERSION_WIN8)
    return true;

  SetProcessMitigationPolicyFunction set_process_mitigation_policy =
      reinterpret_cast<SetProcessMitigationPolicyFunction>(
          ::GetProcAddress(module, "SetProcessMitigationPolicy"));
  if (!set_process_mitigation_policy)
    return false;

  // Enable ASLR policies.
  if (flags & MITIGATION_RELOCATE_IMAGE) {
    PROCESS_MITIGATION_ASLR_POLICY policy = { 0 };
    policy.EnableForceRelocateImages = true;
    policy.DisallowStrippedImages = (flags &
        MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
        MITIGATION_RELOCATE_IMAGE_REQUIRED;

    if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
                                       sizeof(policy)) &&
        ERROR_ACCESS_DENIED != ::GetLastError()) {
      return false;
    }
  }

  // Enable strict handle policies.
  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
    policy.HandleExceptionsPermanentlyEnabled =
        policy.RaiseExceptionOnInvalidHandleReference = true;

    if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
                                       sizeof(policy)) &&
        ERROR_ACCESS_DENIED != ::GetLastError()) {
      return false;
    }
  }

  // Enable system call policies.
  if (flags & MITIGATION_WIN32K_DISABLE) {
    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
    policy.DisallowWin32kSystemCalls = true;

    if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
                                       sizeof(policy)) &&
        ERROR_ACCESS_DENIED != ::GetLastError()) {
      return false;
    }
  }

  // Enable system call policies.
  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 };
    policy.DisableExtensionPoints = true;

    if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
                                       &policy, sizeof(policy)) &&
        ERROR_ACCESS_DENIED != ::GetLastError()) {
      return false;
    }
  }

  return true;
}

void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
                                       DWORD64* policy_flags, size_t* size) {
  base::win::Version version = base::win::GetVersion();

  *policy_flags = 0;
#if defined(_WIN64)
  *size = sizeof(*policy_flags);
#elif defined(_M_IX86)
  // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
  if (version < base::win::VERSION_WIN8)
    *size = sizeof(DWORD);
  else
    *size = sizeof(*policy_flags);
#else
#error This platform is not supported.
#endif

  // Nothing for Win XP or Vista.
  if (version <= base::win::VERSION_VISTA)
    return;

  if (flags & MITIGATION_DEP) {
    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
    if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
      *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
  }

  if (flags & MITIGATION_SEHOP)
    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;

  // Win 7
  if (version < base::win::VERSION_WIN8)
    return;

  if (flags & MITIGATION_RELOCATE_IMAGE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
    if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
      *policy_flags |=
          PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
    }
  }

  if (flags & MITIGATION_HEAP_TERMINATE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
  }

  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
  }

  if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
  }

  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
  }

  if (flags & MITIGATION_WIN32K_DISABLE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
  }

  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    *policy_flags |=
        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
  }
}

MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
  // Anything prior to XP SP2.
  if (!IsXPSP2OrLater())
    return 0;

  base::win::Version version = base::win::GetVersion();

  // Windows XP SP2+.
  if (version < base::win::VERSION_VISTA) {
    return flags & (MITIGATION_DEP |
                    MITIGATION_DEP_NO_ATL_THUNK);

  // Windows Vista
  if (version < base::win::VERSION_WIN7) {
    return flags & (MITIGATION_DEP |
                    MITIGATION_DEP_NO_ATL_THUNK |
                    MITIGATION_BOTTOM_UP_ASLR |
                    MITIGATION_DLL_SEARCH_ORDER |
                    MITIGATION_HEAP_TERMINATE);
  }

  // Windows 7 and Vista.
  } else if (version < base::win::VERSION_WIN8) {
    return flags & (MITIGATION_BOTTOM_UP_ASLR |
                    MITIGATION_DLL_SEARCH_ORDER |
                    MITIGATION_HEAP_TERMINATE);
  }

  // Windows 8 and above.
  return flags & (MITIGATION_BOTTOM_UP_ASLR |
                  MITIGATION_DLL_SEARCH_ORDER);
}

bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
                                               MitigationFlags flags) {
// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
#if !defined(_WIN64)
  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    unsigned int limit;
    rand_s(&limit);
    char* ptr = 0;
    const size_t kMask64k = 0xFFFF;
    // Random range (512k-16.5mb) in 64k steps.
    const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
    while (ptr < end) {
      MEMORY_BASIC_INFORMATION memory_info;
      if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
        break;
      size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
                             static_cast<SIZE_T>(end - ptr));
      if (ptr && memory_info.State == MEM_FREE)
        ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
      ptr += size;
    }
  }
#endif

  return true;
}

bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
  // All of these mitigations can be enabled after startup.
  return !(flags & ~(MITIGATION_HEAP_TERMINATE |
                     MITIGATION_DEP |
                     MITIGATION_DEP_NO_ATL_THUNK |
                     MITIGATION_RELOCATE_IMAGE |
                     MITIGATION_RELOCATE_IMAGE_REQUIRED |
                     MITIGATION_BOTTOM_UP_ASLR |
                     MITIGATION_STRICT_HANDLE_CHECKS |
                     MITIGATION_WIN32K_DISABLE |
                     MITIGATION_EXTENSION_DLL_DISABLE |
                     MITIGATION_DLL_SEARCH_ORDER));
}

bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
  // These mitigations cannot be enabled prior to startup.
  return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS |
                    MITIGATION_WIN32K_DISABLE |
                    MITIGATION_DLL_SEARCH_ORDER));
}

}  // namespace sandbox

<|endoftext|>


<commit_before>/* Lantern - A path tracer
*
* Lantern is the legal property of Adrian Astley
* Copyright Adrian Astley 2015
*/

#include <GLFW/glfw3.h>

#include <cstdio>
#include <exception>

static void error_callback(int error, const char *description) {
	printf("Error %d: %s\n", error, description);
}

int main(int argc, const char *argv[]) {
	// Setup window
	glfwSetErrorCallback(error_callback);
	if (!glfwInit()) {
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	GLFWwindow* window = glfwCreateWindow(1280, 720, "Lantern", NULL, NULL);
	glfwMakeContextCurrent(window);

	glfwSwapInterval(1);
	while (!glfwWindowShouldClose(window)) {
		float ratio;
		int width, height;

		glfwGetFramebufferSize(window, &width, &height);
		ratio = width / (float)height;

		glViewport(0, 0, width, height);
		glClear(GL_COLOR_BUFFER_BIT);

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
		glMatrixMode(GL_MODELVIEW);

		glLoadIdentity();
		glRotatef((float)glfwGetTime() * 50.f, 0.f, 0.f, 1.f);

		glBegin(GL_TRIANGLES);
		glColor3f(1.f, 0.f, 0.f);
		glVertex3f(-0.6f, -0.4f, 0.f);
		glColor3f(0.f, 1.f, 0.f);
		glVertex3f(0.6f, -0.4f, 0.f);
		glColor3f(0.f, 0.f, 1.f);
		glVertex3f(0.f, 0.6f, 0.f);
		glEnd();

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);

	// Cleanup
	glfwTerminate();
}
<commit_msg>Convert main to use Visualizer and Renderer<commit_after>/* Lantern - A path tracer
*
* Lantern is the legal property of Adrian Astley
* Copyright Adrian Astley 2015 - 2016
*/

#include "common/atomic_frame_buffer.h"

#include "visualizer/visualizer.h"
#include "renderer/renderer.h"

#include <xmmintrin.h>
#include <pmmintrin.h>

#include <thread>

void StartRendererWrapper(Lantern::Renderer *renderer) {
	renderer->Start();
}

int main(int argc, const char *argv[]) {
	_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
	_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);

	Lantern::AtomicFrameBuffer frameBuffer(1280, 720);

	Lantern::Renderer renderer(&frameBuffer);
	std::thread renderThread(StartRendererWrapper, &renderer);

	Lantern::Visualizer visualizer(&frameBuffer);
	visualizer.Run();

	renderThread.join();
}
<|endoftext|>