<commit_before>#include <bts/rpc/rpc_client.hpp>
#include <bts/net/stcp_socket.hpp>
#include <bts/blockchain/address.hpp>
#include <bts/blockchain/transaction.hpp>
#include <bts/blockchain/block.hpp>
#include <bts/utilities/key_conversion.hpp>
#include <bts/utilities/padding_ostream.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/network/tcp_socket.hpp>
#include <fc/rpc/json_connection.hpp>
#include <fc/thread/thread.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/digest.hpp>
#include <fc/thread/future.hpp>

#include <bts/rpc_stubs/common_api_rpc_client.hpp>

namespace bts { namespace rpc {

  namespace detail
  {
    class rpc_client_impl : public bts::rpc_stubs::common_api_rpc_client
    {
    public:
      fc::rpc::json_connection_ptr _json_connection;
      fc::future<void> _json_exec_loop_complete;

      virtual fc::rpc::json_connection_ptr get_json_connection() const override { return _json_connection; }
      void connect_to(const fc::ip::endpoint& remote_endpoint, const blockchain::public_key_type& remote_public_key);
      bool login(const std::string& username, const std::string& password);
    };

    void rpc_client_impl::connect_to(const fc::ip::endpoint& remote_endpoint,
                                     const bts::blockchain::public_key_type& remote_public_key)
    {
       fc::buffered_istream_ptr buffered_istream;
       fc::buffered_ostream_ptr buffered_ostream;

       if( remote_public_key != bts::blockchain::public_key_type() )
       {
          net::stcp_socket_ptr socket = std::make_shared<bts::net::stcp_socket>();

          try
          {
             socket->connect_to(remote_endpoint);
          }
          catch ( const fc::exception& e )
          {
             elog( "fatal: error opening RPC socket to endpoint ${endpoint}: ${e}", ("endpoint", remote_endpoint)("e", e.to_detail_string() ) );
             throw;
          }

          fc::ecc::compact_signature signature;
          fc::raw::unpack(*socket, signature);
          wdump((signature));
          FC_ASSERT(blockchain::public_key_type(fc::ecc::public_key(signature, fc::digest(socket->get_shared_secret())))
                    == remote_public_key,
                    "Unable to establish secure connection with server.");

          buffered_istream = std::make_shared<fc::buffered_istream>(socket);
          buffered_ostream = std::make_shared<utilities::padding_ostream<>>(socket);
       } else {
          fc::tcp_socket_ptr socket = std::make_shared<fc::tcp_socket>();

          try
          {
             socket->connect_to(remote_endpoint);
          }
          catch ( const fc::exception& e )
          {
             elog( "fatal: error opening RPC socket to endpoint ${endpoint}: ${e}", ("endpoint", remote_endpoint)("e", e.to_detail_string() ) );
             throw;
          }

          buffered_istream = std::make_shared<fc::buffered_istream>(socket);
          buffered_ostream = std::make_shared<fc::buffered_ostream>(socket);
       }

       _json_connection = std::make_shared<fc::rpc::json_connection>(std::move(buffered_istream),
                                                                     std::move(buffered_ostream));
       _json_exec_loop_complete = fc::async([=](){ _json_connection->exec(); }, "json exec loop");
    }
    bool rpc_client_impl::login(const std::string& username, const std::string& password)
    {
      return _json_connection->call<bool>("login", username, password);
    }

  } // end namespace detail

  rpc_client::rpc_client() :
    my(new detail::rpc_client_impl)
  {
  }

  rpc_client::~rpc_client()
  {
  }

  void rpc_client::connect_to(const fc::ip::endpoint& remote_endpoint,
                              const bts::blockchain::public_key_type& remote_public_key)
  {
    my->connect_to(remote_endpoint, remote_public_key);
  }

  bool rpc_client::login(const std::string& username, const std::string& password)
  {
    return my->login(username, password);
  }

  fc::rpc::json_connection_ptr rpc_client::get_json_connection() const
  {
    return my->_json_connection;
  }

} } // bts::rpc
<commit_msg>Attempt to fix crash on exit<commit_after>#include <bts/rpc/rpc_client.hpp>
#include <bts/net/stcp_socket.hpp>
#include <bts/blockchain/address.hpp>
#include <bts/blockchain/transaction.hpp>
#include <bts/blockchain/block.hpp>
#include <bts/utilities/key_conversion.hpp>
#include <bts/utilities/padding_ostream.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/network/tcp_socket.hpp>
#include <fc/rpc/json_connection.hpp>
#include <fc/thread/thread.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/digest.hpp>
#include <fc/thread/future.hpp>

#include <bts/rpc_stubs/common_api_rpc_client.hpp>

namespace bts { namespace rpc {

  namespace detail
  {
    class rpc_client_impl : public bts::rpc_stubs::common_api_rpc_client
    {
    public:
      fc::rpc::json_connection_ptr _json_connection;
      fc::future<void> _json_exec_loop_complete;

      virtual fc::rpc::json_connection_ptr get_json_connection() const override { return _json_connection; }
      void connect_to(const fc::ip::endpoint& remote_endpoint, const blockchain::public_key_type& remote_public_key);
      bool login(const std::string& username, const std::string& password);
    };

    void rpc_client_impl::connect_to(const fc::ip::endpoint& remote_endpoint,
                                     const bts::blockchain::public_key_type& remote_public_key)
    {
       fc::buffered_istream_ptr buffered_istream;
       fc::buffered_ostream_ptr buffered_ostream;

       if( remote_public_key != bts::blockchain::public_key_type() )
       {
          net::stcp_socket_ptr socket = std::make_shared<bts::net::stcp_socket>();

          try
          {
             socket->connect_to(remote_endpoint);
          }
          catch ( const fc::exception& e )
          {
             elog( "fatal: error opening RPC socket to endpoint ${endpoint}: ${e}", ("endpoint", remote_endpoint)("e", e.to_detail_string() ) );
             throw;
          }

          fc::ecc::compact_signature signature;
          fc::raw::unpack(*socket, signature);
          wdump((signature));
          FC_ASSERT(blockchain::public_key_type(fc::ecc::public_key(signature, fc::digest(socket->get_shared_secret())))
                    == remote_public_key,
                    "Unable to establish secure connection with server.");

          buffered_istream = std::make_shared<fc::buffered_istream>(socket);
          buffered_ostream = std::make_shared<utilities::padding_ostream<>>(socket);
       } else {
          fc::tcp_socket_ptr socket = std::make_shared<fc::tcp_socket>();

          try
          {
             socket->connect_to(remote_endpoint);
          }
          catch ( const fc::exception& e )
          {
             elog( "fatal: error opening RPC socket to endpoint ${endpoint}: ${e}", ("endpoint", remote_endpoint)("e", e.to_detail_string() ) );
             throw;
          }

          buffered_istream = std::make_shared<fc::buffered_istream>(socket);
          buffered_ostream = std::make_shared<fc::buffered_ostream>(socket);
       }

       _json_connection = std::make_shared<fc::rpc::json_connection>(std::move(buffered_istream),
                                                                     std::move(buffered_ostream));
       _json_exec_loop_complete = fc::async([=](){ _json_connection->exec(); }, "json exec loop");
    }
    bool rpc_client_impl::login(const std::string& username, const std::string& password)
    {
      return _json_connection->call<bool>("login", username, password);
    }

  } // end namespace detail

  rpc_client::rpc_client() :
    my(new detail::rpc_client_impl)
  {
  }

  rpc_client::~rpc_client()
  {
     try
     {
        my->_json_exec_loop_complete.cancel_and_wait("~rpc_client()");
     } catch (const fc::exception& e) {
        wlog("Caught exception ${e} while canceling json_connection exec loop", ("e", e));
     }
  }

  void rpc_client::connect_to(const fc::ip::endpoint& remote_endpoint,
                              const bts::blockchain::public_key_type& remote_public_key)
  {
    my->connect_to(remote_endpoint, remote_public_key);
  }

  bool rpc_client::login(const std::string& username, const std::string& password)
  {
    return my->login(username, password);
  }

  fc::rpc::json_connection_ptr rpc_client::get_json_connection() const
  {
    return my->_json_connection;
  }

} } // bts::rpc
<|endoftext|>


<commit_before><commit_msg>Replace the NOTIMPLEMENTED() in NPN_ForceRedraw with a comment<commit_after><|endoftext|>


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

#include "webkit/glue/plugins/plugin_list.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_switches.h"
#include "webkit/glue/webkit_glue.h"

namespace NPAPI {

base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);

// static
PluginList* PluginList::Singleton() {
  return g_singleton.Pointer();
}

// static
bool PluginList::DebugPluginLoading() {
  return CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDebugPluginLoading);
}

