<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 "chrome/renderer/chrome_render_process_observer.h"

#include <limits>
#include <vector>

#include "base/allocator/allocator_extension.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/threading/platform_thread.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_localization_peer.h"
#include "chrome/common/metrics/variations/variations_util.h"
#include "chrome/common/net/net_resource_provider.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/chrome_content_renderer_client.h"
#include "chrome/renderer/content_settings_observer.h"
#include "chrome/renderer/security_filter_peer.h"
#include "content/public/common/resource_dispatcher_delegate.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view_visitor.h"
#include "content/public/renderer/render_view.h"
#include "crypto/nss_util.h"
#include "media/base/media_switches.h"
#include "net/base/net_errors.h"
#include "net/base/net_module.h"
#include "third_party/sqlite/sqlite3.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFontCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"

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

#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
#endif

using WebKit::WebCache;
using WebKit::WebCrossOriginPreflightResultCache;
using WebKit::WebFontCache;
using WebKit::WebRuntimeFeatures;
using content::RenderThread;

namespace {

static const int kCacheStatsDelayMS = 2000;

class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
 public:
  RendererResourceDelegate()
      : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
  }

  virtual webkit_glue::ResourceLoaderBridge::Peer* OnRequestComplete(
      webkit_glue::ResourceLoaderBridge::Peer* current_peer,
      ResourceType::Type resource_type,
      int error_code) {
    // Update the browser about our cache.
    // Rate limit informing the host of our cache stats.
    if (!weak_factory_.HasWeakPtrs()) {
      MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
                    weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS));
    }

    if (error_code == net::ERR_ABORTED) {
      return NULL;
    }

    // Resource canceled with a specific error are filtered.
    return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
        resource_type, current_peer, error_code);
  }

  virtual webkit_glue::ResourceLoaderBridge::Peer* OnReceivedResponse(
      webkit_glue::ResourceLoaderBridge::Peer* current_peer,
      const std::string& mime_type,
      const GURL& url) {
    return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
        current_peer, RenderThread::Get(), mime_type, url);
  }

 private:
  void InformHostOfCacheStats() {
    WebCache::UsageStats stats;
    WebCache::getUsageStats(&stats);
    RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats));
  }

  base::WeakPtrFactory<RendererResourceDelegate> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate);
};

#if defined(OS_WIN)
static base::win::IATPatchFunction g_iat_patch_createdca;
HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
                          LPCSTR device_name,
                          LPCSTR output,
                          const void* init_data) {
  DCHECK(std::string("DISPLAY") == std::string(driver_name));
  DCHECK(!device_name);
  DCHECK(!output);
  DCHECK(!init_data);

  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
  return CreateCompatibleDC(NULL);
}

static base::win::IATPatchFunction g_iat_patch_get_font_data;
DWORD WINAPI GetFontDataPatch(HDC hdc,
                              DWORD table,
                              DWORD offset,
                              LPVOID buffer,
                              DWORD length) {
  int rv = GetFontData(hdc, table, offset, buffer, length);
  if (rv == GDI_ERROR && hdc) {
    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));

    LOGFONT logfont;
    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
      std::vector<char> font_data;
      RenderThread::Get()->PreCacheFont(logfont);
      rv = GetFontData(hdc, table, offset, buffer, length);
      RenderThread::Get()->ReleaseCachedFonts();
    }
  }
  return rv;
}
#endif  // OS_WIN

}  // namespace

bool ChromeRenderProcessObserver::is_incognito_process_ = false;

ChromeRenderProcessObserver::ChromeRenderProcessObserver(
    chrome::ChromeContentRendererClient* client)
    : client_(client),
      clear_cache_pending_(false) {
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kEnableWatchdog)) {
    // TODO(JAR): Need to implement renderer IO msgloop watchdog.
  }

  if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
    base::StatisticsRecorder::set_dump_on_exit(true);
  }

#if defined(TOOLKIT_VIEWS)
  WebRuntimeFeatures::enableRequestAutocomplete(
      command_line.HasSwitch(switches::kEnableInteractiveAutocomplete) ||
      command_line.HasSwitch(switches::kEnableExperimentalWebKitFeatures));
#endif

  RenderThread* thread = RenderThread::Get();
  resource_delegate_.reset(new RendererResourceDelegate());
  thread->SetResourceDispatcherDelegate(resource_delegate_.get());

  // Configure modules that need access to resources.
  net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);

#if defined(OS_WIN)
  // Need to patch a few functions for font loading to work correctly.
  FilePath pdf;
  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
      file_util::PathExists(pdf)) {
    g_iat_patch_createdca.Patch(
        pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
    g_iat_patch_get_font_data.Patch(
        pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
  }
#endif

#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
  // On platforms where we use system NSS libraries, the .so's must be loaded.
  if (!command_line.HasSwitch(switches::kSingleProcess)) {
    // We are going to fork to engage the sandbox and we have not loaded
    // any security modules so it is safe to disable the fork check in NSS.
    crypto::DisableNSSForkCheck();
    crypto::ForceNSSNoDBInit();
    crypto::EnsureNSSInit();
  }
#elif defined(OS_WIN)
  // crypt32.dll is used to decode X509 certificates for Chromoting.
  // Only load this library when the feature is enabled.
  std::string error;
  base::LoadNativeLibrary(FilePath(L"crypt32.dll"), &error);
#endif
  // Setup initial set of crash dump data for Field Trials in this renderer.
  chrome_variations::SetChildProcessLoggingVariationList();
}

ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
}

bool ChromeRenderProcessObserver::OnControlMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess,
                        OnSetIsIncognitoProcess)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetCacheCapacities, OnSetCacheCapacities)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_ClearCache, OnClearCache)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats, OnGetV8HeapStats)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats,
                        OnGetCacheResourceStats)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_PurgeMemory, OnPurgeMemory)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules,
                        OnSetContentSettingRules)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_ToggleWebKitSharedTimer,
                        OnToggleWebKitSharedTimer)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
    bool is_incognito_process) {
  is_incognito_process_ = is_incognito_process;
}

void ChromeRenderProcessObserver::OnSetContentSettingRules(
    const RendererContentSettingRules& rules) {
  content_setting_rules_ = rules;
}

void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity,
                                                       size_t max_dead_capacity,
                                                       size_t capacity) {
  WebCache::setCapacities(
      min_dead_capacity, max_dead_capacity, capacity);
}

void ChromeRenderProcessObserver::OnClearCache(bool on_navigation) {
  if (on_navigation) {
    clear_cache_pending_ = true;
  } else {
    WebCache::clear();
  }
}

void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
  WebCache::ResourceTypeStats stats;
  WebCache::getResourceTypeStats(&stats);
  RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
}

void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
    const std::string& field_trial_name,
    const std::string& group_name) {
  base::FieldTrial* trial =
      base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
  // Ensure the trial is marked as "used" by calling group() on it. This is
  // needed to ensure the trial is properly reported in renderer crash reports.
  trial->group();
  chrome_variations::SetChildProcessLoggingVariationList();
}

void ChromeRenderProcessObserver::OnGetV8HeapStats() {
  v8::HeapStatistics heap_stats;
  v8::V8::GetHeapStatistics(&heap_stats);
  RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
      heap_stats.total_heap_size(), heap_stats.used_heap_size()));
}

void ChromeRenderProcessObserver::OnToggleWebKitSharedTimer(bool suspend) {
  RenderThread::Get()->ToggleWebKitSharedTimer(suspend);
}

void ChromeRenderProcessObserver::OnPurgeMemory() {
  RenderThread::Get()->EnsureWebKitInitialized();

  // Clear the object cache (as much as possible; some live objects cannot be
  // freed).
  WebCache::clear();

  // Clear the font/glyph cache.
  WebFontCache::clear();

  // Clear the Cross-Origin Preflight cache.
  WebCrossOriginPreflightResultCache::clear();

  // Release all freeable memory from the SQLite process-global page cache (a
  // low-level object which backs the Connection-specific page caches).
  while (sqlite3_release_memory(std::numeric_limits<int>::max()) > 0) {
  }

  v8::V8::LowMemoryNotification();

  // Tell our allocator to release any free pages it's still holding.
  base::allocator::ReleaseFreeMemory();

  if (client_)
    client_->OnPurgeMemory();
}

void ChromeRenderProcessObserver::ExecutePendingClearCache() {
  if (clear_cache_pending_) {
    clear_cache_pending_ = false;
    WebCache::clear();
  }
}

const RendererContentSettingRules*
ChromeRenderProcessObserver::content_setting_rules() const {
  return &content_setting_rules_;
}
<commit_msg>Replace NSS init with wrapper.<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 "chrome/renderer/chrome_render_process_observer.h"

#include <limits>
#include <vector>

#include "base/allocator/allocator_extension.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/threading/platform_thread.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_localization_peer.h"
#include "chrome/common/metrics/variations/variations_util.h"
#include "chrome/common/net/net_resource_provider.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/chrome_content_renderer_client.h"
#include "chrome/renderer/content_settings_observer.h"
#include "chrome/renderer/security_filter_peer.h"
#include "content/public/common/resource_dispatcher_delegate.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view_visitor.h"
#include "content/public/renderer/render_view.h"
#include "crypto/nss_util.h"
#include "media/base/media_switches.h"
#include "net/base/net_errors.h"
#include "net/base/net_module.h"
#include "third_party/sqlite/sqlite3.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFontCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"

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

#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
#endif

using WebKit::WebCache;
using WebKit::WebCrossOriginPreflightResultCache;
using WebKit::WebFontCache;
using WebKit::WebRuntimeFeatures;
using content::RenderThread;