bool PluginList::PluginsLoaded() {
  AutoLock lock(lock_);
  return plugins_loaded_;
}

void PluginList::RefreshPlugins() {
  AutoLock lock(lock_);
  plugins_need_refresh_ = true;
}

void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_paths_.push_back(plugin_path);
#endif
}

void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
  AutoLock lock(lock_);
  std::vector<FilePath>::iterator it =
      std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
                plugin_path);
  if (it != extra_plugin_paths_.end())
    extra_plugin_paths_.erase(it);
}

void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_dirs_.push_back(plugin_dir);
#endif
}

void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
  AutoLock lock(lock_);
  internal_plugins_.push_back(info);
}

void PluginList::UnregisterInternalPlugin(const FilePath& path) {
  AutoLock lock(lock_);
  for (size_t i = 0; i < internal_plugins_.size(); i++) {
    if (internal_plugins_[i].path == path) {
      internal_plugins_.erase(internal_plugins_.begin() + i);
      return;
    }
  }
  NOTREACHED();
}

bool PluginList::ReadPluginInfo(const FilePath& filename,
                                WebPluginInfo* info,
                                const PluginEntryPoints** entry_points) {
  {
    AutoLock lock(lock_);
    for (size_t i = 0; i < internal_plugins_.size(); ++i) {
      if (filename == internal_plugins_[i].path) {
        *entry_points = &internal_plugins_[i].entry_points;
        return CreateWebPluginInfo(internal_plugins_[i], info);
      }
    }
  }

  // Not an internal plugin.
  *entry_points = NULL;

  return PluginLib::ReadWebPluginInfo(filename, info);
}

bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
                                     WebPluginInfo* info) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<string16> descriptions;
  SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
  SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
  SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions);

  info->mime_types.clear();

  if (mime_types.empty()) {
    LOG_IF(ERROR, PluginList::DebugPluginLoading())
        << "Plugin " << pvi.product_name << " has no MIME types, skipping";
    return false;
  }

  info->name = WideToUTF16(pvi.product_name);
  info->desc = WideToUTF16(pvi.file_description);
  info->version = WideToUTF16(pvi.file_version);
  info->path = pvi.path;
  info->enabled = true;

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // On Windows, the description likely has a list of file extensions
      // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
      // list from the description if it is present.
      size_t ext = mime_type.description.find(ASCIIToUTF16("(*"));
      if (ext != string16::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return true;
}

PluginList::PluginList()
    : plugins_loaded_(false), plugins_need_refresh_(false) {
  PlatformInit();
}

void PluginList::LoadPlugins(bool refresh) {
  // Don't want to hold the lock while loading new plugins, so we don't block
  // other methods if they're called on other threads.
  std::vector<FilePath> extra_plugin_paths;
  std::vector<FilePath> extra_plugin_dirs;
  std::vector<PluginVersionInfo> internal_plugins;
  {
    AutoLock lock(lock_);
    if (plugins_loaded_ && !refresh && !plugins_need_refresh_)
      return;

    // Clear the refresh bit now, because it might get set again before we
    // reach the end of the method.
    plugins_need_refresh_ = false;
    extra_plugin_paths = extra_plugin_paths_;
    extra_plugin_dirs = extra_plugin_dirs_;
    internal_plugins = internal_plugins_;
  }

  base::TimeTicks start_time = base::TimeTicks::Now();

  std::vector<WebPluginInfo> new_plugins;
  std::set<FilePath> visited_plugins;

  std::vector<FilePath> directories_to_scan;
  GetPluginDirectories(&directories_to_scan);

  // Load internal plugins first so that, if both an internal plugin and a
  // "discovered" plugin want to handle the same type, the internal plugin
  // will have precedence.
  for (size_t i = 0; i < internal_plugins.size(); ++i) {
    if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
      continue;
    LoadPlugin(internal_plugins[i].path, &new_plugins);
  }

  for (size_t i = 0; i < extra_plugin_paths.size(); ++i) {
    const FilePath& path = extra_plugin_paths[i];
    if (visited_plugins.find(path) != visited_plugins.end())
      continue;
    LoadPlugin(path, &new_plugins);
    visited_plugins.insert(path);
  }

  for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
    LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins);
  }

  for (size_t i = 0; i < directories_to_scan.size(); ++i) {
    LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins);
  }

#if defined OS_WIN
  LoadPluginsFromRegistry(&new_plugins, &visited_plugins);
#endif

  // Load the default plugin last.
  if (webkit_glue::IsDefaultPluginEnabled())
    LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);

  base::TimeTicks end_time = base::TimeTicks::Now();
  base::TimeDelta elapsed = end_time - start_time;
  DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";

  // Only update the data now since loading plugins can take a while.
  AutoLock lock(lock_);

  // Go through and mark new plugins in the disabled list as, well, disabled.
  for (std::vector<WebPluginInfo>::iterator it = new_plugins.begin();
       it != new_plugins.end();
       ++it) {
    if (disabled_plugins_.find(it->path) != disabled_plugins_.end())
      it->enabled = false;
  }

  plugins_ = new_plugins;
  plugins_loaded_ = true;
}

void PluginList::LoadPlugin(const FilePath& path,
                            std::vector<WebPluginInfo>* plugins) {
  LOG_IF(ERROR, PluginList::DebugPluginLoading())
      << "Loading plugin " << path.value();

  WebPluginInfo plugin_info;
  const PluginEntryPoints* entry_points;

  if (!ReadPluginInfo(path, &plugin_info, &entry_points))
    return;

  if (!ShouldLoadPlugin(plugin_info, plugins))
    return;

  if (path.value() != kDefaultPluginLibraryName
#if defined(OS_WIN) && !defined(NDEBUG)
      && path.BaseName().value() != L"npspy.dll"  // Make an exception for NPSPY
#endif
      ) {
    for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
      // TODO: don't load global handlers for now.
      // WebKit hands to the Plugin before it tries
      // to handle mimeTypes on its own.
      const std::string &mime_type = plugin_info.mime_types[i].mime_type;
      if (mime_type == "*" )
        return;
    }
  }

  plugins->push_back(plugin_info);
}

bool PluginList::FindPlugin(const std::string& mime_type,
                            bool allow_wildcard,
                            WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindDisabledPlugin(const std::string& mime_type,
                                    bool allow_wildcard,
                                    WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (!plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindPlugin(const GURL &url,
                            std::string* actual_mime_type,
                            WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  std::string path = url.path();
  std::string::size_type last_dot = path.rfind('.');
  if (last_dot == std::string::npos)
    return false;

  std::string extension = StringToLowerASCII(std::string(path, last_dot+1));

  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsExtension(plugins_[i], extension, actual_mime_type)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::SupportsType(const WebPluginInfo& info,
                              const std::string &mime_type,
                              bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = info.mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && mime_info.mime_type == "*") {
        continue;
      }
      return true;
    }
  }
  return false;
}

bool PluginList::SupportsExtension(const WebPluginInfo& info,
                                   const std::string &extension,
                                   std::string* actual_mime_type) {
  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_type = info.mime_types[i];
    for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
      if (mime_type.file_extensions[j] == extension) {
        if (actual_mime_type)
          *actual_mime_type = mime_type.mime_type;
        return true;
      }
    }
  }

  return false;
}

void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  AutoLock lock(lock_);
  *plugins = plugins_;
}

void PluginList::GetEnabledPlugins(bool refresh,
                                   std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  plugins->clear();
  AutoLock lock(lock_);
  for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->enabled)
      plugins->push_back(*it);
  }
}

bool PluginList::GetPluginInfo(const GURL& url,
                               const std::string& mime_type,
                               bool allow_wildcard,
                               WebPluginInfo* info,
                               std::string* actual_mime_type) {
  bool found = FindPlugin(mime_type, allow_wildcard, info);
  if (!found || (info->path.value() == kDefaultPluginLibraryName)) {
    if (FindPlugin(url, actual_mime_type, info) ||
        FindDisabledPlugin(mime_type, allow_wildcard, info)) {
      found = true;
    }
  }

  return found;
}

bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
                                     WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].path == plugin_path) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::EnablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_enable = false;

  std::set<FilePath>::iterator entry = disabled_plugins_.find(filename);
  if (entry == disabled_plugins_.end())
    return did_enable;  // Early exit if plugin not in disabled list.

  disabled_plugins_.erase(entry);  // Remove from disabled list.

  // Set enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(!it->enabled);  // Should have been disabled.
      it->enabled = true;
      did_enable = true;
    }
  }

  return did_enable;
}

bool PluginList::DisablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_disable = false;

  if (disabled_plugins_.find(filename) != disabled_plugins_.end())
    return did_disable;  // Early exit if plugin already in disabled list.

  disabled_plugins_.insert(filename);  // Add to disabled list.

  // Unset enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(it->enabled);  // Should have been enabled.
      it->enabled = false;
      did_disable = true;
    }
  }

  return did_disable;
}

void PluginList::Shutdown() {
  // TODO
}

}  // namespace NPAPI
<commit_msg>Reduce console DLOG(INFO) spam in plugin_list<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/plugins/plugin_list.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_switches.h"
#include "webkit/glue/webkit_glue.h"

namespace NPAPI {

base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);

// static
PluginList* PluginList::Singleton() {
  return g_singleton.Pointer();
}

// static
bool PluginList::DebugPluginLoading() {
  return CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDebugPluginLoading);
}

bool PluginList::PluginsLoaded() {
  AutoLock lock(lock_);
  return plugins_loaded_;
}

void PluginList::RefreshPlugins() {
  AutoLock lock(lock_);
  plugins_need_refresh_ = true;
}

void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_paths_.push_back(plugin_path);
#endif
}

void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
  AutoLock lock(lock_);
  std::vector<FilePath>::iterator it =
      std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
                plugin_path);
  if (it != extra_plugin_paths_.end())
    extra_plugin_paths_.erase(it);
}

void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_dirs_.push_back(plugin_dir);
#endif
}

void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
  AutoLock lock(lock_);
  internal_plugins_.push_back(info);
}

void PluginList::UnregisterInternalPlugin(const FilePath& path) {
  AutoLock lock(lock_);
  for (size_t i = 0; i < internal_plugins_.size(); i++) {
    if (internal_plugins_[i].path == path) {
      internal_plugins_.erase(internal_plugins_.begin() + i);
      return;
    }
  }
  NOTREACHED();
}

bool PluginList::ReadPluginInfo(const FilePath& filename,
                                WebPluginInfo* info,
                                const PluginEntryPoints** entry_points) {
  {
    AutoLock lock(lock_);
    for (size_t i = 0; i < internal_plugins_.size(); ++i) {
      if (filename == internal_plugins_[i].path) {
        *entry_points = &internal_plugins_[i].entry_points;
        return CreateWebPluginInfo(internal_plugins_[i], info);
      }
    }
  }

  // Not an internal plugin.
  *entry_points = NULL;

  return PluginLib::ReadWebPluginInfo(filename, info);
}

bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
                                     WebPluginInfo* info) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<string16> descriptions;
  SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
  SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
  SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions);

  info->mime_types.clear();

  if (mime_types.empty()) {
    LOG_IF(ERROR, PluginList::DebugPluginLoading())
        << "Plugin " << pvi.product_name << " has no MIME types, skipping";
    return false;
  }

  info->name = WideToUTF16(pvi.product_name);
  info->desc = WideToUTF16(pvi.file_description);
  info->version = WideToUTF16(pvi.file_version);
  info->path = pvi.path;
  info->enabled = true;

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // On Windows, the description likely has a list of file extensions
      // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
      // list from the description if it is present.
      size_t ext = mime_type.description.find(ASCIIToUTF16("(*"));
      if (ext != string16::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return true;
}

PluginList::PluginList()
    : plugins_loaded_(false), plugins_need_refresh_(false) {
  PlatformInit();
}

void PluginList::LoadPlugins(bool refresh) {
  // Don't want to hold the lock while loading new plugins, so we don't block
  // other methods if they're called on other threads.
  std::vector<FilePath> extra_plugin_paths;
  std::vector<FilePath> extra_plugin_dirs;
  std::vector<PluginVersionInfo> internal_plugins;
  {
    AutoLock lock(lock_);
    if (plugins_loaded_ && !refresh && !plugins_need_refresh_)
      return;

    // Clear the refresh bit now, because it might get set again before we
    // reach the end of the method.
    plugins_need_refresh_ = false;
    extra_plugin_paths = extra_plugin_paths_;
    extra_plugin_dirs = extra_plugin_dirs_;
    internal_plugins = internal_plugins_;
  }

  std::vector<WebPluginInfo> new_plugins;
  std::set<FilePath> visited_plugins;

  std::vector<FilePath> directories_to_scan;
  GetPluginDirectories(&directories_to_scan);

  // Load internal plugins first so that, if both an internal plugin and a
  // "discovered" plugin want to handle the same type, the internal plugin
  // will have precedence.
  for (size_t i = 0; i < internal_plugins.size(); ++i) {
    if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
      continue;
    LoadPlugin(internal_plugins[i].path, &new_plugins);
  }

  for (size_t i = 0; i < extra_plugin_paths.size(); ++i) {
    const FilePath& path = extra_plugin_paths[i];
    if (visited_plugins.find(path) != visited_plugins.end())
      continue;
    LoadPlugin(path, &new_plugins);
    visited_plugins.insert(path);
  }

  for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
    LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins);
  }

  for (size_t i = 0; i < directories_to_scan.size(); ++i) {
    LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins);
  }

#if defined OS_WIN
  LoadPluginsFromRegistry(&new_plugins, &visited_plugins);
#endif

  // Load the default plugin last.
  if (webkit_glue::IsDefaultPluginEnabled())
    LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);

  // Only update the data now since loading plugins can take a while.
  AutoLock lock(lock_);

  // Go through and mark new plugins in the disabled list as, well, disabled.
  for (std::vector<WebPluginInfo>::iterator it = new_plugins.begin();
       it != new_plugins.end();
       ++it) {
    if (disabled_plugins_.find(it->path) != disabled_plugins_.end())
      it->enabled = false;
  }

  plugins_ = new_plugins;
  plugins_loaded_ = true;
}

void PluginList::LoadPlugin(const FilePath& path,
                            std::vector<WebPluginInfo>* plugins) {
  LOG_IF(ERROR, PluginList::DebugPluginLoading())
      << "Loading plugin " << path.value();

  WebPluginInfo plugin_info;
  const PluginEntryPoints* entry_points;

  if (!ReadPluginInfo(path, &plugin_info, &entry_points))
    return;

  if (!ShouldLoadPlugin(plugin_info, plugins))
    return;

  if (path.value() != kDefaultPluginLibraryName
#if defined(OS_WIN) && !defined(NDEBUG)
      && path.BaseName().value() != L"npspy.dll"  // Make an exception for NPSPY
#endif
      ) {
    for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
      // TODO: don't load global handlers for now.
      // WebKit hands to the Plugin before it tries
      // to handle mimeTypes on its own.
      const std::string &mime_type = plugin_info.mime_types[i].mime_type;
      if (mime_type == "*" )
        return;
    }
  }

  plugins->push_back(plugin_info);
}

bool PluginList::FindPlugin(const std::string& mime_type,
                            bool allow_wildcard,
                            WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindDisabledPlugin(const std::string& mime_type,
                                    bool allow_wildcard,
                                    WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (!plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindPlugin(const GURL &url,
                            std::string* actual_mime_type,
                            WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  std::string path = url.path();
  std::string::size_type last_dot = path.rfind('.');
  if (last_dot == std::string::npos)
    return false;

  std::string extension = StringToLowerASCII(std::string(path, last_dot+1));

  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsExtension(plugins_[i], extension, actual_mime_type)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::SupportsType(const WebPluginInfo& info,
                              const std::string &mime_type,
                              bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = info.mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && mime_info.mime_type == "*") {
        continue;
      }
      return true;
    }
  }
  return false;
}

bool PluginList::SupportsExtension(const WebPluginInfo& info,
                                   const std::string &extension,
                                   std::string* actual_mime_type) {
  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_type = info.mime_types[i];
    for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
      if (mime_type.file_extensions[j] == extension) {
        if (actual_mime_type)
          *actual_mime_type = mime_type.mime_type;
        return true;
      }
    }
  }

  return false;
}

void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  AutoLock lock(lock_);
  *plugins = plugins_;
}

void PluginList::GetEnabledPlugins(bool refresh,
                                   std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  plugins->clear();
  AutoLock lock(lock_);
  for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->enabled)
      plugins->push_back(*it);
  }
}

bool PluginList::GetPluginInfo(const GURL& url,
                               const std::string& mime_type,
                               bool allow_wildcard,
                               WebPluginInfo* info,
                               std::string* actual_mime_type) {
  bool found = FindPlugin(mime_type, allow_wildcard, info);
  if (!found || (info->path.value() == kDefaultPluginLibraryName)) {
    if (FindPlugin(url, actual_mime_type, info) ||
        FindDisabledPlugin(mime_type, allow_wildcard, info)) {
      found = true;
    }
  }

  return found;
}

bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
                                     WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].path == plugin_path) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::EnablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_enable = false;

  std::set<FilePath>::iterator entry = disabled_plugins_.find(filename);
  if (entry == disabled_plugins_.end())
    return did_enable;  // Early exit if plugin not in disabled list.

  disabled_plugins_.erase(entry);  // Remove from disabled list.

  // Set enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(!it->enabled);  // Should have been disabled.
      it->enabled = true;
      did_enable = true;
    }
  }

  return did_enable;
}

bool PluginList::DisablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_disable = false;

  if (disabled_plugins_.find(filename) != disabled_plugins_.end())
    return did_disable;  // Early exit if plugin already in disabled list.

  disabled_plugins_.insert(filename);  // Add to disabled list.

  // Unset enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(it->enabled);  // Should have been enabled.
      it->enabled = false;
      did_disable = true;
    }
  }

  return did_disable;
}

void PluginList::Shutdown() {
  // TODO
}

}  // namespace NPAPI
<|endoftext|>


<commit_before>#include "scanner.hpp"
#include "compiler_error.hpp"
#include <cctype>

namespace p0
{
	namespace
	{
		bool is_whitespace(char c)
		{
			switch (c)
			{
			case ' ':
			case '\t':
			case '\n':
			case '\r':
				return true;

			default:
				return false;
			}
		}

		bool is_identifer_first(char c)
		{
			c = std::tolower(c);
			return
				((c >= 'a') && (c <= 'z')) ||
				(c == '_');
		}

		bool is_digit_10(char c)
		{
			return ((c >= '0') && (c <= '9'));
		}

		bool is_identifier_tail(char c)
		{
			return
				is_identifer_first(c) ||
				is_digit_10(c);
		}

		bool is_keyword(source_range content, char const *keyword)
		{
			for (auto i = content.begin(); i != content.end(); ++i, ++keyword)
			{
				if (*i != *keyword)
				{
					return false;
				}
			}

			return (*keyword == '\0');
		}

		struct keyword
		{
			char const *content;
			token_type::Enum token;
		};

		token_type::Enum find_keyword(source_range content)
		{
			//a rather simple (= slow) approach of finding keywords
			static std::array<keyword, 9> const keywords =
			{{
				{"var", token_type::var},
				{"function", token_type::function},
				{"return", token_type::return_},
				{"null", token_type::null},
				{"if", token_type::if_},
				{"else", token_type::else_},
				{"while", token_type::while_},
				{"break", token_type::break_},
				{"continue", token_type::continue_},
			}};

			using namespace std;

			for (auto k = begin(keywords); k != end(keywords); ++k)
			{
				if (is_keyword(content, k->content))
				{
					return k->token;
				}
			}

			return token_type::identifier;
		}
	}

	scanner::scanner(
		source_range source
		)
		: m_pos(source.begin())
		, m_end(source.end())
		, m_was_integer(false)
	{
	}

	token scanner::next_token()
	{
		skip_whitespace();

		if (m_pos == m_end)
		{
			return token(
				token_type::end_of_file,
				source_range(m_end, m_end)
				);
		}

		switch (*m_pos)
		{
		case '(': return eat_single_char_token(token_type::parenthesis_left);
		case ')': return eat_single_char_token(token_type::parenthesis_right);
		case '{': return eat_single_char_token(token_type::brace_left);
		case '}': return eat_single_char_token(token_type::brace_right);
		case '[': return eat_single_char_token(token_type::bracket_left);
		case ']': return eat_single_char_token(token_type::bracket_right);
		case '=': return eat_single_or_double_token(token_type::assign, '=', token_type::equal);
		case ',': return eat_single_char_token(token_type::comma);
		case '+': return eat_single_char_token(token_type::plus);
		case '-': return eat_single_char_token(token_type::minus);
		case '*': return eat_single_char_token(token_type::star);
		case '/': return eat_single_char_token(token_type::slash);
		case '%': return eat_single_char_token(token_type::modulo);
		case '&': return eat_single_or_double_token(token_type::ampersand, '&', token_type::ampersands);
		case '|': return eat_single_or_double_token(token_type::pipe, '|', token_type::pipes);
		case '<': return eat_single_or_triple_token(token_type::less, '<', token_type::shift_left, '=', token_type::less_equal);
		case '>': return eat_single_or_triple_token(token_type::greater, '>', token_type::shift_right, '=', token_type::greater_equal);
		case '!': return eat_single_or_double_token(token_type::exclamation_mark, '=', token_type::not_equal);
		case '.': return eat_single_char_token(token_type::dot);
		case '~': return eat_single_char_token(token_type::tilde);
		case '^': return eat_single_char_token(token_type::caret);
		case '"':
			{
				++m_pos;
				auto const string_begin = m_pos;

				for (;;)
				{
					auto const on_unexpected_eof = [this]()
					{
						throw compiler_error(
							"Unexpected end of file in string literal",
							source_range(m_end, m_end)
							);
					};

					if (m_pos == m_end)
					{
						on_unexpected_eof();
					}

					if (((*m_pos < 0x20) ||
						(*m_pos > 0x7e)) &&
						(*m_pos != '\t'))
					{
						throw compiler_error(
							"This character has to be hex-encoded in a string literal",
							source_range(m_pos, m_pos + 1)
							);
					}

					if (*m_pos == '\\')
					{
						++m_pos;
						if (m_pos == m_end)
						{
							on_unexpected_eof();
						}

						++m_pos;
					}

					else if (*m_pos == '"')
					{
						break;
					}

					else
					{
						++m_pos;
					}
				}

				auto const string_end = m_pos;
				++m_pos;

				return token(
					token_type::string,
					source_range(string_begin, string_end)
					);
			}

		default:
			if (is_identifer_first(*m_pos))
			{
				if (m_was_integer)
				{
					throw compiler_error(
						"An integer may not be directly followed by an identifier or a keyword",
						source_range(m_pos, m_pos + 1)
						);
				}

				auto const identifier_begin = m_pos;
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					is_identifier_tail(*m_pos));
				auto const identifier_end = m_pos;

				source_range const range(
					identifier_begin,
					identifier_end
					);

				auto const type = find_keyword(range);

				return token(
					type,
					range
					);
			}

			if (is_digit_10(*m_pos))
			{
				auto const integer_begin = m_pos;
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					is_digit_10(*m_pos));
				auto const integer_end = m_pos;

				m_was_integer = true;
				return token(
					token_type::integer_10,
					source_range(integer_begin, integer_end)
					);
			}

			throw compiler_error(
				"Unexpected character",
				source_range(m_pos, m_pos + 1)
				);
		}
	}

	void scanner::skip_line()
	{
		while (
			(m_pos != m_end) &&
			(*m_pos != '\n'))
		{
			++m_pos;
		}
	}

	source_range scanner::rest() const
	{
		return source_range(
			m_pos,
			m_end
			);
	}

	void scanner::skip_whitespace()
	{
		while (m_pos != m_end)
		{
			if (is_whitespace(*m_pos))
			{
				++m_pos;
				m_was_integer = false;
				continue;
			}

			//a comment starts with a semicolon and ends after the current line
			if (*m_pos == ';')
			{
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					(*m_pos != '\n')
					);
				m_was_integer = false;
				continue;
			}

			break;
		}
	}

	token scanner::eat_single_char_token(token_type::Enum type)
	{
		++m_pos;
		return token(
			type,
			source_range((m_pos - 1), m_pos)
			);
	}

	token scanner::eat_single_or_double_token(
		token_type::Enum single_token,
		char second_char,
		token_type::Enum double_token
		)
	{
		++m_pos;

		if ((m_pos != m_end) &&
			(*m_pos == second_char))
		{
			++m_pos;
			return token(double_token, source_range(m_pos - 2, m_pos));
		}

		return token(single_token, source_range(m_pos - 1, m_pos));
	}

	token scanner::eat_single_or_triple_token(
		token_type::Enum single_token,
		char second_char_0,
		token_type::Enum double_token_0,
		char second_char_1,
		token_type::Enum double_token_1
		)
	{
		++m_pos;

		if (m_pos != m_end)
		{
			if (*m_pos == second_char_0)
			{
				++m_pos;
				return token(double_token_0, source_range(m_pos - 2, m_pos));
			}
			if (*m_pos == second_char_1)
			{
				++m_pos;
				return token(double_token_1, source_range(m_pos - 2, m_pos));
			}
		}

		return token(single_token, source_range(m_pos - 1, m_pos));
	}
}
<commit_msg>integer followed by identifier/keyword fixed<commit_after>#include "scanner.hpp"
#include "compiler_error.hpp"
#include <cctype>

namespace p0
{
	namespace
	{
		bool is_whitespace(char c)
		{
			switch (c)
			{
			case ' ':
			case '\t':
			case '\n':
			case '\r':
				return true;

			default:
				return false;
			}
		}