namespace {

static const int kCacheStatsDelayMS = 2000;

class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
 public:
  RendererResourceDelegate()
      : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
  }

  virtual webkit_glue::ResourceLoaderBridge::Peer* OnRequestComplete(
      webkit_glue::ResourceLoaderBridge::Peer* current_peer,
      ResourceType::Type resource_type,
      int error_code) {
    // Update the browser about our cache.
    // Rate limit informing the host of our cache stats.
    if (!weak_factory_.HasWeakPtrs()) {
      MessageLoop::current()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
                    weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS));
    }

    if (error_code == net::ERR_ABORTED) {
      return NULL;
    }

    // Resource canceled with a specific error are filtered.
    return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
        resource_type, current_peer, error_code);
  }

  virtual webkit_glue::ResourceLoaderBridge::Peer* OnReceivedResponse(
      webkit_glue::ResourceLoaderBridge::Peer* current_peer,
      const std::string& mime_type,
      const GURL& url) {
    return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
        current_peer, RenderThread::Get(), mime_type, url);
  }

 private:
  void InformHostOfCacheStats() {
    WebCache::UsageStats stats;
    WebCache::getUsageStats(&stats);
    RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats));
  }

  base::WeakPtrFactory<RendererResourceDelegate> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate);
};

#if defined(OS_WIN)
static base::win::IATPatchFunction g_iat_patch_createdca;
HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
                          LPCSTR device_name,
                          LPCSTR output,
                          const void* init_data) {
  DCHECK(std::string("DISPLAY") == std::string(driver_name));
  DCHECK(!device_name);
  DCHECK(!output);
  DCHECK(!init_data);

  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
  return CreateCompatibleDC(NULL);
}

static base::win::IATPatchFunction g_iat_patch_get_font_data;
DWORD WINAPI GetFontDataPatch(HDC hdc,
                              DWORD table,
                              DWORD offset,
                              LPVOID buffer,
                              DWORD length) {
  int rv = GetFontData(hdc, table, offset, buffer, length);
  if (rv == GDI_ERROR && hdc) {
    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));

    LOGFONT logfont;
    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
      std::vector<char> font_data;
      RenderThread::Get()->PreCacheFont(logfont);
      rv = GetFontData(hdc, table, offset, buffer, length);
      RenderThread::Get()->ReleaseCachedFonts();
    }
  }
  return rv;
}
#endif  // OS_WIN

}  // namespace

bool ChromeRenderProcessObserver::is_incognito_process_ = false;

ChromeRenderProcessObserver::ChromeRenderProcessObserver(
    chrome::ChromeContentRendererClient* client)
    : client_(client),
      clear_cache_pending_(false) {
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kEnableWatchdog)) {
    // TODO(JAR): Need to implement renderer IO msgloop watchdog.
  }

  if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
    base::StatisticsRecorder::set_dump_on_exit(true);
  }

#if defined(TOOLKIT_VIEWS)
  WebRuntimeFeatures::enableRequestAutocomplete(
      command_line.HasSwitch(switches::kEnableInteractiveAutocomplete) ||
      command_line.HasSwitch(switches::kEnableExperimentalWebKitFeatures));
#endif

  RenderThread* thread = RenderThread::Get();
  resource_delegate_.reset(new RendererResourceDelegate());
  thread->SetResourceDispatcherDelegate(resource_delegate_.get());

  // Configure modules that need access to resources.
  net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);

#if defined(OS_WIN)
  // Need to patch a few functions for font loading to work correctly.
  FilePath pdf;
  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
      file_util::PathExists(pdf)) {
    g_iat_patch_createdca.Patch(
        pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
    g_iat_patch_get_font_data.Patch(
        pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
  }
#endif

#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
  // On platforms where we use system NSS shared libraries,
  // initialize NSS now because it won't be able to load the .so's
  // after we engage the sandbox.
  if (!command_line.HasSwitch(switches::kSingleProcess))
    crypto::InitNSSSafely();
#elif defined(OS_WIN)
  // crypt32.dll is used to decode X509 certificates for Chromoting.
  // Only load this library when the feature is enabled.
  std::string error;
  base::LoadNativeLibrary(FilePath(L"crypt32.dll"), &error);
#endif
  // Setup initial set of crash dump data for Field Trials in this renderer.
  chrome_variations::SetChildProcessLoggingVariationList();
}

ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
}

bool ChromeRenderProcessObserver::OnControlMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess,
                        OnSetIsIncognitoProcess)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetCacheCapacities, OnSetCacheCapacities)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_ClearCache, OnClearCache)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats, OnGetV8HeapStats)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats,
                        OnGetCacheResourceStats)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_PurgeMemory, OnPurgeMemory)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules,
                        OnSetContentSettingRules)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_ToggleWebKitSharedTimer,
                        OnToggleWebKitSharedTimer)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
    bool is_incognito_process) {
  is_incognito_process_ = is_incognito_process;
}

void ChromeRenderProcessObserver::OnSetContentSettingRules(
    const RendererContentSettingRules& rules) {
  content_setting_rules_ = rules;
}

void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity,
                                                       size_t max_dead_capacity,
                                                       size_t capacity) {
  WebCache::setCapacities(
      min_dead_capacity, max_dead_capacity, capacity);
}

void ChromeRenderProcessObserver::OnClearCache(bool on_navigation) {
  if (on_navigation) {
    clear_cache_pending_ = true;
  } else {
    WebCache::clear();
  }
}

void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
  WebCache::ResourceTypeStats stats;
  WebCache::getResourceTypeStats(&stats);
  RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
}

void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
    const std::string& field_trial_name,
    const std::string& group_name) {
  base::FieldTrial* trial =
      base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
  // Ensure the trial is marked as "used" by calling group() on it. This is
  // needed to ensure the trial is properly reported in renderer crash reports.
  trial->group();
  chrome_variations::SetChildProcessLoggingVariationList();
}

void ChromeRenderProcessObserver::OnGetV8HeapStats() {
  v8::HeapStatistics heap_stats;
  v8::V8::GetHeapStatistics(&heap_stats);
  RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
      heap_stats.total_heap_size(), heap_stats.used_heap_size()));
}

void ChromeRenderProcessObserver::OnToggleWebKitSharedTimer(bool suspend) {
  RenderThread::Get()->ToggleWebKitSharedTimer(suspend);
}

void ChromeRenderProcessObserver::OnPurgeMemory() {
  RenderThread::Get()->EnsureWebKitInitialized();

  // Clear the object cache (as much as possible; some live objects cannot be
  // freed).
  WebCache::clear();

  // Clear the font/glyph cache.
  WebFontCache::clear();

  // Clear the Cross-Origin Preflight cache.
  WebCrossOriginPreflightResultCache::clear();

  // Release all freeable memory from the SQLite process-global page cache (a
  // low-level object which backs the Connection-specific page caches).
  while (sqlite3_release_memory(std::numeric_limits<int>::max()) > 0) {
  }

  v8::V8::LowMemoryNotification();

  // Tell our allocator to release any free pages it's still holding.
  base::allocator::ReleaseFreeMemory();

  if (client_)
    client_->OnPurgeMemory();
}

void ChromeRenderProcessObserver::ExecutePendingClearCache() {
  if (clear_cache_pending_) {
    clear_cache_pending_ = false;
    WebCache::clear();
  }
}