		bool is_identifer_first(char c)
		{
			c = std::tolower(c);
			return
				((c >= 'a') && (c <= 'z')) ||
				(c == '_');
		}

		bool is_digit_10(char c)
		{
			return ((c >= '0') && (c <= '9'));
		}

		bool is_identifier_tail(char c)
		{
			return
				is_identifer_first(c) ||
				is_digit_10(c);
		}

		bool is_keyword(source_range content, char const *keyword)
		{
			for (auto i = content.begin(); i != content.end(); ++i, ++keyword)
			{
				if (*i != *keyword)
				{
					return false;
				}
			}

			return (*keyword == '\0');
		}

		struct keyword
		{
			char const *content;
			token_type::Enum token;
		};

		token_type::Enum find_keyword(source_range content)
		{
			//a rather simple (= slow) approach of finding keywords
			static std::array<keyword, 9> const keywords =
			{{
				{"var", token_type::var},
				{"function", token_type::function},
				{"return", token_type::return_},
				{"null", token_type::null},
				{"if", token_type::if_},
				{"else", token_type::else_},
				{"while", token_type::while_},
				{"break", token_type::break_},
				{"continue", token_type::continue_},
			}};

			using namespace std;

			for (auto k = begin(keywords); k != end(keywords); ++k)
			{
				if (is_keyword(content, k->content))
				{
					return k->token;
				}
			}

			return token_type::identifier;
		}
	}

	scanner::scanner(
		source_range source
		)
		: m_pos(source.begin())
		, m_end(source.end())
		, m_was_integer(false)
	{
	}

	token scanner::next_token()
	{
		skip_whitespace();

		if (m_pos == m_end)
		{
			return token(
				token_type::end_of_file,
				source_range(m_end, m_end)
				);
		}

		bool const was_integer = m_was_integer;
		m_was_integer = false;

		switch (*m_pos)
		{
		case '(': return eat_single_char_token(token_type::parenthesis_left);
		case ')': return eat_single_char_token(token_type::parenthesis_right);
		case '{': return eat_single_char_token(token_type::brace_left);
		case '}': return eat_single_char_token(token_type::brace_right);
		case '[': return eat_single_char_token(token_type::bracket_left);
		case ']': return eat_single_char_token(token_type::bracket_right);
		case '=': return eat_single_or_double_token(token_type::assign, '=', token_type::equal);
		case ',': return eat_single_char_token(token_type::comma);
		case '+': return eat_single_char_token(token_type::plus);
		case '-': return eat_single_char_token(token_type::minus);
		case '*': return eat_single_char_token(token_type::star);
		case '/': return eat_single_char_token(token_type::slash);
		case '%': return eat_single_char_token(token_type::modulo);
		case '&': return eat_single_or_double_token(token_type::ampersand, '&', token_type::ampersands);
		case '|': return eat_single_or_double_token(token_type::pipe, '|', token_type::pipes);
		case '<': return eat_single_or_triple_token(token_type::less, '<', token_type::shift_left, '=', token_type::less_equal);
		case '>': return eat_single_or_triple_token(token_type::greater, '>', token_type::shift_right, '=', token_type::greater_equal);
		case '!': return eat_single_or_double_token(token_type::exclamation_mark, '=', token_type::not_equal);
		case '.': return eat_single_char_token(token_type::dot);
		case '~': return eat_single_char_token(token_type::tilde);
		case '^': return eat_single_char_token(token_type::caret);
		case '"':
			{
				++m_pos;
				auto const string_begin = m_pos;

				for (;;)
				{
					auto const on_unexpected_eof = [this]()
					{
						throw compiler_error(
							"Unexpected end of file in string literal",
							source_range(m_end, m_end)
							);
					};

					if (m_pos == m_end)
					{
						on_unexpected_eof();
					}

					if (((*m_pos < 0x20) ||
						(*m_pos > 0x7e)) &&
						(*m_pos != '\t'))
					{
						throw compiler_error(
							"This character has to be hex-encoded in a string literal",
							source_range(m_pos, m_pos + 1)
							);
					}

					if (*m_pos == '\\')
					{
						++m_pos;
						if (m_pos == m_end)
						{
							on_unexpected_eof();
						}

						++m_pos;
					}

					else if (*m_pos == '"')
					{
						break;
					}

					else
					{
						++m_pos;
					}
				}

				auto const string_end = m_pos;
				++m_pos;

				return token(
					token_type::string,
					source_range(string_begin, string_end)
					);
			}

		default:
			if (is_identifer_first(*m_pos))
			{
				if (was_integer)
				{
					throw compiler_error(
						"An integer may not be directly followed by an identifier or a keyword",
						source_range(m_pos, m_pos + 1)
						);
				}

				auto const identifier_begin = m_pos;
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					is_identifier_tail(*m_pos));
				auto const identifier_end = m_pos;

				source_range const range(
					identifier_begin,
					identifier_end
					);

				auto const type = find_keyword(range);

				return token(
					type,
					range
					);
			}

			if (is_digit_10(*m_pos))
			{
				auto const integer_begin = m_pos;
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					is_digit_10(*m_pos));
				auto const integer_end = m_pos;

				m_was_integer = true;

				return token(
					token_type::integer_10,
					source_range(integer_begin, integer_end)
					);
			}

			throw compiler_error(
				"Unexpected character",
				source_range(m_pos, m_pos + 1)
				);
		}
	}

	void scanner::skip_line()
	{
		while (
			(m_pos != m_end) &&
			(*m_pos != '\n'))
		{
			++m_pos;
		}
	}

	source_range scanner::rest() const
	{
		return source_range(
			m_pos,
			m_end
			);
	}

	void scanner::skip_whitespace()
	{
		while (m_pos != m_end)
		{
			if (is_whitespace(*m_pos))
			{
				++m_pos;

				m_was_integer = false;
				continue;
			}

			//a comment starts with a semicolon and ends after the current line
			if (*m_pos == ';')
			{
				do
				{
					++m_pos;
				}
				while (
					(m_pos != m_end) &&
					(*m_pos != '\n')
					);

				m_was_integer = false;
				continue;
			}

			break;
		}
	}

	token scanner::eat_single_char_token(token_type::Enum type)
	{
		++m_pos;
		return token(
			type,
			source_range((m_pos - 1), m_pos)
			);
	}

	token scanner::eat_single_or_double_token(
		token_type::Enum single_token,
		char second_char,
		token_type::Enum double_token
		)
	{
		++m_pos;

		if ((m_pos != m_end) &&
			(*m_pos == second_char))
		{
			++m_pos;
			return token(double_token, source_range(m_pos - 2, m_pos));
		}

		return token(single_token, source_range(m_pos - 1, m_pos));
	}

	token scanner::eat_single_or_triple_token(
		token_type::Enum single_token,
		char second_char_0,
		token_type::Enum double_token_0,
		char second_char_1,
		token_type::Enum double_token_1
		)
	{
		++m_pos;

		if (m_pos != m_end)
		{
			if (*m_pos == second_char_0)
			{
				++m_pos;
				return token(double_token_0, source_range(m_pos - 2, m_pos));
			}
			if (*m_pos == second_char_1)
			{
				++m_pos;
				return token(double_token_1, source_range(m_pos - 2, m_pos));
			}
		}

		return token(single_token, source_range(m_pos - 1, m_pos));
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ReadMaybeMapped.h"

#include <boost/iostreams/device/mapped_file.hpp>
#include <fcntl.h>
#include <sys/stat.h>

#ifdef __linux__
#include <sys/mman.h> // For madvise
#endif

#include "Debug.h"
#include "Macros.h"

namespace redex {
namespace {

std::string strerror_str(int no) { return std::string(strerror(no)); };

// Implementation based on posix read. Avoids heap allocation when data
// is small enough.
template <size_t kDataSize>
struct ReadFileContents final {
  size_t size;
  std::unique_ptr<char[]> content;
  char inline_data[kDataSize];

  explicit ReadFileContents(const std::string& file) {
    int fd = open(file.c_str(), O_RDONLY | O_BINARY);
    if (fd < 0) {
      throw std::runtime_error(std::string("Failed to open ") + file + ": " +
                               strerror_str(errno));
    }
    struct stat st = {};
    if (fstat(fd, &st) == -1) {
      auto saved_errno = errno;
      close(fd);
      throw std::runtime_error(std::string("Failed to get file length of ") +
                               file + ": " + strerror_str(saved_errno));
    }
    read_data(file, fd, static_cast<size_t>(st.st_size));
  }
  ReadFileContents(const std::string& file, int fd, size_t size) {
    read_data(file, fd, size);
  }

  void read_data(const std::string& file, int fd, size_t size_in) {
    size = size_in;
    if (size == 0) {
      close(fd);
      return;
    }
    char* data;
    if (size > kDataSize) {
      content = std::make_unique<char[]>(size);
      data = content.get();
    } else {
      data = inline_data;
    }

    // Now read.
    size_t remaining = size;
    while (remaining > 0) {
      ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, remaining));
      if (n <= 0) {
        auto saved_errno = errno;
        close(fd);
        throw std::runtime_error(std::string("Failed reading ") + file + ": " +
                                 strerror_str(saved_errno));
      }
      data += n;
      remaining -= n;
    }
    close(fd);
  }

  const char* get_content() const {
    return size > kDataSize ? content.get() : inline_data;
  }
  size_t get_content_size() const { return size; }
};
using PageSizeReadFileContents = ReadFileContents<4080>;

static_assert(sizeof(PageSizeReadFileContents) == 4096 || sizeof(void*) != 8,
              "Unexpected size");

// Mmap: just map file contents and wrap the mapping, avoiding allocation
// and explicit I/O.
//
// Note: using boost for Windows compat.
template <int kMadviseFlags>
struct MmapFileContents final {
  boost::iostreams::mapped_file_source mapped_file{};

  explicit MmapFileContents(const std::string& file) {
    mapped_file.open(file);
    if (!mapped_file.is_open()) {
      throw std::runtime_error(std::string("Could not open ") + file);
    }
#ifdef __linux__
    if (mapped_file.size() > 0) {
      madvise(const_cast<char*>(mapped_file.data()),
              mapped_file.size(),
              kMadviseFlags);
    }
#endif
  }

  const char* get_content() const { return mapped_file.data(); }
  size_t get_content_size() const { return mapped_file.size(); }
};

} // namespace

// Mmaps may not amortize for small files. Split between `read` and `mmap`.
void read_file_with_contents(const std::string& file,
                             const std::function<void(const char*, size_t)>& fn,
                             size_t threshold) {
  int fd = open(file.c_str(), O_RDONLY | O_BINARY);
  if (fd < 0) {
    throw std::runtime_error(std::string("Failed to open ") + file + ": " +
                             strerror_str(errno));
  }
  struct stat st = {};
  if (fstat(fd, &st) == -1) {
    auto saved_errno = errno;
    close(fd);
    throw std::runtime_error(std::string("Failed to get file length of ") +
                             file + ": " + strerror_str(saved_errno));
  }
  size_t size = static_cast<size_t>(st.st_size);

  if (size <= threshold) {
    auto content = PageSizeReadFileContents(file, fd, size);
    fn(content.get_content(), content.get_content_size());
  } else {
    close(fd);
    constexpr int kAdvFlags =
#ifdef __linux__
        MADV_SEQUENTIAL | MADV_WILLNEED;
#else
        0;
#endif
    auto content = MmapFileContents<kAdvFlags>(file);
    fn(content.get_content(), content.get_content_size());
  }
}

} // namespace redex
<commit_msg>Add missing include<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ReadMaybeMapped.h"

#include <boost/iostreams/device/mapped_file.hpp>
#include <fcntl.h>
#include <sys/stat.h>

#ifdef __linux__
#include <sys/mman.h> // For madvise
#endif

#include "utils/Compat.h" // TEMP_FAILURE_RETRY, if necessary.

#include "Debug.h"
#include "Macros.h"

namespace redex {
namespace {

std::string strerror_str(int no) { return std::string(strerror(no)); };

// Implementation based on posix read. Avoids heap allocation when data
// is small enough.
template <size_t kDataSize>
struct ReadFileContents final {
  size_t size;
  std::unique_ptr<char[]> content;
  char inline_data[kDataSize];

  explicit ReadFileContents(const std::string& file) {
    int fd = open(file.c_str(), O_RDONLY | O_BINARY);
    if (fd < 0) {
      throw std::runtime_error(std::string("Failed to open ") + file + ": " +
                               strerror_str(errno));
    }
    struct stat st = {};
    if (fstat(fd, &st) == -1) {
      auto saved_errno = errno;
      close(fd);
      throw std::runtime_error(std::string("Failed to get file length of ") +
                               file + ": " + strerror_str(saved_errno));
    }
    read_data(file, fd, static_cast<size_t>(st.st_size));
  }
  ReadFileContents(const std::string& file, int fd, size_t size) {
    read_data(file, fd, size);
  }

  void read_data(const std::string& file, int fd, size_t size_in) {
    size = size_in;
    if (size == 0) {
      close(fd);
      return;
    }
    char* data;
    if (size > kDataSize) {
      content = std::make_unique<char[]>(size);
      data = content.get();
    } else {
      data = inline_data;
    }

    // Now read.
    size_t remaining = size;
    while (remaining > 0) {
      ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, remaining));
      if (n <= 0) {
        auto saved_errno = errno;
        close(fd);
        throw std::runtime_error(std::string("Failed reading ") + file + ": " +
                                 strerror_str(saved_errno));
      }
      data += n;
      remaining -= n;
    }
    close(fd);
  }

  const char* get_content() const {
    return size > kDataSize ? content.get() : inline_data;
  }
  size_t get_content_size() const { return size; }
};
using PageSizeReadFileContents = ReadFileContents<4080>;

static_assert(sizeof(PageSizeReadFileContents) == 4096 || sizeof(void*) != 8,
              "Unexpected size");

// Mmap: just map file contents and wrap the mapping, avoiding allocation
// and explicit I/O.
//
// Note: using boost for Windows compat.
template <int kMadviseFlags>
struct MmapFileContents final {
  boost::iostreams::mapped_file_source mapped_file{};

  explicit MmapFileContents(const std::string& file) {
    mapped_file.open(file);
    if (!mapped_file.is_open()) {
      throw std::runtime_error(std::string("Could not open ") + file);
    }
#ifdef __linux__
    if (mapped_file.size() > 0) {
      madvise(const_cast<char*>(mapped_file.data()),
              mapped_file.size(),
              kMadviseFlags);
    }
#endif
  }

  const char* get_content() const { return mapped_file.data(); }
  size_t get_content_size() const { return mapped_file.size(); }
};

} // namespace

// Mmaps may not amortize for small files. Split between `read` and `mmap`.
void read_file_with_contents(const std::string& file,
                             const std::function<void(const char*, size_t)>& fn,
                             size_t threshold) {
  int fd = open(file.c_str(), O_RDONLY | O_BINARY);
  if (fd < 0) {
    throw std::runtime_error(std::string("Failed to open ") + file + ": " +
                             strerror_str(errno));
  }
  struct stat st = {};
  if (fstat(fd, &st) == -1) {
    auto saved_errno = errno;
    close(fd);
    throw std::runtime_error(std::string("Failed to get file length of ") +
                             file + ": " + strerror_str(saved_errno));
  }
  size_t size = static_cast<size_t>(st.st_size);

  if (size <= threshold) {
    auto content = PageSizeReadFileContents(file, fd, size);
    fn(content.get_content(), content.get_content_size());
  } else {
    close(fd);
    constexpr int kAdvFlags =
#ifdef __linux__
        MADV_SEQUENTIAL | MADV_WILLNEED;
#else
        0;
#endif
    auto content = MmapFileContents<kAdvFlags>(file);
    fn(content.get_content(), content.get_content_size());
  }
}

} // namespace redex
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include "vast/concept/parseable/vast/json.hpp"
#include "vast/concept/printable/vast/json.hpp"
#include "vast/detail/line_range.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/expected.hpp"
#include "vast/format/multi_layout_reader.hpp"
#include "vast/format/printer_writer.hpp"
#include "vast/fwd.hpp"
#include "vast/json.hpp"
#include "vast/schema.hpp"

namespace vast::format::json {

struct event_printer : printer<event_printer> {
  using attribute = event;

  template <class Iterator>
  bool print(Iterator& out, const event& e) const {
    vast::json j;
    if (!convert(e.data(), j, e.type()))
      return false;
    return printers::json<policy::oneline>(out, j);
  }
};

class writer : public printer_writer<event_printer> {
public:
  using printer_writer<event_printer>::printer_writer;

  const char* name() const {
    return "json-writer";
  }
};

/// Adds a JSON object to a table slice builder according to a given layout.
/// @param builder The builder to add the JSON object to.
/// @param xs The JSON object to add to *builder.
/// @param layout The record type describing *xs*.
/// @param name The name of the reader used for logging.
/// @returns An error iff the operation failed.
caf::error add(table_slice_builder& builder, const vast::json::object& xs,
               const record_type& layout, const std::string_view name);

/// @relates reader
struct default_selector {
  caf::optional<record_type> operator()(const vast::json::object&) {
    return layout;
  }