const RendererContentSettingRules*
ChromeRenderProcessObserver::content_setting_rules() const {
  return &content_setting_rules_;
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: SampleAppMain.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/ for details.

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

=========================================================================*/

#include "SampleApp.h"
#include <qapplication.h>
#include "itkTextOutput.h"
#include <itksys/SystemTools.hxx>
#include <stdexcept>

#include <mitkStandardFileLocations.h>
#include <mitkProperties.h>
#include <mitkVector.h>

#include <QmitkFunctionalityTesting.h>
#include <sstream>

/*
* BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
* Activating GlobalImmediateModeRendering in vtk solves this problem.
*/
//#include <vtkMapper.h>

#include <QmitkControlsRightFctLayoutTemplate.h>
#include <qsplitter.h>

int main(int argc, char* argv[])
{
  try
  {
    // Add directory in which the application executable resides as search directory
    mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(itksys::SystemTools::GetFilenamePath(argv[0]).c_str());
    //
    // determine application name without path and extension
    //
    std::string executableName = itksys::SystemTools::GetFilenameWithoutExtension( itksys::SystemTools::GetFilenameName(argv[0] ) );
    std::stringstream caption;
    caption << executableName << ", Builddate " << __DATE__ << ", " << __TIME__ << ".";
    itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());
    // parse testing parameters
    bool enableFunctionalityTesting = false;
    const char * testingParameter = NULL;
    if (strcmp(argv[argc-1], "-testing")==0) {
      enableFunctionalityTesting = true;
    } else if (argc >= 2 && strcmp(argv[argc-2], "-testing")==0) {
      testingParameter = argv[argc-1];
      enableFunctionalityTesting = true;
    }

    QApplication a( argc, argv );
    SampleApp mainWindow(NULL, "mainwindow",Qt::WType_TopLevel,testingParameter);
    mainWindow.setCaption( caption.str().c_str() );
    a.setMainWidget(&mainWindow);
#ifdef USEDARKPALETTE
    std::cout << "changing palette ..." << std::endl;
    QPalette p( QColor( 64,64,64), QColor(64,64,64));
    a.setPalette(p,TRUE);
#endif
    /*
    * BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
    * Activating GlobalImmediateModeRendering in vtk solves this problem. Also add #include vtkMapper above
    */
    //vtkMapper::GlobalImmediateModeRenderingOn();

    //B/     Setup MainApp Widget size (default: maximized) ////
    mitk::Point3dProperty* sizeProp = dynamic_cast<mitk::Point3dProperty*>
                                      (mainWindow.m_Options->GetProperty("Startup window size"));
    if(sizeProp)
    {
      mitk::Point3D p = sizeProp->GetValue();
      if(p[0] == 0.0 && p[1] == 0.0)
        mainWindow.showMaximized();
      else
      {
        mainWindow.resize(sizeProp->GetValue()[0], sizeProp->GetValue()[1]);
        mainWindow.show();
      }
    }
    else
      mainWindow.showMaximized();

    mainWindow.RaiseDialogBars();

    //B/ Setup  MultiWidget size (default: 2/3 of total MainApp width) ////
    mitk::Point3dProperty* splitterSizeProp = dynamic_cast<mitk::Point3dProperty*>
                                      (mainWindow.m_Options->GetProperty("Main Splitter ratio"));

    QmitkControlsRightFctLayoutTemplate* fctwidget = (QmitkControlsRightFctLayoutTemplate*) mainWindow.centralWidget();
    if(fctwidget)
    {
      QValueList<int> i;

      if(splitterSizeProp)
      {
        mitk::Point3D p = splitterSizeProp->GetValue();
        if(p[0] == 0.0 && p[1] == 0.0)
        {
          i.push_back(mainWindow.width()/3*2);
          i.push_back(mainWindow.width()/3*1);
        }
        else
        {
          i.push_back(p[0]);
          i.push_back(p[1]);
        }
      }
      else
      {
        i.push_back(mainWindow.width()/3*2);
        i.push_back(mainWindow.width()/3*1);
      }
      fctwidget->MainSplitter->setSizes(i);
      mainWindow.repaint();
    }

    if(enableFunctionalityTesting)
    {
      std::cout.setf(std::ios_base::unitbuf);
      return StartQmitkFunctionalityTesting(mainWindow.GetFctMediator());
    }
    else
    {
      return a.exec();
    }
  }
  catch (const std::bad_alloc& e)
  {
    std::cout << "MITK MainApp caught bad_alloc: Could not acquire enough memory: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception..." << std::endl;
    return EXIT_FAILURE;
  }
}
<commit_msg>FIX (#1125): MainApp windows black after startup (even with data loaded)<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: SampleAppMain.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/ for details.

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

=========================================================================*/

#include "SampleApp.h"
#include <qapplication.h>
#include "itkTextOutput.h"
#include <itksys/SystemTools.hxx>
#include <stdexcept>

#include <mitkStandardFileLocations.h>
#include <mitkProperties.h>
#include <mitkVector.h>

#include <QmitkFunctionalityTesting.h>
#include <sstream>

/*
* BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
* Activating GlobalImmediateModeRendering in vtk solves this problem.
*/
//#include <vtkMapper.h>

#include <QmitkControlsRightFctLayoutTemplate.h>
#include <qsplitter.h>

int main(int argc, char* argv[])
{
  try
  {
    // Add directory in which the application executable resides as search directory
    mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(itksys::SystemTools::GetFilenamePath(argv[0]).c_str());
    //
    // determine application name without path and extension
    //
    std::string executableName = itksys::SystemTools::GetFilenameWithoutExtension( itksys::SystemTools::GetFilenameName(argv[0] ) );
    std::stringstream caption;
    caption << executableName << ", Builddate " << __DATE__ << ", " << __TIME__ << ".";
    itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());
    // parse testing parameters
    bool enableFunctionalityTesting = false;
    const char * testingParameter = NULL;
    if (strcmp(argv[argc-1], "-testing")==0) {
      enableFunctionalityTesting = true;
    } else if (argc >= 2 && strcmp(argv[argc-2], "-testing")==0) {
      testingParameter = argv[argc-1];
      enableFunctionalityTesting = true;
    }

    QApplication a( argc, argv );
    SampleApp mainWindow(NULL, "mainwindow",Qt::WType_TopLevel,testingParameter);
    mainWindow.setCaption( caption.str().c_str() );
    a.setMainWidget(&mainWindow);
#ifdef USEDARKPALETTE
    std::cout << "changing palette ..." << std::endl;
    QPalette p( QColor( 64,64,64), QColor(64,64,64));
    a.setPalette(p,TRUE);
#endif
    /*
    * BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
    * Activating GlobalImmediateModeRendering in vtk solves this problem. Also add #include vtkMapper above
    */
    //vtkMapper::GlobalImmediateModeRenderingOn();

    //B/     Setup MainApp Widget size (default: maximized) ////
    mitk::Point3dProperty* sizeProp = dynamic_cast<mitk::Point3dProperty*>
                                      (mainWindow.m_Options->GetProperty("Startup window size"));
    if(sizeProp)
    {
      mitk::Point3D p = sizeProp->GetValue();
      if(p[0] == 0.0 && p[1] == 0.0)
        mainWindow.showMaximized();
      else
      {
        mainWindow.resize(sizeProp->GetValue()[0], sizeProp->GetValue()[1]);
        mainWindow.show();
      }
    }
    else
      mainWindow.showMaximized();

    mainWindow.RaiseDialogBars();

    //B/ Setup  MultiWidget size (default: 2/3 of total MainApp width) ////
    mitk::Point3dProperty* splitterSizeProp = dynamic_cast<mitk::Point3dProperty*>
                                      (mainWindow.m_Options->GetProperty("Main Splitter ratio"));

    QmitkControlsRightFctLayoutTemplate* fctwidget = (QmitkControlsRightFctLayoutTemplate*) mainWindow.centralWidget();
    if(fctwidget)
    {
      QValueList<int> i;

      if(splitterSizeProp)
      {
        mitk::Point3D p = splitterSizeProp->GetValue();
        if(p[0] == 0.0 && p[1] == 0.0)
        {
          i.push_back(mainWindow.width()/3*2);
          i.push_back(mainWindow.width()/3*1);
        }
        else
        {
          i.push_back(p[0]);
          i.push_back(p[1]);
        }
      }
      else
      {
        i.push_back(mainWindow.width()/3*2);
        i.push_back(mainWindow.width()/3*1);
      }
      fctwidget->MainSplitter->setSizes(i);
      mainWindow.repaint();
    }
    // reinit views after mainwindow and fctwidget initialization
    mainWindow.viewReinitMultiWidget();

    if(enableFunctionalityTesting)
    {
      std::cout.setf(std::ios_base::unitbuf);
      return StartQmitkFunctionalityTesting(mainWindow.GetFctMediator());
    }
    else
    {
      return a.exec();
    }
  }
  catch (const std::bad_alloc& e)
  {
    std::cout << "MITK MainApp caught bad_alloc: Could not acquire enough memory: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception..." << std::endl;
    return EXIT_FAILURE;
  }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/policy.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6()
#include <boost/crc.hpp>

#include "test.hpp"

using namespace libtorrent;

boost::uint32_t hash_buffer(char const* buf, int len)
{
	boost::crc_optimal<32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc;
	crc.process_block(buf, buf + len);
	return crc.checksum();
}

int test_main()
{

	// when the IP is the same, we hash the ports, sorted
	boost::uint32_t p = peer_priority(
		tcp::endpoint(address::from_string("230.12.123.3"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\x01\x2c\x04\xd2", 4));

	// when we're in the same /24, we just hash the IPs
	p = peer_priority(
		tcp::endpoint(address::from_string("230.12.123.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x7b\x01\xe6\x0c\x7b\x03", 8));

	// when we're in the same /16, we just hash the IPs masked by
	// 0xffffff55
	p = peer_priority(
		tcp::endpoint(address::from_string("230.12.23.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x17\x01\xe6\x0c\x7b\x01", 8));

	// when we're in different /16, we just hash the IPs masked by
	// 0xffff5555
	p = peer_priority(
		tcp::endpoint(address::from_string("230.120.23.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x51\x01\xe6\x78\x15\x01", 8));

	if (supports_ipv6())
	{
		// IPv6 has a twice as wide mask, and we only care about the top 64 bits
		// when the IPs are the same, just hash the ports
		p = peer_priority(
			tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x4d2)
			, tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x12c));
		TEST_EQUAL(p, hash_buffer("\x01\x2c\x04\xd2", 4));

		// these IPs don't belong to the same /32, so apply the full mask
		// 0xffffffff55555555
		p = peer_priority(
			tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x4d2)
			, tcp::endpoint(address::from_string("ffff:0fff:ffff:ffff::1"), 0x12c));
		TEST_EQUAL(p, hash_buffer(
			"\xff\xff\x0f\xff\x55\x55\x55\x55\x00\x00\x00\x00\x00\x00\x00\x01"
			"\xff\xff\xff\xff\x55\x55\x55\x55\x00\x00\x00\x00\x00\x00\x00\x01", 32));
	}

	return 0;
}

<commit_msg>add test vector from bep40 to test_peer_priority<commit_after>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/policy.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6()
#include <boost/crc.hpp>

#include "test.hpp"

using namespace libtorrent;

boost::uint32_t hash_buffer(char const* buf, int len)
{
	boost::crc_optimal<32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc;
	crc.process_block(buf, buf + len);
	return crc.checksum();
}

int test_main()
{

	// when the IP is the same, we hash the ports, sorted
	boost::uint32_t p = peer_priority(
		tcp::endpoint(address::from_string("230.12.123.3"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\x01\x2c\x04\xd2", 4));

	// when we're in the same /24, we just hash the IPs
	p = peer_priority(
		tcp::endpoint(address::from_string("230.12.123.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x7b\x01\xe6\x0c\x7b\x03", 8));

	// when we're in the same /16, we just hash the IPs masked by
	// 0xffffff55
	p = peer_priority(
		tcp::endpoint(address::from_string("230.12.23.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x17\x01\xe6\x0c\x7b\x01", 8));

	// when we're in different /16, we just hash the IPs masked by
	// 0xffff5555
	p = peer_priority(
		tcp::endpoint(address::from_string("230.120.23.1"), 0x4d2)
		, tcp::endpoint(address::from_string("230.12.123.3"), 0x12c));
	TEST_EQUAL(p, hash_buffer("\xe6\x0c\x51\x01\xe6\x78\x15\x01", 8));

	// test vectors from BEP 40
	TEST_EQUAL(peer_priority(
		tcp::endpoint(address::from_string("123.213.32.10"), 0)
		, tcp::endpoint(address::from_string("98.76.54.32"), 0))
		, 0xec2d7224);

	TEST_EQUAL(peer_priority(
		tcp::endpoint(address::from_string("123.213.32.10"), 0)
		, tcp::endpoint(address::from_string("123.213.32.234"), 0))
		, 0x99568189);

	if (supports_ipv6())
	{
		// IPv6 has a twice as wide mask, and we only care about the top 64 bits
		// when the IPs are the same, just hash the ports
		p = peer_priority(
			tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x4d2)
			, tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x12c));
		TEST_EQUAL(p, hash_buffer("\x01\x2c\x04\xd2", 4));

		// these IPs don't belong to the same /32, so apply the full mask
		// 0xffffffff55555555
		p = peer_priority(
			tcp::endpoint(address::from_string("ffff:ffff:ffff:ffff::1"), 0x4d2)
			, tcp::endpoint(address::from_string("ffff:0fff:ffff:ffff::1"), 0x12c));
		TEST_EQUAL(p, hash_buffer(
			"\xff\xff\x0f\xff\x55\x55\x55\x55\x00\x00\x00\x00\x00\x00\x00\x01"
			"\xff\xff\xff\xff\x55\x55\x55\x55\x00\x00\x00\x00\x00\x00\x00\x01", 32));
	}

	return 0;
}

<|endoftext|>


<commit_before>#pragma once
#include "../std/functional.hpp"
#include "../std/iterator.hpp"
#include "../std/map.hpp"

template <class ContainerT> class BackInsertFunctor
{
  ContainerT & m_Container;
public:
  explicit BackInsertFunctor(ContainerT & container) : m_Container(container)
  {
  }
  void operator() (typename ContainerT::value_type const & t) const
  {
    m_Container.push_back(t);
  }
};

template <class ContainerT>
BackInsertFunctor<ContainerT> MakeBackInsertFunctor(ContainerT & container)
{
  return BackInsertFunctor<ContainerT>(container);
}

template <class ContainerT> class InsertFunctor
{
  ContainerT & m_Container;
public:
  explicit InsertFunctor(ContainerT & container) : m_Container(container)
  {
  }
  void operator() (typename ContainerT::value_type const & t) const
  {
    m_Container.insert(t);
  }
};

template <class ContainerT>
InsertFunctor<ContainerT> MakeInsertFunctor(ContainerT & container)
{
  return InsertFunctor<ContainerT>(container);
}

template <class IterT, class CompareT> inline bool IsSorted(IterT beg, IterT end, CompareT comp)
{
  if (beg == end)
    return true;
  IterT prev = beg;
  for (++beg; beg != end; ++beg, ++prev)
  {
    if (comp(*beg, *prev))
      return false;
  }
  return true;
}

template <class IterT, class CompareT>
inline bool IsSortedAndUnique(IterT beg, IterT end, CompareT comp)
{
  if (beg == end)
    return true;
  IterT prev = beg;
  for (++beg; beg != end; ++beg, ++prev)
  {
    if (!comp(*prev, *beg))
      return false;
  }
  return true;
}

template <class IterT, class CompareT>
IterT RemoveIfKeepValid(IterT beg, IterT end, CompareT comp)
{
  while (beg != end)
  {
    if (comp(*beg))
    {
      while (beg != --end)
      {
        if (!comp(*end))
        {
          swap(*beg, *end);
          ++beg;
          break;
        }
      }
    }
    else
      ++beg;
  }

  return end;
}

template <class IterT> inline bool IsSorted(IterT beg, IterT end)
{
  return IsSorted(beg, end, less<typename iterator_traits<IterT>::value_type>());
}

template <class IterT> inline bool IsSortedAndUnique(IterT beg, IterT end)
{
  return IsSortedAndUnique(beg, end, less<typename iterator_traits<IterT>::value_type>());
}

struct DeleteFunctor
{
  template <typename T> void operator() (T const * p) const
  {
    delete p;
  }
};

struct NoopFunctor
{
  template <typename T> inline void operator () (T const &) const
  {
  }
};

struct IdFunctor
{
  template <typename T> inline T operator () (T const & x) const
  {
    return x;
  }
};

template <typename IterT> IterT NextIterInCycle(IterT it, IterT beg, IterT end)
{
  if (++it == end)
    return beg;
  return it;
}

template <typename IterT> IterT PrevIterInCycle(IterT it, IterT beg, IterT end)
{
  if (it == beg)
    it = end;
  return --it;
}

template <typename KeyT, typename ValueT, typename CompareT, typename AllocatorT>
ValueT ValueForKey(map<KeyT, ValueT, CompareT, AllocatorT> const & m, KeyT key, ValueT defaultV)
{
  typename map<KeyT, ValueT, CompareT, AllocatorT>::const_iterator const it = m.find(key);
  return (it == m.end() ? defaultV : it->second);
}
<commit_msg>Add guard for deleting objects in container.<commit_after>#pragma once
#include "../std/functional.hpp"
#include "../std/iterator.hpp"
#include "../std/map.hpp"

template <class ContainerT> class BackInsertFunctor
{
  ContainerT & m_Container;
public:
  explicit BackInsertFunctor(ContainerT & container) : m_Container(container)
  {
  }
  void operator() (typename ContainerT::value_type const & t) const
  {
    m_Container.push_back(t);
  }
};

template <class ContainerT>
BackInsertFunctor<ContainerT> MakeBackInsertFunctor(ContainerT & container)
{
  return BackInsertFunctor<ContainerT>(container);
}

template <class ContainerT> class InsertFunctor
{
  ContainerT & m_Container;
public:
  explicit InsertFunctor(ContainerT & container) : m_Container(container)
  {
  }
  void operator() (typename ContainerT::value_type const & t) const
  {
    m_Container.insert(t);
  }
};

template <class ContainerT>
InsertFunctor<ContainerT> MakeInsertFunctor(ContainerT & container)
{
  return InsertFunctor<ContainerT>(container);
}

template <class IterT, class CompareT> inline bool IsSorted(IterT beg, IterT end, CompareT comp)
{
  if (beg == end)
    return true;
  IterT prev = beg;
  for (++beg; beg != end; ++beg, ++prev)
  {
    if (comp(*beg, *prev))
      return false;
  }
  return true;
}

template <class IterT, class CompareT>
inline bool IsSortedAndUnique(IterT beg, IterT end, CompareT comp)
{
  if (beg == end)
    return true;
  IterT prev = beg;
  for (++beg; beg != end; ++beg, ++prev)
  {
    if (!comp(*prev, *beg))
      return false;
  }
  return true;
}

template <class IterT, class CompareT>
IterT RemoveIfKeepValid(IterT beg, IterT end, CompareT comp)
{
  while (beg != end)
  {
    if (comp(*beg))
    {
      while (beg != --end)
      {
        if (!comp(*end))
        {
          swap(*beg, *end);
          ++beg;
          break;
        }
      }
    }
    else
      ++beg;
  }

  return end;
}

template <class IterT> inline bool IsSorted(IterT beg, IterT end)
{
  return IsSorted(beg, end, less<typename iterator_traits<IterT>::value_type>());
}

template <class IterT> inline bool IsSortedAndUnique(IterT beg, IterT end)
{
  return IsSortedAndUnique(beg, end, less<typename iterator_traits<IterT>::value_type>());
}

struct DeleteFunctor
{
  template <typename T> void operator() (T const * p) const
  {
    delete p;
  }
};

template <class TContainer> class DeleteRangeGuard
{
  TContainer & m_cont;
public:
  DeleteRangeGuard(TContainer & cont) : m_cont(cont) {}
  ~DeleteRangeGuard()
  {
    for_each(m_cont.begin(), m_cont.end(), DeleteFunctor());
    m_cont.clear();
  }
};

struct NoopFunctor
{
  template <typename T> void operator () (T const &) const
  {
  }
};

struct IdFunctor
{
  template <typename T> inline T operator () (T const & x) const
  {
    return x;
  }
};

template <typename IterT> IterT NextIterInCycle(IterT it, IterT beg, IterT end)
{
  if (++it == end)
    return beg;
  return it;
}

template <typename IterT> IterT PrevIterInCycle(IterT it, IterT beg, IterT end)
{
  if (it == beg)
    it = end;
  return --it;
}

template <typename KeyT, typename ValueT, typename CompareT, typename AllocatorT>
ValueT ValueForKey(map<KeyT, ValueT, CompareT, AllocatorT> const & m, KeyT key, ValueT defaultV)
{
  typename map<KeyT, ValueT, CompareT, AllocatorT>::const_iterator const it = m.find(key);
  return (it == m.end() ? defaultV : it->second);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/torrent_info.hpp"

#if TORRENT_USE_IOSTREAM
#include <sstream>
#endif

struct test_torrent_t
{
	char const* file;
};

using namespace libtorrent;

test_torrent_t test_torrents[] =
{
	{ "base.torrent" },
	{ "empty_path.torrent" },
	{ "parent_path.torrent" },
	{ "hidden_parent_path.torrent" },
	{ "single_multi_file.torrent" },
	{ "slash_path.torrent" },
	{ "backslash_path.torrent" },
	{ "url_list.torrent" },
	{ "url_list2.torrent" },
	{ "url_list3.torrent" },
	{ "httpseed.torrent" },
	{ "empty_httpseed.torrent" },
	{ "long_name.torrent" },
	{ "whitespace_url.torrent" },
	{ "duplicate_files.torrent" },
	{ "pad_file.torrent" },
	{ "creation_date.torrent" },
	{ "no_creation_date.torrent" },
	{ "url_seed.torrent" },
	{ "url_seed_multi.torrent" },
	{ "url_seed_multi_space.torrent" },
	{ "url_seed_multi_space_nolist.torrent" },
	{ "root_hash.torrent" },
};

struct test_failing_torrent_t
{
	char const* file;
	error_code error; // the expected error
};

test_failing_torrent_t test_error_torrents[] =
{
	{ "missing_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "invalid_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "negative_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "no_name.torrent", errors::torrent_missing_name },
	{ "invalid_name.torrent", errors::torrent_missing_name },
	{ "invalid_name2.torrent", errors::torrent_invalid_name },
	{ "invalid_info.torrent", errors::torrent_missing_info },
	{ "string.torrent", errors::torrent_is_no_dict },
	{ "negative_size.torrent", errors::torrent_invalid_length },
	{ "negative_file_size.torrent", errors::torrent_file_parse_failed },
	{ "invalid_path_list.torrent", errors::torrent_file_parse_failed },
	{ "missing_path_list.torrent", errors::torrent_file_parse_failed },
	{ "invalid_pieces.torrent", errors::torrent_missing_pieces },
	{ "unaligned_pieces.torrent", errors::torrent_invalid_hashes },
	{ "invalid_root_hash.torrent", errors::torrent_invalid_hashes },
	{ "invalid_root_hash2.torrent", errors::torrent_missing_pieces},
	{ "invalid_file_size.torrent", errors::torrent_file_parse_failed },
};

// TODO: test remap_files
// TODO: merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash"
// TODO: torrent with 'p' (padfile) attribute
// TODO: torrent with 'h' (hidden) attribute
// TODO: torrent with 'x' (executable) attribute
// TODO: torrent with 'l' (symlink) attribute
// TODO: creating a merkle torrent (torrent_info::build_merkle_list)
// TODO: torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once)

int test_main()
{
	for (int i = 0; i < sizeof(test_torrents)/sizeof(test_torrents[0]); ++i)
	{
		error_code ec;
		fprintf(stderr, "loading %s\n", test_torrents[i].file);
		boost::intrusive_ptr<torrent_info> ti(new torrent_info(combine_path(combine_path("..", "test_torrents"), test_torrents[i].file), ec));
		TEST_CHECK(!ec);
		if (ec) fprintf(stderr, "  -> failed %s\n", ec.message().c_str());

		if (std::string(test_torrents[i].file) == "whitespace_url.torrent")
		{
			// make sure we trimmed the url
			TEST_CHECK(ti->trackers().size() > 0);
			if (ti->trackers().size() > 0)
				TEST_CHECK(ti->trackers()[0].url == "udp://test.com/announce");
		}
		else if (std::string(test_torrents[i].file) == "duplicate_files.torrent")
		{
			// make sure we disambiguated the files
			TEST_EQUAL(ti->num_files(), 2);
			TEST_CHECK(ti->file_at(0).path == combine_path(combine_path("temp", "foo"), "bar.txt"));
			TEST_CHECK(ti->file_at(1).path == combine_path(combine_path("temp", "foo"), "bar.1.txt"));
		}
		else if (std::string(test_torrents[i].file) == "pad_file.torrent")
		{
			TEST_EQUAL(ti->num_files(), 2);
			TEST_CHECK(ti->file_at(0).pad_file == false);
			TEST_CHECK(ti->file_at(1).pad_file == true);
		}
		else if (std::string(test_torrents[i].file) == "creation_date.torrent")
		{
			TEST_CHECK(*ti->creation_date() == 1234567);
		}
		else if (std::string(test_torrents[i].file) == "no_creation_date.torrent")
		{
			TEST_CHECK(!ti->creation_date());
		}
		else if (std::string(test_torrents[i].file) == "url_seed.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file");
#endif
		}
		else if (std::string(test_torrents[i].file) == "url_seed_multi.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file/");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file/");
#endif
		}
		else if (std::string(test_torrents[i].file) == "url_seed_multi_space.torrent"
			|| std::string(test_torrents[i].file) == "url_seed_multi_space_nolist.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/test%20file/foo%20bar/");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/test%20file/foo%20bar/");
#endif
		}

		int index = 0;
		for (torrent_info::file_iterator i = ti->begin_files();
			i != ti->end_files(); ++i, ++index)
		{
			int first = ti->map_file(index, 0, 0).piece;
			int last = ti->map_file(index, (std::max)(size_type(i->size)-1, size_type(0)), 0).piece;
			fprintf(stderr, "  %11"PRId64" %c%c%c%c [ %4d, %4d ] %7u %s %s %s%s\n"
				, i->size
				, (i->pad_file?'p':'-')
				, (i->executable_attribute?'x':'-')
				, (i->hidden_attribute?'h':'-')
				, (i->symlink_attribute?'l':'-')
				, first, last
				, boost::uint32_t(ti->files().mtime(*i))
				, ti->files().hash(*i) != sha1_hash(0) ? to_hex(ti->files().hash(*i).to_string()).c_str() : ""
				, ti->files().file_path(*i).c_str()
				, i->symlink_attribute ? "-> ": ""
				, i->symlink_attribute && i->symlink_index != -1 ? ti->files().symlink(*i).c_str() : "");
		}

		// test swap
#if !defined TORRENT_NO_DEPRECATE && TORRENT_USE_IOSTREAM
		std::stringstream str1;
		ti->print(str1);

		torrent_info temp("temp", ec);
		temp.swap(*ti);

		std::stringstream str2;
		temp.print(str2);
		TEST_EQUAL(str1.str(), str2.str());
#endif

	}

	for (int i = 0; i < sizeof(test_error_torrents)/sizeof(test_error_torrents[0]); ++i)
	{
		error_code ec;
		fprintf(stderr, "loading %s\n", test_error_torrents[i].file);
		boost::intrusive_ptr<torrent_info> ti(new torrent_info(combine_path(combine_path("..", "test_torrents"), test_error_torrents[i].file), ec));
		fprintf(stderr, "E: %s\nexpected: %s\n", ec.message().c_str(), test_error_torrents[i].error.message().c_str());
		TEST_EQUAL(ec, test_error_torrents[i].error);
	}

	return 0;
}

<commit_msg>fix test_torrent_parse for windows<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/torrent_info.hpp"

#if TORRENT_USE_IOSTREAM
#include <sstream>
#endif

struct test_torrent_t
{
	char const* file;
};

using namespace libtorrent;

test_torrent_t test_torrents[] =
{
	{ "base.torrent" },
	{ "empty_path.torrent" },
	{ "parent_path.torrent" },
	{ "hidden_parent_path.torrent" },
	{ "single_multi_file.torrent" },
	{ "slash_path.torrent" },
	{ "backslash_path.torrent" },
	{ "url_list.torrent" },
	{ "url_list2.torrent" },
	{ "url_list3.torrent" },
	{ "httpseed.torrent" },
	{ "empty_httpseed.torrent" },
	{ "long_name.torrent" },
	{ "whitespace_url.torrent" },
	{ "duplicate_files.torrent" },
	{ "pad_file.torrent" },
	{ "creation_date.torrent" },
	{ "no_creation_date.torrent" },
	{ "url_seed.torrent" },
	{ "url_seed_multi.torrent" },
	{ "url_seed_multi_space.torrent" },
	{ "url_seed_multi_space_nolist.torrent" },
	{ "root_hash.torrent" },
};

struct test_failing_torrent_t
{
	char const* file;
	error_code error; // the expected error
};

test_failing_torrent_t test_error_torrents[] =
{
	{ "missing_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "invalid_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "negative_piece_len.torrent", errors::torrent_missing_piece_length },
	{ "no_name.torrent", errors::torrent_missing_name },
	{ "invalid_name.torrent", errors::torrent_missing_name },
	{ "invalid_name2.torrent", errors::torrent_invalid_name },
	{ "invalid_info.torrent", errors::torrent_missing_info },
	{ "string.torrent", errors::torrent_is_no_dict },
	{ "negative_size.torrent", errors::torrent_invalid_length },
	{ "negative_file_size.torrent", errors::torrent_file_parse_failed },
	{ "invalid_path_list.torrent", errors::torrent_file_parse_failed },
	{ "missing_path_list.torrent", errors::torrent_file_parse_failed },
	{ "invalid_pieces.torrent", errors::torrent_missing_pieces },
	{ "unaligned_pieces.torrent", errors::torrent_invalid_hashes },
	{ "invalid_root_hash.torrent", errors::torrent_invalid_hashes },
	{ "invalid_root_hash2.torrent", errors::torrent_missing_pieces},
	{ "invalid_file_size.torrent", errors::torrent_file_parse_failed },
};

// TODO: test remap_files
// TODO: merkle torrents. specifically torrent_info::add_merkle_nodes and torrent with "root hash"
// TODO: torrent with 'p' (padfile) attribute
// TODO: torrent with 'h' (hidden) attribute
// TODO: torrent with 'x' (executable) attribute
// TODO: torrent with 'l' (symlink) attribute
// TODO: creating a merkle torrent (torrent_info::build_merkle_list)
// TODO: torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once)

int test_main()
{
	std::string root_dir = parent_path(current_working_directory());
	for (int i = 0; i < sizeof(test_torrents)/sizeof(test_torrents[0]); ++i)
	{
		error_code ec;
		fprintf(stderr, "loading %s\n", test_torrents[i].file);
		boost::intrusive_ptr<torrent_info> ti(new torrent_info(combine_path(combine_path(root_dir, "test_torrents"), test_torrents[i].file), ec));
		TEST_CHECK(!ec);
		if (ec) fprintf(stderr, "  -> failed %s\n", ec.message().c_str());

		if (std::string(test_torrents[i].file) == "whitespace_url.torrent")
		{
			// make sure we trimmed the url
			TEST_CHECK(ti->trackers().size() > 0);
			if (ti->trackers().size() > 0)
				TEST_CHECK(ti->trackers()[0].url == "udp://test.com/announce");
		}
		else if (std::string(test_torrents[i].file) == "duplicate_files.torrent")
		{
			// make sure we disambiguated the files
			TEST_EQUAL(ti->num_files(), 2);
			TEST_CHECK(ti->file_at(0).path == combine_path(combine_path("temp", "foo"), "bar.txt"));
			TEST_CHECK(ti->file_at(1).path == combine_path(combine_path("temp", "foo"), "bar.1.txt"));
		}
		else if (std::string(test_torrents[i].file) == "pad_file.torrent")
		{
			TEST_EQUAL(ti->num_files(), 2);
			TEST_CHECK(ti->file_at(0).pad_file == false);
			TEST_CHECK(ti->file_at(1).pad_file == true);
		}
		else if (std::string(test_torrents[i].file) == "creation_date.torrent")
		{
			TEST_CHECK(*ti->creation_date() == 1234567);
		}
		else if (std::string(test_torrents[i].file) == "no_creation_date.torrent")
		{
			TEST_CHECK(!ti->creation_date());
		}
		else if (std::string(test_torrents[i].file) == "url_seed.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file");
#endif
		}
		else if (std::string(test_torrents[i].file) == "url_seed_multi.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/file/");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/file/");
#endif
		}
		else if (std::string(test_torrents[i].file) == "url_seed_multi_space.torrent"
			|| std::string(test_torrents[i].file) == "url_seed_multi_space_nolist.torrent")
		{
			TEST_EQUAL(ti->web_seeds().size(), 1);
			TEST_EQUAL(ti->web_seeds()[0].url, "http://test.com/test%20file/foo%20bar/");
#ifndef TORRENT_NO_DEPRECATE
			TEST_EQUAL(ti->http_seeds().size(), 0);
			TEST_EQUAL(ti->url_seeds().size(), 1);
			TEST_EQUAL(ti->url_seeds()[0], "http://test.com/test%20file/foo%20bar/");
#endif
		}

		int index = 0;
		for (torrent_info::file_iterator i = ti->begin_files();
			i != ti->end_files(); ++i, ++index)
		{
			int first = ti->map_file(index, 0, 0).piece;
			int last = ti->map_file(index, (std::max)(size_type(i->size)-1, size_type(0)), 0).piece;
			fprintf(stderr, "  %11"PRId64" %c%c%c%c [ %4d, %4d ] %7u %s %s %s%s\n"
				, i->size
				, (i->pad_file?'p':'-')
				, (i->executable_attribute?'x':'-')
				, (i->hidden_attribute?'h':'-')
				, (i->symlink_attribute?'l':'-')
				, first, last
				, boost::uint32_t(ti->files().mtime(*i))
				, ti->files().hash(*i) != sha1_hash(0) ? to_hex(ti->files().hash(*i).to_string()).c_str() : ""
				, ti->files().file_path(*i).c_str()
				, i->symlink_attribute ? "-> ": ""
				, i->symlink_attribute && i->symlink_index != -1 ? ti->files().symlink(*i).c_str() : "");
		}

		// test swap
#if !defined TORRENT_NO_DEPRECATE && TORRENT_USE_IOSTREAM
		std::stringstream str1;
		ti->print(str1);

		torrent_info temp("temp", ec);
		temp.swap(*ti);

		std::stringstream str2;
		temp.print(str2);
		TEST_EQUAL(str1.str(), str2.str());
#endif

	}

	for (int i = 0; i < sizeof(test_error_torrents)/sizeof(test_error_torrents[0]); ++i)
	{
		error_code ec;
		fprintf(stderr, "loading %s\n", test_error_torrents[i].file);
		boost::intrusive_ptr<torrent_info> ti(new torrent_info(combine_path(combine_path(root_dir, "test_torrents"), test_error_torrents[i].file), ec));
		fprintf(stderr, "E: %s\nexpected: %s\n", ec.message().c_str(), test_error_torrents[i].error.message().c_str());
		TEST_EQUAL(ec, test_error_torrents[i].error);
	}

	return 0;
}

<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief This file specifies auxiliary functions and data used by a Bison
 *        parser to convert YAML data to a key set.
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <cerrno>
#include <fstream>

#include "driver.hpp"

using std::ifstream;
using std::string;
using std::to_string;

using kdb::Key;
using kdb::KeySet;

using yy::parser;

// -- Macros -------------------------------------------------------------------

#define DEBUG_LEVEL 0

// -- Functions ----------------------------------------------------------------

namespace
{

/**
 * @brief This function converts a given number to an array base name.
 *
 * @param index This number specifies the index of the array entry.
 *
 * @return A string representing the given indices as Elektra array name.
 */
string indexToArrayBaseName (uintmax_t const index)
{
	size_t digits = 1;

	for (uintmax_t value = index; value > 9; digits++)
	{
		value /= 10;
	}

	return "#" + string (digits - 1, '_') + to_string (index);
}

/**
 * @brief This function converts a YAML scalar to a string.
 *
 * @param text This string contains a YAML scalar (including quote
 *             characters).
 *
 * @return A string without leading and trailing quote characters
 */
string scalarToText (string const & text)
{
	if (text.length () == 0)
	{
		return text;
	}
	if (*(text.begin ()) == '"' || *(text.begin ()) == '\'')
	{
		return text.substr (1, text.length () - 2);
	}
	return text;
}

} // namespace

// -- Class --------------------------------------------------------------------

/**
 * This constructor creates a new driver for the given parent key.
 *
 * @param parent This key specifies the parent of the key set the parser
 *               creates.
 */
Driver::Driver (Key const & parent)
{
	parents.push (parent);
}

/**
 * @brief This function parses the current YAML file.
 *
 * @param filename This parameter stores the path of the file the driver
 *                 should parse.
 *
 * @retval -3 if the given file could not be opened
 * @retval -2 if parsing was unsuccessful due to memory exhaustion
 * @retval -1 if the given file contains a syntax error
 * @retval  0 if parsing was successful
 */
int Driver::parse (const string & filepath)
{
	filename = filepath;

	ifstream input{ filename };
	if (!input.good ()) return -3;

	Lexer lexer{ input };
	parser parser{ lexer, *this };
	parser.set_debug_level (DEBUG_LEVEL);

	return -parser.parse ();
}

/**
 * @brief This method retrieves the current key set produced by the driver.
 *
 * @return A key set representing the YAML data produced by the last call of
 *         the method `parse`
 */
KeySet Driver::getKeySet () const
{
	return keys;
}

/**
 * @brief This function will be called by the Bison parser to indicate an error.
 *
 * @param location This value specifies the location of the erroneous input.
 * @param message This value stores the error message emitted by the Bison
 *                parser.
 */
void Driver::error (const location_type & location, const string & message)
{
	errorMessage = filename + ":" + to_string (location.begin.line) + ":" + to_string (location.begin.column) + ": " + message;
}

/**
 * @brief This function returns the last error message produced by the parser.
 *
 * @return A string containing an error message describing a syntax error
 */
string Driver::getErrorMessage ()
{
	return errorMessage;
}

// ===========
// = Actions =
// ===========

/**
 * @brief This function will be called after the parser exits a value.
 *
 * @param text This variable contains the text stored in the value.
 */
void Driver::exitValue (string const & text)
{
	Key key = parents.top ();
	key.setString (scalarToText (text));
	keys.append (key);
}

/**
 * @brief This function will be called after the parser found a key.
 *
 * @param text This variable contains the text of the key.
 */
void Driver::exitKey (string const & text)
{
	// Entering a mapping such as `part: …` means that we need to add `part` to
	// the key name
	Key child{ parents.top ().getName (), KEY_END };
	child.addBaseName (scalarToText (text));
	parents.push (child);
}

/**
 * @brief This function will be called after the parser exits a key-value
 *        pair.
 *
 * @param matchedValue This variable specifies if the pair contains a value
 *                     or not.
 */
void Driver::exitPair (bool const matchedValue)
{
	if (!matchedValue)
	{
		// Add key with empty value
		keys.append (parents.top ());
	}
	// Returning from a mapping such as `part: …` means that we need need to
	// remove the key for `part` from the stack.
	parents.pop ();
}

/**
 * @brief This function will be called after the parser enters a sequence.
 */
void Driver::enterSequence ()
{
	indices.push (0);
	parents.top ().setMeta ("array", ""); // We start with an empty array
}

/**
 * @brief This function will be called after the parser exits a sequence.
 */
void Driver::exitSequence ()
{
	// We add the parent key of all array elements after we leave the sequence
	keys.append (parents.top ());
	indices.pop ();
}

/**
 * @brief This function will be called after the parser recognizes an element
 *        of a sequence.
 */
void Driver::enterElement ()
{

	Key key{ parents.top ().getName (), KEY_END };
	key.addBaseName (indexToArrayBaseName (indices.top ()));

	uintmax_t index = indices.top ();
	indices.pop ();
	if (index < UINTMAX_MAX)
	{
		index++;
	}
	indices.push (index);

	parents.top ().setMeta ("array", key.getBaseName ());
	parents.push (key);
}

/**
 * @brief This function will be called after the parser read an element of a
 *        sequence.
 */
void Driver::exitElement ()
{
	parents.pop (); // Remove the key for the current array entry
}
<commit_msg>YAMBi: Throw exception in case of array overflow<commit_after>/**
 * @file
 *
 * @brief This file specifies auxiliary functions and data used by a Bison
 *        parser to convert YAML data to a key set.
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <cerrno>
#include <fstream>
#include <stdexcept>

#include "driver.hpp"

using std::ifstream;
using std::overflow_error;
using std::string;
using std::to_string;

using kdb::Key;
using kdb::KeySet;

using yy::parser;

// -- Macros -------------------------------------------------------------------

#define DEBUG_LEVEL 0

// -- Functions ----------------------------------------------------------------

namespace
{

/**
 * @brief This function converts a given number to an array base name.
 *
 * @param index This number specifies the index of the array entry.
 *
 * @return A string representing the given indices as Elektra array name.
 */
string indexToArrayBaseName (uintmax_t const index)
{
	size_t digits = 1;

	for (uintmax_t value = index; value > 9; digits++)
	{
		value /= 10;
	}

	return "#" + string (digits - 1, '_') + to_string (index);
}

/**
 * @brief This function converts a YAML scalar to a string.
 *
 * @param text This string contains a YAML scalar (including quote
 *             characters).
 *
 * @return A string without leading and trailing quote characters
 */
string scalarToText (string const & text)
{
	if (text.length () == 0)
	{
		return text;
	}
	if (*(text.begin ()) == '"' || *(text.begin ()) == '\'')
	{
		return text.substr (1, text.length () - 2);
	}
	return text;
}

} // namespace

// -- Class --------------------------------------------------------------------

/**
 * This constructor creates a new driver for the given parent key.
 *
 * @param parent This key specifies the parent of the key set the parser
 *               creates.
 */
Driver::Driver (Key const & parent)
{
	parents.push (parent);
}

/**
 * @brief This function parses the current YAML file.
 *
 * @param filename This parameter stores the path of the file the driver
 *                 should parse.
 *
 * @retval -3 if the given file could not be opened
 * @retval -2 if parsing was unsuccessful due to memory exhaustion
 * @retval -1 if the given file contains a syntax error
 * @retval  0 if parsing was successful
 */
int Driver::parse (const string & filepath)
{
	filename = filepath;

	ifstream input{ filename };
	if (!input.good ()) return -3;

	Lexer lexer{ input };
	parser parser{ lexer, *this };
	parser.set_debug_level (DEBUG_LEVEL);

	return -parser.parse ();
}

/**
 * @brief This method retrieves the current key set produced by the driver.
 *
 * @return A key set representing the YAML data produced by the last call of
 *         the method `parse`
 */
KeySet Driver::getKeySet () const
{
	return keys;
}

/**
 * @brief This function will be called by the Bison parser to indicate an error.
 *
 * @param location This value specifies the location of the erroneous input.
 * @param message This value stores the error message emitted by the Bison
 *                parser.
 */
void Driver::error (const location_type & location, const string & message)
{
	errorMessage = filename + ":" + to_string (location.begin.line) + ":" + to_string (location.begin.column) + ": " + message;
}

/**
 * @brief This function returns the last error message produced by the parser.
 *
 * @return A string containing an error message describing a syntax error
 */
string Driver::getErrorMessage ()
{
	return errorMessage;
}

// ===========
// = Actions =
// ===========

/**
 * @brief This function will be called after the parser exits a value.
 *
 * @param text This variable contains the text stored in the value.
 */
void Driver::exitValue (string const & text)
{
	Key key = parents.top ();
	key.setString (scalarToText (text));
	keys.append (key);
}

/**
 * @brief This function will be called after the parser found a key.
 *
 * @param text This variable contains the text of the key.
 */
void Driver::exitKey (string const & text)
{
	// Entering a mapping such as `part: …` means that we need to add `part` to
	// the key name
	Key child{ parents.top ().getName (), KEY_END };
	child.addBaseName (scalarToText (text));
	parents.push (child);
}

/**
 * @brief This function will be called after the parser exits a key-value
 *        pair.
 *
 * @param matchedValue This variable specifies if the pair contains a value
 *                     or not.
 */
void Driver::exitPair (bool const matchedValue)
{
	if (!matchedValue)
	{
		// Add key with empty value
		keys.append (parents.top ());
	}
	// Returning from a mapping such as `part: …` means that we need need to
	// remove the key for `part` from the stack.
	parents.pop ();
}

/**
 * @brief This function will be called after the parser enters a sequence.
 */
void Driver::enterSequence ()
{
	indices.push (0);
	parents.top ().setMeta ("array", ""); // We start with an empty array
}

/**
 * @brief This function will be called after the parser exits a sequence.
 */
void Driver::exitSequence ()
{
	// We add the parent key of all array elements after we leave the sequence
	keys.append (parents.top ());
	indices.pop ();
}

/**
 * @brief This function will be called after the parser recognizes an element
 *        of a sequence.
 */
void Driver::enterElement ()
{

	Key key{ parents.top ().getName (), KEY_END };
	if (indices.top () >= UINTMAX_MAX) throw overflow_error ("Unable to increase array index for array “" + key.getName () + "”");

	key.addBaseName (indexToArrayBaseName (indices.top ()));

	uintmax_t index = indices.top ();
	indices.pop ();
	index++;
	indices.push (index);

	parents.top ().setMeta ("array", key.getBaseName ());
	parents.push (key);
}

/**
 * @brief This function will be called after the parser read an element of a
 *        sequence.
 */
void Driver::exitElement ()
{
	parents.pop (); // Remove the key for the current array entry
}
<|endoftext|>


<commit_before>#include "vlc_video_source.h"
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <thread>

namespace gg
{

//-----------------------------------------------------------------------------
VideoSourceVLC::VideoSourceVLC( const std::string path )
    : _vlc_inst(nullptr)
    , _vlc_mp(nullptr)
    , m_size( 0 )
    , m_pixWidth( 0 )
    , m_pixHeight( 0 )
{
    this->mInitSource( path.c_str() );
    this->mRunSource();
    //std::cout<<"sleeping"<<std::endl;
    //std::this_thread::sleep_for(std::chrono::seconds(1));
    //std::cout<<"done sleeping"<<std::endl;
}

//-----------------------------------------------------------------------------
VideoSourceVLC::~VideoSourceVLC()
{
    /* Stop playing */
    libvlc_media_player_stop( this->_vlc_mp );

    /* Free the media_player */
    if( _vlc_mp ) {
        libvlc_media_player_release( this->_vlc_mp );
    }
    // the following lines was not working a few years ago (core dump if several streams are open) - \todo recheck if we want it back
    //if ( m_vlcInstance ){
    //   libvlc_release ( m_vlcInstance );
    //}
}

//-----------------------------------------------------------------------------
bool VideoSourceVLC::get_frame_dimensions( int & width, int & height )
{
    ///\todo mutex
    if( this->m_pixWidth==0 || this->m_pixHeight==0 ) {
        //std::cerr<<"Size not set yet"<<std::endl;
        return false;
    }
    width = this->m_pixWidth;
    height = this->m_pixHeight;
    return true;
}

//-----------------------------------------------------------------------------
bool VideoSourceVLC::get_frame( VideoFrame_BGRA & frame )
{
    ///\todo mutex

    if( this->m_pixWidth==0 || this->m_pixHeight==0 || !this->m_videoBuffer ) {
        //std::cerr<<"Size not set yet in VideoSourceVLC::get_next_frame"<<std::endl;
        return false;
    }

    //std::cout<<"m_pixWidth: "<<m_pixWidth<<std::endl;
    //std::cout<<"m_pixHeight: "<<m_pixHeight<<std::endl;
    //std::cout<<"m_size: "<<m_size<<std::endl;

    //Allocate and fill the image
    if( this->m_pixWidth*this->m_pixHeight*4 == this->m_size ) {
        frame = VideoFrame_BGRA(this->m_videoBuffer, this->m_pixWidth, this->m_pixHeight);
    }
    else
    {
        throw std::runtime_error("get_next_frame not implemented for padded images");
    }

    //std::cout<<"VideoSourceVLC::get_next_frame"<<std::endl;
    //throw std::runtime_error("get_next_frame to be implemented");
    return true;
}

bool get_frame(VideoFrame_I420 & frame)
{
    // TODO
    throw gg::VideoSourceError("get_frame(VideoFrame_I420 & frame) not implemented for VLC");
}

//-----------------------------------------------------------------------------
double VideoSourceVLC::get_frame_rate()
{
    //return libvlc_media_player_get_rate( m_mp );
    return libvlc_media_player_get_fps( this->_vlc_mp );
    //throw std::runtime_error("get_frame_rate to be implemented");
    //return 0.0;
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::set_sub_frame( int x, int y, int width, int height )
{
    throw std::runtime_error("set_sub_frame not implemented");
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::mInitSource( const char * path )
{
    try {
        // VLC pointers
        libvlc_media_t    *media;

        // VLC options
        char smem_options[512];

        sprintf( smem_options, "#transcode{vcodec=BGRA}:smem{video-data=%lld,video-prerender-callback=%lld,video-postrender-callback=%lld}",
                 // We are using transcode because smem only support raw audio and video formats
                 (long long int)(intptr_t)(void*) this,                               // we pass the pointer of the current object to the static callbacks
                 (long long int)(intptr_t)(void*) &VideoSourceVLC::prepareRender,  // pointer to the 1st callback called by VLC (static)
                 (long long int)(intptr_t)(void*) &VideoSourceVLC::handleStream ); // pointer to the 2nd callback called by VLC (static)

        const char * const vlc_args[] = {
            "-I", "dummy",        // Don't use any interface
            "--ignore-config",    // Don't use VLC's config
            "--extraintf=logger", // Log anything
            //"--verbose=2", // Be much more verbose then normal for debugging purpose
            //"--clock-jitter=0",
            //"--file-caching=150",
            "--no-audio",
            "--sout", smem_options    // Stream to memory
        };

        // We launch VLC
        _vlc_inst = libvlc_new( sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args );

        // If path contains a colon (:), it will be treated as a
        // URL. Else, it will be considered as a local path.
        if( std::string(path).find(":") == std::string::npos ) {
            //std::cout<<"opening file "<<path<<std::endl;
            media = libvlc_media_new_path( _vlc_inst, path );
        }
        else {
            //std::cout<<"opening url "<<path<<std::endl;
            media = libvlc_media_new_location( _vlc_inst, path );
        }

        libvlc_media_add_option( media, ":noaudio" );
        libvlc_media_add_option( media, ":no-video-title-show" );

        // Create a media player playing environement
        _vlc_mp = libvlc_media_player_new_from_media( media );
        // No need to keep the media now
        libvlc_media_release( media );

        //std::cout<<"Media open: "<<path<<std::endl;
    }
    catch( ... ) {
        throw std::runtime_error( std::string("Init device failed for the path ").append( path ) );
    }
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::mRunSource()
{
    try {
        // play the media_player
        libvlc_media_player_play( _vlc_mp );
        //std::cout<<"Media playing"<<std::endl;
        return;
    }
    catch( ... )
    {
        throw std::runtime_error("Error while running source");
        //std::cerr<<"Error while running source"<<std::endl;
        //return;
    }
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::prepareRender( VideoSourceVLC* p_video_data, uint8_t** pp_pixel_buffer, int size )
{
    ///\todo create mutex guard
    //std::cout<<"VideoSourceVLC::prepareRender"<<std::endl;
    // called before video rendered
    // p_video_data is the echo of the "this" pointer
    if( size != p_video_data->m_size ) {
        p_video_data->m_videoBuffer = new uint8_t[size];
        p_video_data->m_size = size;
        unsigned int width,height;
        libvlc_video_get_size( p_video_data->_vlc_mp, 0, &width, &height );
        p_video_data->m_pixWidth = width;
        p_video_data->m_pixHeight = height;
    }

    *pp_pixel_buffer = p_video_data->m_videoBuffer;
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::handleStream( VideoSourceVLC* /*p_video_data*/, uint8_t* /*p_pixel_buffer*/, int /*width*/, int /*height*/,
                                   int /*pixel_pitch*/, int /*size*/, int64_t /*pts*/ )
{
    ///\todo create mutex guard
    //std::cout<<"VideoSourceVLC::handleStream"<<std::endl;
    //std::cout<<"pixel_pitch"<<pixel_pitch<<std::endl;
    //std::cout<<"size"<<size<<std::endl;
    //std::cout<<"pts"<<pts<<std::endl;
    // called after video rendered
    // p_video_data is the echo of the "this" pointer
    //p_video_data->mReadRGBFrame( p_video_data->m_videoBuffer );
    //p_video_data->m_pixWidth = width;
    //p_video_data->m_pixHeight = height;
}

}
<commit_msg>Issue #83: activated code for releasing VLC engine<commit_after>#include "vlc_video_source.h"
#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <thread>

namespace gg
{

//-----------------------------------------------------------------------------
VideoSourceVLC::VideoSourceVLC( const std::string path )
    : _vlc_inst(nullptr)
    , _vlc_mp(nullptr)
    , m_size( 0 )
    , m_pixWidth( 0 )
    , m_pixHeight( 0 )
{
    this->mInitSource( path.c_str() );
    this->mRunSource();
    //std::cout<<"sleeping"<<std::endl;
    //std::this_thread::sleep_for(std::chrono::seconds(1));
    //std::cout<<"done sleeping"<<std::endl;
}

//-----------------------------------------------------------------------------
VideoSourceVLC::~VideoSourceVLC()
{
    /* Stop playing */
    libvlc_media_player_stop( this->_vlc_mp );

    /* Free the media_player */
    if( _vlc_mp ) {
        libvlc_media_player_release( this->_vlc_mp );
    }

    // free engine
    if ( _vlc_inst )
        libvlc_release( this->_vlc_inst );
}

//-----------------------------------------------------------------------------
bool VideoSourceVLC::get_frame_dimensions( int & width, int & height )
{
    ///\todo mutex
    if( this->m_pixWidth==0 || this->m_pixHeight==0 ) {
        //std::cerr<<"Size not set yet"<<std::endl;
        return false;
    }
    width = this->m_pixWidth;
    height = this->m_pixHeight;
    return true;
}

//-----------------------------------------------------------------------------
bool VideoSourceVLC::get_frame( VideoFrame_BGRA & frame )
{
    ///\todo mutex

    if( this->m_pixWidth==0 || this->m_pixHeight==0 || !this->m_videoBuffer ) {
        //std::cerr<<"Size not set yet in VideoSourceVLC::get_next_frame"<<std::endl;
        return false;
    }

    //std::cout<<"m_pixWidth: "<<m_pixWidth<<std::endl;
    //std::cout<<"m_pixHeight: "<<m_pixHeight<<std::endl;
    //std::cout<<"m_size: "<<m_size<<std::endl;

    //Allocate and fill the image
    if( this->m_pixWidth*this->m_pixHeight*4 == this->m_size ) {
        frame = VideoFrame_BGRA(this->m_videoBuffer, this->m_pixWidth, this->m_pixHeight);
    }
    else
    {
        throw std::runtime_error("get_next_frame not implemented for padded images");
    }

    //std::cout<<"VideoSourceVLC::get_next_frame"<<std::endl;
    //throw std::runtime_error("get_next_frame to be implemented");
    return true;
}

bool get_frame(VideoFrame_I420 & frame)
{
    // TODO
    throw gg::VideoSourceError("get_frame(VideoFrame_I420 & frame) not implemented for VLC");
}

//-----------------------------------------------------------------------------
double VideoSourceVLC::get_frame_rate()
{
    //return libvlc_media_player_get_rate( m_mp );
    return libvlc_media_player_get_fps( this->_vlc_mp );
    //throw std::runtime_error("get_frame_rate to be implemented");
    //return 0.0;
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::set_sub_frame( int x, int y, int width, int height )
{
    throw std::runtime_error("set_sub_frame not implemented");
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::mInitSource( const char * path )
{
    try {
        // VLC pointers
        libvlc_media_t    *media;

        // VLC options
        char smem_options[512];

        sprintf( smem_options, "#transcode{vcodec=BGRA}:smem{video-data=%lld,video-prerender-callback=%lld,video-postrender-callback=%lld}",
                 // We are using transcode because smem only support raw audio and video formats
                 (long long int)(intptr_t)(void*) this,                               // we pass the pointer of the current object to the static callbacks
                 (long long int)(intptr_t)(void*) &VideoSourceVLC::prepareRender,  // pointer to the 1st callback called by VLC (static)
                 (long long int)(intptr_t)(void*) &VideoSourceVLC::handleStream ); // pointer to the 2nd callback called by VLC (static)

        const char * const vlc_args[] = {
            "-I", "dummy",        // Don't use any interface
            "--ignore-config",    // Don't use VLC's config
            "--extraintf=logger", // Log anything
            //"--verbose=2", // Be much more verbose then normal for debugging purpose
            //"--clock-jitter=0",
            //"--file-caching=150",
            "--no-audio",
            "--sout", smem_options    // Stream to memory
        };

        // We launch VLC
        _vlc_inst = libvlc_new( sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args );

        // If path contains a colon (:), it will be treated as a
        // URL. Else, it will be considered as a local path.
        if( std::string(path).find(":") == std::string::npos ) {
            //std::cout<<"opening file "<<path<<std::endl;
            media = libvlc_media_new_path( _vlc_inst, path );
        }
        else {
            //std::cout<<"opening url "<<path<<std::endl;
            media = libvlc_media_new_location( _vlc_inst, path );
        }

        libvlc_media_add_option( media, ":noaudio" );
        libvlc_media_add_option( media, ":no-video-title-show" );

        // Create a media player playing environement
        _vlc_mp = libvlc_media_player_new_from_media( media );
        // No need to keep the media now
        libvlc_media_release( media );

        //std::cout<<"Media open: "<<path<<std::endl;
    }
    catch( ... ) {
        throw std::runtime_error( std::string("Init device failed for the path ").append( path ) );
    }
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::mRunSource()
{
    try {
        // play the media_player
        libvlc_media_player_play( _vlc_mp );
        //std::cout<<"Media playing"<<std::endl;
        return;
    }
    catch( ... )
    {
        throw std::runtime_error("Error while running source");
        //std::cerr<<"Error while running source"<<std::endl;
        //return;
    }
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::prepareRender( VideoSourceVLC* p_video_data, uint8_t** pp_pixel_buffer, int size )
{
    ///\todo create mutex guard
    //std::cout<<"VideoSourceVLC::prepareRender"<<std::endl;
    // called before video rendered
    // p_video_data is the echo of the "this" pointer
    if( size != p_video_data->m_size ) {
        p_video_data->m_videoBuffer = new uint8_t[size];
        p_video_data->m_size = size;
        unsigned int width,height;
        libvlc_video_get_size( p_video_data->_vlc_mp, 0, &width, &height );
        p_video_data->m_pixWidth = width;
        p_video_data->m_pixHeight = height;
    }

    *pp_pixel_buffer = p_video_data->m_videoBuffer;
}

//-----------------------------------------------------------------------------
void VideoSourceVLC::handleStream( VideoSourceVLC* /*p_video_data*/, uint8_t* /*p_pixel_buffer*/, int /*width*/, int /*height*/,
                                   int /*pixel_pitch*/, int /*size*/, int64_t /*pts*/ )
{
    ///\todo create mutex guard
    //std::cout<<"VideoSourceVLC::handleStream"<<std::endl;
    //std::cout<<"pixel_pitch"<<pixel_pitch<<std::endl;
    //std::cout<<"size"<<size<<std::endl;
    //std::cout<<"pts"<<pts<<std::endl;
    // called after video rendered
    // p_video_data is the echo of the "this" pointer
    //p_video_data->mReadRGBFrame( p_video_data->m_videoBuffer );
    //p_video_data->m_pixWidth = width;
    //p_video_data->m_pixHeight = height;
}

}
<|endoftext|>