  caf::error schema(vast::schema sch) {
    auto entry = *sch.begin();
    if (!caf::holds_alternative<record_type>(entry))
      return make_error(ec::invalid_configuration,
                        "only record_types supported for json schema");
    layout = flatten(caf::get<record_type>(entry));
    return caf::none;
  }

  vast::schema schema() const {
    vast::schema result;
    if (layout)
      result.add(*layout);
    return result;
  }

  static const char* name() {
    return "json-reader";
  }

  caf::optional<record_type> layout = caf::none;
};

/// A reader for JSON data. It operates with a *selector* to determine the
/// mapping of JSON object to the appropriate record type in the schema.
template <class Selector = default_selector>
class reader final : public multi_layout_reader {
public:
  using super = multi_layout_reader;

  /// Constructs a JSON reader.
  /// @param table_slice_type The ID for table slice type to build.
  /// @param in The stream of JSON objects.
  explicit reader(caf::atom_value table_slice_type,
                  std::unique_ptr<std::istream> in = nullptr);

  void reset(std::unique_ptr<std::istream> in);

  caf::error schema(vast::schema sch) override;

  caf::error schema(vast::type, vast::schema);

  vast::schema schema() const override;

  const char* name() const override;

protected:
  caf::error read_impl(size_t max_events, size_t max_slice_size,
                       consumer& f) override;

private:
  using iterator_type = std::string_view::const_iterator;

  Selector selector_;
  std::unique_ptr<std::istream> input_;
  std::unique_ptr<detail::line_range> lines_;
  caf::optional<size_t> proto_field_;
  std::vector<size_t> port_fields_;
};

// -- implementation ----------------------------------------------------------

template <class Selector>
reader<Selector>::reader(caf::atom_value table_slice_type,
                         std::unique_ptr<std::istream> in)
  : super(table_slice_type) {
  if (in != nullptr)
    reset(std::move(in));
}

template <class Selector>
void reader<Selector>::reset(std::unique_ptr<std::istream> in) {
  VAST_ASSERT(in != nullptr);
  input_ = std::move(in);
  lines_ = std::make_unique<detail::line_range>(*input_);
}

template <class Selector>
caf::error reader<Selector>::schema(vast::schema s) {
  return selector_.schema(std::move(s));
}

template <class Selector>
vast::schema reader<Selector>::schema() const {
  return selector_.schema();
}

template <class Selector>
const char* reader<Selector>::name() const {
  return Selector::name();
}

template <class Selector>
caf::error reader<Selector>::read_impl(size_t max_events, size_t max_slice_size,
                                       consumer& cons) {
  VAST_ASSERT(max_events > 0);
  VAST_ASSERT(max_slice_size > 0);
  size_t produced = 0;
  while (produced < max_events) {
    // EOF check.
    if (lines_->done())
      return finish(cons, make_error(ec::end_of_input, "input exhausted"));
    auto& line = lines_->get();
    vast::json j;
    if (!parsers::json(line, j))
      return make_error(ec::parse_error, "unable to parse json");
    auto xs = caf::get_if<vast::json::object>(&j);
    if (!xs)
      return make_error(ec::type_clash, "not a json object");
    auto layout = selector_(*xs);
    if (!layout)
      return make_error(ec::parse_error, "unable to get a layout");
    auto bptr = builder(*layout);
    if (bptr == nullptr)
      return make_error(ec::parse_error, "unable to get a builder");
    if (auto err = add(*bptr, *xs, *layout, selector_.name())) {
      err.context() += caf::make_message("line", lines_->line_number());
      return finish(cons, err);
    }
    produced++;
    if (bptr->rows() == max_slice_size)
      if (auto err = finish(cons, bptr))
        return err;
    lines_->next();
  }
  return finish(cons);
}

} // namespace vast::format::json
<commit_msg>Don't abort on unrecognized events<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include "vast/concept/parseable/vast/json.hpp"
#include "vast/concept/printable/vast/json.hpp"
#include "vast/detail/line_range.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/expected.hpp"
#include "vast/format/multi_layout_reader.hpp"
#include "vast/format/printer_writer.hpp"
#include "vast/fwd.hpp"
#include "vast/json.hpp"
#include "vast/logger.hpp"
#include "vast/schema.hpp"

namespace vast::format::json {

struct event_printer : printer<event_printer> {
  using attribute = event;

  template <class Iterator>
  bool print(Iterator& out, const event& e) const {
    vast::json j;
    if (!convert(e.data(), j, e.type()))
      return false;
    return printers::json<policy::oneline>(out, j);
  }
};

class writer : public printer_writer<event_printer> {
public:
  using printer_writer<event_printer>::printer_writer;

  const char* name() const {
    return "json-writer";
  }
};

/// Adds a JSON object to a table slice builder according to a given layout.
/// @param builder The builder to add the JSON object to.
/// @param xs The JSON object to add to *builder.
/// @param layout The record type describing *xs*.
/// @param name The name of the reader used for logging.
/// @returns An error iff the operation failed.
caf::error add(table_slice_builder& builder, const vast::json::object& xs,
               const record_type& layout, const std::string_view name);

/// @relates reader
struct default_selector {
  caf::optional<record_type> operator()(const vast::json::object&) {
    return layout;
  }

  caf::error schema(vast::schema sch) {
    auto entry = *sch.begin();
    if (!caf::holds_alternative<record_type>(entry))
      return make_error(ec::invalid_configuration,
                        "only record_types supported for json schema");
    layout = flatten(caf::get<record_type>(entry));
    return caf::none;
  }

  vast::schema schema() const {
    vast::schema result;
    if (layout)
      result.add(*layout);
    return result;
  }

  static const char* name() {
    return "json-reader";
  }

  caf::optional<record_type> layout = caf::none;
};

/// A reader for JSON data. It operates with a *selector* to determine the
/// mapping of JSON object to the appropriate record type in the schema.
template <class Selector = default_selector>
class reader final : public multi_layout_reader {
public:
  using super = multi_layout_reader;

  /// Constructs a JSON reader.
  /// @param table_slice_type The ID for table slice type to build.
  /// @param in The stream of JSON objects.
  explicit reader(caf::atom_value table_slice_type,
                  std::unique_ptr<std::istream> in = nullptr);

  void reset(std::unique_ptr<std::istream> in);

  caf::error schema(vast::schema sch) override;

  caf::error schema(vast::type, vast::schema);

  vast::schema schema() const override;

  const char* name() const override;

protected:
  caf::error read_impl(size_t max_events, size_t max_slice_size,
                       consumer& f) override;

private:
  using iterator_type = std::string_view::const_iterator;

  Selector selector_;
  std::unique_ptr<std::istream> input_;
  std::unique_ptr<detail::line_range> lines_;
  caf::optional<size_t> proto_field_;
  std::vector<size_t> port_fields_;
};

// -- implementation ----------------------------------------------------------

template <class Selector>
reader<Selector>::reader(caf::atom_value table_slice_type,
                         std::unique_ptr<std::istream> in)
  : super(table_slice_type) {
  if (in != nullptr)
    reset(std::move(in));
}

template <class Selector>
void reader<Selector>::reset(std::unique_ptr<std::istream> in) {
  VAST_ASSERT(in != nullptr);
  input_ = std::move(in);
  lines_ = std::make_unique<detail::line_range>(*input_);
}

template <class Selector>
caf::error reader<Selector>::schema(vast::schema s) {
  return selector_.schema(std::move(s));
}

template <class Selector>
vast::schema reader<Selector>::schema() const {
  return selector_.schema();
}

template <class Selector>
const char* reader<Selector>::name() const {
  return Selector::name();
}

template <class Selector>
caf::error reader<Selector>::read_impl(size_t max_events, size_t max_slice_size,
                                       consumer& cons) {
  VAST_ASSERT(max_events > 0);
  VAST_ASSERT(max_slice_size > 0);
  size_t produced = 0;
  for (; produced < max_events; lines_->next()) {
    // EOF check.
    if (lines_->done())
      return finish(cons, make_error(ec::end_of_input, "input exhausted"));
    auto& line = lines_->get();
    vast::json j;
    if (!parsers::json(line, j))
      return make_error(ec::parse_error, "unable to parse json");
    auto xs = caf::get_if<vast::json::object>(&j);
    if (!xs)
      return make_error(ec::type_clash, "not a json object");
    auto layout = selector_(*xs);
    if (!layout) {
      VAST_INFO(this, "unable to get a layout");
      continue;
    }
    VAST_INFO(this, "got layout", *layout);
    auto bptr = builder(*layout);
    if (bptr == nullptr)
      return make_error(ec::parse_error, "unable to get a builder");
    if (auto err = add(*bptr, *xs, *layout, selector_.name())) {
      err.context() += caf::make_message("line", lines_->line_number());
      return finish(cons, err);
    }
    produced++;
    if (bptr->rows() == max_slice_size)
      if (auto err = finish(cons, bptr))
        return err;
  }
  return finish(cons);
}

} // namespace vast::format::json
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/FiberState.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam YieldType Yield type.
 */
template<class YieldType>
class Fiber {
public:
  /**
   * Default constructor.
   */
  Fiber(Label* context) {
    //
  }

  /**
   * Constructor.
   */
  Fiber(Label* context, const Shared<FiberState<YieldType>>& state) :
      state(context, state) {
    //
  }

  /**
   * Copy constructor.
   */
  Fiber(Label* context, const Fiber<YieldType>& o) :
      state(context, o.state) {
    //
  }

  /**
   * Deep copy constructor.
   */
  Fiber(Label* context, Label* label, const Fiber<YieldType>& o) :
      state(context, label, o.state) {
    //
  }

  /**
   * Clone the fiber.
   */
  Fiber<YieldType> clone() const {
    return Fiber<YieldType>(state.clone());
  }

  /**
   * Freeze the fiber.
   */
  void freeze() const {
    state.freeze();
  }

  /**
   * Thaw the fiber.
   */
  void thaw(LazyLabel* label) const {
    state.thaw(label);
  }

  /**
   * Finish the fiber.
   */
  void finish() const {
    state.finish();
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const {
    bool result = false;
    if (state.query()) {
      result = state->query();
      if (!result) {
        const_cast<Fiber<YieldType>*>(this)->state.release();
        // ^ fiber has finished, delete the state
      }
    }
    return result;
  }

  /**
   * Get the last yield value.
   */
  YieldType get() const {
    libbirch_assert_msg_(state.query(), "fiber handle undefined");
    return state->get();
  }

private:
  /**
   * Fiber state.
   */
  Shared<FiberState<YieldType>> state;
};

template<class T>
struct is_value<Fiber<T>> {
  static const bool value = false;
};
}
<commit_msg>Updates to Fiber constructors, copy and move constructors.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/FiberState.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam YieldType Yield type.
 */
template<class YieldType>
class Fiber {
public:
  /**
   * Constructor.
   */
  Fiber() {
    //
  }

  /**
   * Constructor.
   */
  Fiber(Label* context, const Shared<FiberState<YieldType>>& state) :
      state(context, state) {
    //
  }

  /**
   * Copy constructor.
   */
  Fiber(Label* context, const Fiber<YieldType>& o) :
      state(context, o.state) {
    //
  }

  /**
   * Move constructor.
   */
  Fiber(Label* context, Fiber<YieldType>&& o) :
      state(context, std::move(o.state)) {
    //
  }

  /**
   * Deep copy constructor.
   */
  Fiber(Label* context, Label* label, const Fiber<YieldType>& o) :
      state(context, label, o.state) {
    //
  }

  /**
   * Copy assignment.
   */
  Fiber& assign(Label* context, const Fiber<YieldType>& o) {
    state.assign(context, o.state);
    return *this;
  }

  /**
   * Move assignment.
   */
  Fiber& assign(Label* context, Fiber<YieldType>&& o) {
    state.assign(context, std::move(o.state));
    return *this;
  }

  /**
   * Clone the fiber.
   */
  Fiber<YieldType> clone() const {
    return Fiber<YieldType>(state.clone());
  }

  /**
   * Freeze the fiber.
   */
  void freeze() const {
    state.freeze();
  }

  /**
   * Thaw the fiber.
   */
  void thaw(LazyLabel* label) const {
    state.thaw(label);
  }

  /**
   * Finish the fiber.
   */
  void finish() const {
    state.finish();
  }

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const {
    bool result = false;
    if (state.query()) {
      result = state->query();
      if (!result) {
        const_cast<Fiber<YieldType>*>(this)->state.release();
        // ^ fiber has finished, delete the state
      }
    }
    return result;
  }

  /**
   * Get the last yield value.
   */
  YieldType get() const {
    libbirch_assert_msg_(state.query(), "fiber handle undefined");
    return state->get();
  }

private:
  /**
   * Fiber state.
   */
  Shared<FiberState<YieldType>> state;
};

template<class T>
struct is_value<Fiber<T>> {
  static const bool value = false;
};
}
<|endoftext|>


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

#include "chrome/browser/host_zoom_map.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"

HostZoomMap::HostZoomMap(Profile* profile) : profile_(profile) {
  const DictionaryValue* host_zoom_dictionary =
      profile_->GetPrefs()->GetDictionary(prefs::kPerHostZoomLevels);
  // Careful: The returned value could be NULL if the pref has never been set.
  if (host_zoom_dictionary != NULL) {
    for (DictionaryValue::key_iterator i(host_zoom_dictionary->begin_keys());
         i != host_zoom_dictionary->end_keys(); ++i) {
      std::wstring wide_host(*i);
      int zoom_level = 0;
      bool success = host_zoom_dictionary->GetIntegerWithoutPathExpansion(
          wide_host, &zoom_level);
      DCHECK(success);
      host_zoom_levels_[WideToUTF8(wide_host)] = zoom_level;
    }
  }
}

// static
void HostZoomMap::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kPerHostZoomLevels);
}

int HostZoomMap::GetZoomLevel(const std::string& host) const {
  AutoLock auto_lock(lock_);
  HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
  return (i == host_zoom_levels_.end()) ? 0 : i->second;
}

void HostZoomMap::SetZoomLevel(const std::string& host, int level) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (host.empty())
    return;

  {
    AutoLock auto_lock(lock_);
    if (level == 0)
      host_zoom_levels_.erase(host);
    else
      host_zoom_levels_[host] = level;
  }

  DictionaryValue* host_zoom_dictionary =
      profile_->GetPrefs()->GetMutableDictionary(prefs::kPerHostZoomLevels);
  std::wstring wide_host(UTF8ToWide(host));
  if (level == 0) {
    host_zoom_dictionary->RemoveWithoutPathExpansion(wide_host, NULL);
  } else {
    host_zoom_dictionary->SetWithoutPathExpansion(wide_host,
        Value::CreateIntegerValue(level));
  }
}

void HostZoomMap::ResetToDefaults() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  host_zoom_levels_.clear();
  profile_->GetPrefs()->ClearPref(prefs::kPerHostZoomLevels);
}

HostZoomMap::~HostZoomMap() {
}
<commit_msg>One more place I forgot to lock.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/host_zoom_map.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"

HostZoomMap::HostZoomMap(Profile* profile) : profile_(profile) {
  const DictionaryValue* host_zoom_dictionary =
      profile_->GetPrefs()->GetDictionary(prefs::kPerHostZoomLevels);
  // Careful: The returned value could be NULL if the pref has never been set.
  if (host_zoom_dictionary != NULL) {
    for (DictionaryValue::key_iterator i(host_zoom_dictionary->begin_keys());
         i != host_zoom_dictionary->end_keys(); ++i) {
      std::wstring wide_host(*i);
      int zoom_level = 0;
      bool success = host_zoom_dictionary->GetIntegerWithoutPathExpansion(
          wide_host, &zoom_level);
      DCHECK(success);
      host_zoom_levels_[WideToUTF8(wide_host)] = zoom_level;
    }
  }
}

// static
void HostZoomMap::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kPerHostZoomLevels);
}

int HostZoomMap::GetZoomLevel(const std::string& host) const {
  AutoLock auto_lock(lock_);
  HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
  return (i == host_zoom_levels_.end()) ? 0 : i->second;
}

void HostZoomMap::SetZoomLevel(const std::string& host, int level) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (host.empty())
    return;

  {
    AutoLock auto_lock(lock_);
    if (level == 0)
      host_zoom_levels_.erase(host);
    else
      host_zoom_levels_[host] = level;
  }

  DictionaryValue* host_zoom_dictionary =
      profile_->GetPrefs()->GetMutableDictionary(prefs::kPerHostZoomLevels);
  std::wstring wide_host(UTF8ToWide(host));
  if (level == 0) {
    host_zoom_dictionary->RemoveWithoutPathExpansion(wide_host, NULL);
  } else {
    host_zoom_dictionary->SetWithoutPathExpansion(wide_host,
        Value::CreateIntegerValue(level));
  }
}

void HostZoomMap::ResetToDefaults() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  {
    AutoLock auto_lock(lock_);
    host_zoom_levels_.clear();
  }

  profile_->GetPrefs()->ClearPref(prefs::kPerHostZoomLevels);
}

HostZoomMap::~HostZoomMap() {
}
<|endoftext|>


<commit_before><commit_msg>Invoke the right method (invokeDefault) if a plugin calls NPN_InvokeDefault on its own object.<commit_after><|endoftext|>