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

#include "chrome/browser/translate/translate_infobar_delegate2.h"

#include <algorithm>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/translate/translate_manager2.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// static
TranslateInfoBarDelegate2* TranslateInfoBarDelegate2::CreateDelegate(
    Type type,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language) {
  DCHECK(type != kTranslationError);
  if (!TranslateManager2::IsSupportedLanguage(original_language) ||
      !TranslateManager2::IsSupportedLanguage(target_language)) {
    return NULL;
  }
  TranslateInfoBarDelegate2* delegate =
      new TranslateInfoBarDelegate2(type, TranslateErrors::NONE,
                                    tab_contents,
                                    original_language, target_language);
  DCHECK(delegate->original_language_index() != -1);
  DCHECK(delegate->target_language_index() != -1);
  return delegate;
}

TranslateInfoBarDelegate2* TranslateInfoBarDelegate2::CreateErrorDelegate(
    TranslateErrors::Type error,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language) {
  return new TranslateInfoBarDelegate2(kTranslationError, error, tab_contents,
                                       original_language, target_language);
}

TranslateInfoBarDelegate2::TranslateInfoBarDelegate2(
    Type type,
    TranslateErrors::Type error,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language)
    : InfoBarDelegate(tab_contents),
      type_(type),
      background_animation_(kNone),
      tab_contents_(tab_contents),
      original_language_index_(-1),
      target_language_index_(-1),
      error_(error),
      infobar_view_(NULL),
      prefs_(tab_contents_->profile()->GetPrefs()) {
  DCHECK((type_ != kTranslationError && error == TranslateErrors::NONE) ||
         (type_ == kTranslationError && error != TranslateErrors::NONE));

  std::vector<std::string> language_codes;
  TranslateManager2::GetSupportedLanguages(&language_codes);

  languages_.reserve(language_codes.size());
  for (std::vector<std::string>::const_iterator iter = language_codes.begin();
       iter != language_codes.end(); ++iter) {
    std::string language_code = *iter;

    string16 language_name = GetLanguageDisplayableName(language_code);
    // Insert the language in languages_ in alphabetical order.
    std::vector<LanguageNamePair>::iterator iter2;
    for (iter2 = languages_.begin(); iter2 != languages_.end(); ++iter2) {
      if (language_name.compare(iter2->second) < 0)
        break;
    }
    languages_.insert(iter2, LanguageNamePair(language_code, language_name));
  }
  for (std::vector<LanguageNamePair>::const_iterator iter = languages_.begin();
       iter != languages_.end(); ++iter) {
    std::string language_code = iter->first;
    if (language_code == original_language)
      original_language_index_ = iter - languages_.begin();
    if (language_code == target_language)
      target_language_index_ = iter - languages_.begin();
  }
}

int TranslateInfoBarDelegate2::GetLanguageCount() const {
  return static_cast<int>(languages_.size());
}

std::string TranslateInfoBarDelegate2::GetLanguageCodeAt(
    int index) const {
  DCHECK(index >=0 && index < GetLanguageCount());
  return languages_[index].first;
}

string16 TranslateInfoBarDelegate2::GetLanguageDisplayableNameAt(
    int index) const {
  DCHECK(index >=0 && index < GetLanguageCount());
  return languages_[index].second;
}

std::string TranslateInfoBarDelegate2::GetOriginalLanguageCode() const {
  return GetLanguageCodeAt(original_language_index());
}

std::string TranslateInfoBarDelegate2::GetTargetLanguageCode() const {
  return GetLanguageCodeAt(target_language_index());
}

void TranslateInfoBarDelegate2::SetOriginalLanguage(int language_index) {
  DCHECK(language_index < static_cast<int>(languages_.size()));
  original_language_index_ = language_index;
  if (infobar_view_)
    infobar_view_->OriginalLanguageChanged();
  if (type_ == kAfterTranslate)
    Translate();
}

void TranslateInfoBarDelegate2::SetTargetLanguage(int language_index) {
  DCHECK(language_index < static_cast<int>(languages_.size()));
  target_language_index_ = language_index;
  if (infobar_view_)
    infobar_view_->TargetLanguageChanged();
  if (type_ == kAfterTranslate)
    Translate();
}

bool TranslateInfoBarDelegate2::IsError() {
  return type_ == kTranslationError;
}

void TranslateInfoBarDelegate2::Translate() {
  const std::string& original_language_code = GetOriginalLanguageCode();
  prefs_.ResetTranslationDeniedCount(original_language_code);
  prefs_.IncrementTranslationAcceptedCount(original_language_code);

  Singleton<TranslateManager2>::get()->TranslatePage(
      tab_contents_,
      GetLanguageCodeAt(original_language_index()),
      GetLanguageCodeAt(target_language_index()));
}

void TranslateInfoBarDelegate2::RevertTranslation() {
  Singleton<TranslateManager2>::get()->RevertTranslation(tab_contents_);
  tab_contents_->RemoveInfoBar(this);
}

void TranslateInfoBarDelegate2::TranslationDeclined() {
  const std::string& original_language_code = GetOriginalLanguageCode();
  prefs_.ResetTranslationAcceptedCount(original_language_code);
  prefs_.IncrementTranslationDeniedCount(original_language_code);

  // Remember that the user declined the translation so as to prevent showing a
  // translate infobar for that page again.  (TranslateManager initiates
  // translations when getting a LANGUAGE_DETERMINED from the page, which
  // happens when a load stops. That could happen multiple times, including
  // after the user already declined the translation.)
  tab_contents_->language_state().set_translation_declined(true);
}

void TranslateInfoBarDelegate2::InfoBarDismissed() {
  if (type_ != kBeforeTranslate)
    return;

  // The user closed the infobar without clicking the translate button.
  TranslationDeclined();
  UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslateCloseInfobar", 1);
}

void TranslateInfoBarDelegate2::InfoBarClosed() {
  delete this;
}

SkBitmap* TranslateInfoBarDelegate2::GetIcon() const {
  return ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFOBAR_TRANSLATE);
}

InfoBarDelegate::Type TranslateInfoBarDelegate2::GetInfoBarType() {
  return InfoBarDelegate::PAGE_ACTION_TYPE;
}

bool TranslateInfoBarDelegate2::IsLanguageBlacklisted() {
  return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode());
}

void TranslateInfoBarDelegate2::ToggleLanguageBlacklist() {
  const std::string& original_lang = GetOriginalLanguageCode();
  if (prefs_.IsLanguageBlacklisted(original_lang)) {
    prefs_.RemoveLanguageFromBlacklist(original_lang);
  } else {
    prefs_.BlacklistLanguage(original_lang);
    tab_contents_->RemoveInfoBar(this);
  }
}

bool TranslateInfoBarDelegate2::IsSiteBlacklisted() {
  std::string host = GetPageHost();
  return !host.empty() && prefs_.IsSiteBlacklisted(host);
}

void TranslateInfoBarDelegate2::ToggleSiteBlacklist() {
  std::string host = GetPageHost();
  if (host.empty())
    return;

  if (prefs_.IsSiteBlacklisted(host)) {
    prefs_.RemoveSiteFromBlacklist(host);
  } else {
    prefs_.BlacklistSite(host);
    tab_contents_->RemoveInfoBar(this);
  }
}

bool TranslateInfoBarDelegate2::ShouldAlwaysTranslate() {
  return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(),
                                          GetTargetLanguageCode());
}

void TranslateInfoBarDelegate2::ToggleAlwaysTranslate() {
  const std::string& original_lang = GetOriginalLanguageCode();
  const std::string& target_lang = GetTargetLanguageCode();
  if (prefs_.IsLanguagePairWhitelisted(original_lang, target_lang))
    prefs_.RemoveLanguagePairFromWhitelist(original_lang, target_lang);
  else
    prefs_.WhitelistLanguagePair(original_lang, target_lang);
}

void TranslateInfoBarDelegate2::AlwaysTranslatePageLanguage() {
  const std::string& original_lang = GetOriginalLanguageCode();
  const std::string& target_lang = GetTargetLanguageCode();
  DCHECK(!prefs_.IsLanguagePairWhitelisted(original_lang, target_lang));
  prefs_.WhitelistLanguagePair(original_lang, target_lang);
  Translate();
}

void TranslateInfoBarDelegate2::NeverTranslatePageLanguage() {
  std::string original_lang = GetOriginalLanguageCode();
  DCHECK(!prefs_.IsLanguageBlacklisted(original_lang));
  prefs_.BlacklistLanguage(original_lang);
  tab_contents_->RemoveInfoBar(this);
}

string16 TranslateInfoBarDelegate2::GetMessageInfoBarText() {
  switch (type_) {
    case kTranslating:
      return l10n_util::GetStringFUTF16(
          IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
          GetLanguageDisplayableNameAt(target_language_index_));
    case kTranslationError:
      switch (error_) {
        case TranslateErrors::NETWORK:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
        case TranslateErrors::INITIALIZATION_ERROR:
        case TranslateErrors::TRANSLATION_ERROR:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
        case TranslateErrors::UNKNOWN_LANGUAGE:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
        case TranslateErrors::IDENTICAL_LANGUAGES:
          return l10n_util::GetStringFUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
              GetLanguageDisplayableNameAt(target_language_index_));
        default:
          NOTREACHED();
          return string16();
      }
    default:
      NOTREACHED();
      return string16();
  }
}

string16 TranslateInfoBarDelegate2::GetMessageInfoBarButtonText() {
  switch (type_) {
    case kTranslating:
      return string16();
    case kTranslationError:
      if (error_ == TranslateErrors::IDENTICAL_LANGUAGES ||
          error_ == TranslateErrors::UNKNOWN_LANGUAGE) {
        // No retry button, we would fail again with the same error.
        return string16();
      }
      return l10n_util::GetStringUTF16(IDS_TRANSLATE_INFOBAR_RETRY);
    default:
      NOTREACHED();
      return string16();
  }
}

void TranslateInfoBarDelegate2::MessageInfoBarButtonPressed() {
  DCHECK(type_ == kTranslationError);
  Singleton<TranslateManager2>::get()->TranslatePage(
      tab_contents_, GetOriginalLanguageCode(), GetTargetLanguageCode());
}

bool TranslateInfoBarDelegate2::ShouldShowNeverTranslateButton() {
  DCHECK(type_ == kBeforeTranslate);
  return prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3;
}

bool TranslateInfoBarDelegate2::ShouldShowAlwaysTranslateButton() {
  DCHECK(type_ == kBeforeTranslate);
  return prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3;
}

void TranslateInfoBarDelegate2::UpdateBackgroundAnimation(
    TranslateInfoBarDelegate2* previous_infobar) {
  if (!previous_infobar || previous_infobar->IsError() == IsError()) {
    background_animation_ = kNone;
    return;
  }
  background_animation_ = IsError() ? kNormalToError: kErrorToNormal;
}

std::string TranslateInfoBarDelegate2::GetPageHost() {
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  return entry ? entry->url().HostNoBrackets() : std::string();
}

// static
string16 TranslateInfoBarDelegate2::GetLanguageDisplayableName(
    const std::string& language_code) {
  return l10n_util::GetDisplayNameForLocale(
      language_code, g_browser_process->GetApplicationLocale(), true);
}

// static
void TranslateInfoBarDelegate2::GetAfterTranslateStrings(
    std::vector<string16>* strings, bool* swap_languages) {
  DCHECK(strings);
  DCHECK(swap_languages);

  std::vector<size_t> offsets;
  string16 text =
      l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE,
                                 string16(), string16(), &offsets);
  DCHECK(offsets.size() == 2U);

  if (offsets[0] > offsets[1]) {
    // Target language comes before source.
    std::swap(offsets[0], offsets[1]);
    *swap_languages = true;
  } else {
    *swap_languages = false;
  }

  strings->push_back(text.substr(0, offsets[0]));
  strings->push_back(text.substr(offsets[0], offsets[1]));
  strings->push_back(text.substr(offsets[1]));
}
<commit_msg>The text in the after translate infobar was incorrect due to an incorrect usage of the std::string substr() API.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/translate/translate_infobar_delegate2.h"

#include <algorithm>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/translate/translate_manager2.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// static
TranslateInfoBarDelegate2* TranslateInfoBarDelegate2::CreateDelegate(
    Type type,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language) {
  DCHECK(type != kTranslationError);
  if (!TranslateManager2::IsSupportedLanguage(original_language) ||
      !TranslateManager2::IsSupportedLanguage(target_language)) {
    return NULL;
  }
  TranslateInfoBarDelegate2* delegate =
      new TranslateInfoBarDelegate2(type, TranslateErrors::NONE,
                                    tab_contents,
                                    original_language, target_language);
  DCHECK(delegate->original_language_index() != -1);
  DCHECK(delegate->target_language_index() != -1);
  return delegate;
}

TranslateInfoBarDelegate2* TranslateInfoBarDelegate2::CreateErrorDelegate(
    TranslateErrors::Type error,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language) {
  return new TranslateInfoBarDelegate2(kTranslationError, error, tab_contents,
                                       original_language, target_language);
}

TranslateInfoBarDelegate2::TranslateInfoBarDelegate2(
    Type type,
    TranslateErrors::Type error,
    TabContents* tab_contents,
    const std::string& original_language,
    const std::string& target_language)
    : InfoBarDelegate(tab_contents),
      type_(type),
      background_animation_(kNone),
      tab_contents_(tab_contents),
      original_language_index_(-1),
      target_language_index_(-1),
      error_(error),
      infobar_view_(NULL),
      prefs_(tab_contents_->profile()->GetPrefs()) {
  DCHECK((type_ != kTranslationError && error == TranslateErrors::NONE) ||
         (type_ == kTranslationError && error != TranslateErrors::NONE));

  std::vector<std::string> language_codes;
  TranslateManager2::GetSupportedLanguages(&language_codes);

  languages_.reserve(language_codes.size());
  for (std::vector<std::string>::const_iterator iter = language_codes.begin();
       iter != language_codes.end(); ++iter) {
    std::string language_code = *iter;

    string16 language_name = GetLanguageDisplayableName(language_code);
    // Insert the language in languages_ in alphabetical order.
    std::vector<LanguageNamePair>::iterator iter2;
    for (iter2 = languages_.begin(); iter2 != languages_.end(); ++iter2) {
      if (language_name.compare(iter2->second) < 0)
        break;
    }
    languages_.insert(iter2, LanguageNamePair(language_code, language_name));
  }
  for (std::vector<LanguageNamePair>::const_iterator iter = languages_.begin();
       iter != languages_.end(); ++iter) {
    std::string language_code = iter->first;
    if (language_code == original_language)
      original_language_index_ = iter - languages_.begin();
    if (language_code == target_language)
      target_language_index_ = iter - languages_.begin();
  }
}

int TranslateInfoBarDelegate2::GetLanguageCount() const {
  return static_cast<int>(languages_.size());
}

std::string TranslateInfoBarDelegate2::GetLanguageCodeAt(
    int index) const {
  DCHECK(index >=0 && index < GetLanguageCount());
  return languages_[index].first;
}

string16 TranslateInfoBarDelegate2::GetLanguageDisplayableNameAt(
    int index) const {
  DCHECK(index >=0 && index < GetLanguageCount());
  return languages_[index].second;
}

std::string TranslateInfoBarDelegate2::GetOriginalLanguageCode() const {
  return GetLanguageCodeAt(original_language_index());
}

std::string TranslateInfoBarDelegate2::GetTargetLanguageCode() const {
  return GetLanguageCodeAt(target_language_index());
}

void TranslateInfoBarDelegate2::SetOriginalLanguage(int language_index) {
  DCHECK(language_index < static_cast<int>(languages_.size()));
  original_language_index_ = language_index;
  if (infobar_view_)
    infobar_view_->OriginalLanguageChanged();
  if (type_ == kAfterTranslate)
    Translate();
}

void TranslateInfoBarDelegate2::SetTargetLanguage(int language_index) {
  DCHECK(language_index < static_cast<int>(languages_.size()));
  target_language_index_ = language_index;
  if (infobar_view_)
    infobar_view_->TargetLanguageChanged();
  if (type_ == kAfterTranslate)
    Translate();
}

bool TranslateInfoBarDelegate2::IsError() {
  return type_ == kTranslationError;
}

void TranslateInfoBarDelegate2::Translate() {
  const std::string& original_language_code = GetOriginalLanguageCode();
  prefs_.ResetTranslationDeniedCount(original_language_code);
  prefs_.IncrementTranslationAcceptedCount(original_language_code);

  Singleton<TranslateManager2>::get()->TranslatePage(
      tab_contents_,
      GetLanguageCodeAt(original_language_index()),
      GetLanguageCodeAt(target_language_index()));
}

void TranslateInfoBarDelegate2::RevertTranslation() {
  Singleton<TranslateManager2>::get()->RevertTranslation(tab_contents_);
  tab_contents_->RemoveInfoBar(this);
}

void TranslateInfoBarDelegate2::TranslationDeclined() {
  const std::string& original_language_code = GetOriginalLanguageCode();
  prefs_.ResetTranslationAcceptedCount(original_language_code);
  prefs_.IncrementTranslationDeniedCount(original_language_code);

  // Remember that the user declined the translation so as to prevent showing a
  // translate infobar for that page again.  (TranslateManager initiates
  // translations when getting a LANGUAGE_DETERMINED from the page, which
  // happens when a load stops. That could happen multiple times, including
  // after the user already declined the translation.)
  tab_contents_->language_state().set_translation_declined(true);
}

void TranslateInfoBarDelegate2::InfoBarDismissed() {
  if (type_ != kBeforeTranslate)
    return;

  // The user closed the infobar without clicking the translate button.
  TranslationDeclined();
  UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslateCloseInfobar", 1);
}

void TranslateInfoBarDelegate2::InfoBarClosed() {
  delete this;
}

SkBitmap* TranslateInfoBarDelegate2::GetIcon() const {
  return ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFOBAR_TRANSLATE);
}

InfoBarDelegate::Type TranslateInfoBarDelegate2::GetInfoBarType() {
  return InfoBarDelegate::PAGE_ACTION_TYPE;
}

bool TranslateInfoBarDelegate2::IsLanguageBlacklisted() {
  return prefs_.IsLanguageBlacklisted(GetOriginalLanguageCode());
}

void TranslateInfoBarDelegate2::ToggleLanguageBlacklist() {
  const std::string& original_lang = GetOriginalLanguageCode();
  if (prefs_.IsLanguageBlacklisted(original_lang)) {
    prefs_.RemoveLanguageFromBlacklist(original_lang);
  } else {
    prefs_.BlacklistLanguage(original_lang);
    tab_contents_->RemoveInfoBar(this);
  }
}

bool TranslateInfoBarDelegate2::IsSiteBlacklisted() {
  std::string host = GetPageHost();
  return !host.empty() && prefs_.IsSiteBlacklisted(host);
}

void TranslateInfoBarDelegate2::ToggleSiteBlacklist() {
  std::string host = GetPageHost();
  if (host.empty())
    return;

  if (prefs_.IsSiteBlacklisted(host)) {
    prefs_.RemoveSiteFromBlacklist(host);
  } else {
    prefs_.BlacklistSite(host);
    tab_contents_->RemoveInfoBar(this);
  }
}

bool TranslateInfoBarDelegate2::ShouldAlwaysTranslate() {
  return prefs_.IsLanguagePairWhitelisted(GetOriginalLanguageCode(),
                                          GetTargetLanguageCode());
}

void TranslateInfoBarDelegate2::ToggleAlwaysTranslate() {
  const std::string& original_lang = GetOriginalLanguageCode();
  const std::string& target_lang = GetTargetLanguageCode();
  if (prefs_.IsLanguagePairWhitelisted(original_lang, target_lang))
    prefs_.RemoveLanguagePairFromWhitelist(original_lang, target_lang);
  else
    prefs_.WhitelistLanguagePair(original_lang, target_lang);
}

void TranslateInfoBarDelegate2::AlwaysTranslatePageLanguage() {
  const std::string& original_lang = GetOriginalLanguageCode();
  const std::string& target_lang = GetTargetLanguageCode();
  DCHECK(!prefs_.IsLanguagePairWhitelisted(original_lang, target_lang));
  prefs_.WhitelistLanguagePair(original_lang, target_lang);
  Translate();
}

void TranslateInfoBarDelegate2::NeverTranslatePageLanguage() {
  std::string original_lang = GetOriginalLanguageCode();
  DCHECK(!prefs_.IsLanguageBlacklisted(original_lang));
  prefs_.BlacklistLanguage(original_lang);
  tab_contents_->RemoveInfoBar(this);
}

string16 TranslateInfoBarDelegate2::GetMessageInfoBarText() {
  switch (type_) {
    case kTranslating:
      return l10n_util::GetStringFUTF16(
          IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
          GetLanguageDisplayableNameAt(target_language_index_));
    case kTranslationError:
      switch (error_) {
        case TranslateErrors::NETWORK:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
        case TranslateErrors::INITIALIZATION_ERROR:
        case TranslateErrors::TRANSLATION_ERROR:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
        case TranslateErrors::UNKNOWN_LANGUAGE:
          return l10n_util::GetStringUTF16(
              IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
        case TranslateErrors::IDENTICAL_LANGUAGES:
          return l10n_util::GetStringFUTF16(
              IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
              GetLanguageDisplayableNameAt(target_language_index_));
        default:
          NOTREACHED();
          return string16();
      }
    default:
      NOTREACHED();
      return string16();
  }
}

string16 TranslateInfoBarDelegate2::GetMessageInfoBarButtonText() {
  switch (type_) {
    case kTranslating:
      return string16();
    case kTranslationError:
      if (error_ == TranslateErrors::IDENTICAL_LANGUAGES ||
          error_ == TranslateErrors::UNKNOWN_LANGUAGE) {
        // No retry button, we would fail again with the same error.
        return string16();
      }
      return l10n_util::GetStringUTF16(IDS_TRANSLATE_INFOBAR_RETRY);
    default:
      NOTREACHED();
      return string16();
  }
}

void TranslateInfoBarDelegate2::MessageInfoBarButtonPressed() {
  DCHECK(type_ == kTranslationError);
  Singleton<TranslateManager2>::get()->TranslatePage(
      tab_contents_, GetOriginalLanguageCode(), GetTargetLanguageCode());
}

bool TranslateInfoBarDelegate2::ShouldShowNeverTranslateButton() {
  DCHECK(type_ == kBeforeTranslate);
  return prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3;
}

bool TranslateInfoBarDelegate2::ShouldShowAlwaysTranslateButton() {
  DCHECK(type_ == kBeforeTranslate);
  return prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3;
}

void TranslateInfoBarDelegate2::UpdateBackgroundAnimation(
    TranslateInfoBarDelegate2* previous_infobar) {
  if (!previous_infobar || previous_infobar->IsError() == IsError()) {
    background_animation_ = kNone;
    return;
  }
  background_animation_ = IsError() ? kNormalToError: kErrorToNormal;
}

std::string TranslateInfoBarDelegate2::GetPageHost() {
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  return entry ? entry->url().HostNoBrackets() : std::string();
}

// static
string16 TranslateInfoBarDelegate2::GetLanguageDisplayableName(
    const std::string& language_code) {
  return l10n_util::GetDisplayNameForLocale(
      language_code, g_browser_process->GetApplicationLocale(), true);
}

// static
void TranslateInfoBarDelegate2::GetAfterTranslateStrings(
    std::vector<string16>* strings, bool* swap_languages) {
  DCHECK(strings);
  DCHECK(swap_languages);

  std::vector<size_t> offsets;
  string16 text =
      l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE,
                                 string16(), string16(), &offsets);
  DCHECK(offsets.size() == 2U);

  if (offsets[0] > offsets[1]) {
    // Target language comes before source.
    std::swap(offsets[0], offsets[1]);
    *swap_languages = true;
  } else {
    *swap_languages = false;
  }

  strings->push_back(text.substr(0, offsets[0]));
  strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0]));
  strings->push_back(text.substr(offsets[1]));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: launcher.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2007-07-17 07:28:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "launcher.hxx"

#ifndef _WINDOWS_
#   define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#   include <windows.h>
#   include <shellapi.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
#endif

#include <stdlib.h>
#include <malloc.h>

#ifdef __MINGW32__
extern "C" int APIENTRY WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
#else
extern "C" int APIENTRY _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int )
#endif
{
    // Retreive startup info

    STARTUPINFO aStartupInfo;

    ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
    aStartupInfo.cb = sizeof( aStartupInfo );
    GetStartupInfo( &aStartupInfo );

    // Retrieve command line

    LPTSTR  lpCommandLine = GetCommandLine();

    LPTSTR  *ppArguments = NULL;
    int     nArguments = 0;

    ppArguments = GetArgv( &nArguments );

    // if ( 1 == nArguments )
    {
        lpCommandLine = (LPTSTR)_alloca( sizeof(_TCHAR) * (_tcslen(lpCommandLine) + _tcslen(APPLICATION_SWITCH) + 2) );

        _tcscpy( lpCommandLine, GetCommandLine() );
        _tcscat( lpCommandLine, _T(" ") );
        _tcscat( lpCommandLine, APPLICATION_SWITCH );
    }

    // Calculate application name

    TCHAR   szApplicationName[MAX_PATH];
    TCHAR   szDrive[MAX_PATH];
    TCHAR   szDir[MAX_PATH];
    TCHAR   szFileName[MAX_PATH];
    TCHAR   szExt[MAX_PATH];

    GetModuleFileName( NULL, szApplicationName, MAX_PATH );
    _tsplitpath( szApplicationName, szDrive, szDir, szFileName, szExt );
    _tmakepath( szApplicationName, szDrive, szDir, OFFICE_IMAGE_NAME, _T(".exe") );

    PROCESS_INFORMATION aProcessInfo;

    BOOL    fSuccess = CreateProcess(
        szApplicationName,
        lpCommandLine,
        NULL,
        NULL,
        TRUE,
        0,
        NULL,
        NULL,
        &aStartupInfo,
        &aProcessInfo );

    if ( fSuccess )
    {
        CloseHandle( aProcessInfo.hProcess );
        CloseHandle( aProcessInfo.hThread );

        return 0;
    }

    DWORD   dwError = GetLastError();

    LPVOID lpMsgBuf;

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dwError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR)&lpMsgBuf,
        0,
        NULL
    );

    // Display the string.
    MessageBox( NULL, (LPCTSTR)lpMsgBuf, NULL, MB_OK | MB_ICONERROR );

    // Free the buffer.
    LocalFree( lpMsgBuf );

    return GetLastError();
}

<commit_msg>INTEGRATION: CWS changefileheader (1.8.192); FILE MERGED 2008/03/28 15:27:17 rt 1.8.192.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: launcher.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "launcher.hxx"

#ifndef _WINDOWS_
#   define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#   include <windows.h>
#   include <shellapi.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
#endif

#include <stdlib.h>
#include <malloc.h>

#ifdef __MINGW32__
extern "C" int APIENTRY WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
#else
extern "C" int APIENTRY _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int )
#endif
{
    // Retreive startup info

    STARTUPINFO aStartupInfo;

    ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
    aStartupInfo.cb = sizeof( aStartupInfo );
    GetStartupInfo( &aStartupInfo );

    // Retrieve command line

    LPTSTR  lpCommandLine = GetCommandLine();

    LPTSTR  *ppArguments = NULL;
    int     nArguments = 0;

    ppArguments = GetArgv( &nArguments );

    // if ( 1 == nArguments )
    {
        lpCommandLine = (LPTSTR)_alloca( sizeof(_TCHAR) * (_tcslen(lpCommandLine) + _tcslen(APPLICATION_SWITCH) + 2) );

        _tcscpy( lpCommandLine, GetCommandLine() );
        _tcscat( lpCommandLine, _T(" ") );
        _tcscat( lpCommandLine, APPLICATION_SWITCH );
    }

    // Calculate application name

    TCHAR   szApplicationName[MAX_PATH];
    TCHAR   szDrive[MAX_PATH];
    TCHAR   szDir[MAX_PATH];
    TCHAR   szFileName[MAX_PATH];
    TCHAR   szExt[MAX_PATH];

    GetModuleFileName( NULL, szApplicationName, MAX_PATH );
    _tsplitpath( szApplicationName, szDrive, szDir, szFileName, szExt );
    _tmakepath( szApplicationName, szDrive, szDir, OFFICE_IMAGE_NAME, _T(".exe") );

    PROCESS_INFORMATION aProcessInfo;

    BOOL    fSuccess = CreateProcess(
        szApplicationName,
        lpCommandLine,
        NULL,
        NULL,
        TRUE,
        0,
        NULL,
        NULL,
        &aStartupInfo,
        &aProcessInfo );

    if ( fSuccess )
    {
        CloseHandle( aProcessInfo.hProcess );
        CloseHandle( aProcessInfo.hThread );

        return 0;
    }

    DWORD   dwError = GetLastError();

    LPVOID lpMsgBuf;

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dwError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR)&lpMsgBuf,
        0,
        NULL
    );

    // Display the string.
    MessageBox( NULL, (LPCTSTR)lpMsgBuf, NULL, MB_OK | MB_ICONERROR );

    // Free the buffer.
    LocalFree( lpMsgBuf );

    return GetLastError();
}

<|endoftext|>


<commit_before>
#ifndef PHP_MUSTACHE_PRIVATE_HPP
#define PHP_MUSTACHE_PRIVATE_HPP

//#include <stdint.h>

//#include <algorithm>
//#include <exception>
//#include <stdexcept>
//#include <string>

#include "mustache/mustache.hpp"

#endif /* PHP_MUSTACHE_PRIVATE_HPP */

<commit_msg>Work around PHP8 compat issue<commit_after>
#ifndef PHP_MUSTACHE_PRIVATE_HPP
#define PHP_MUSTACHE_PRIVATE_HPP

//#include <stdint.h>

//#include <algorithm>
//#include <exception>
//#include <stdexcept>
//#include <string>

#include "mustache/mustache.hpp"

// Related?: https://github.com/php/php-src/commit/43a7d95016761787cace63fb52e93e27e123d0cc
#ifndef ZEND_ACC_CTOR
#define ZEND_ACC_CTOR 0
#endif

#endif /* PHP_MUSTACHE_PRIVATE_HPP */

<|endoftext|>


<commit_before>/*

Copyright (c) 2008, 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 <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/create_torrent.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name
	, bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (peer_disconnected_alert* p = dynamic_cast<peer_disconnected_alert*>(a.get()))
		{
			std::cerr << name << "(" << p->ip << "): " << p->message() << "\n";
		}
		else if (a->message() != "block downloading"
			&& a->message() != "block finished"
			&& a->message() != "piece finished")
		{
			std::cerr << name << ": " << a->message() << "\n";
		}
		TEST_CHECK(dynamic_cast<fastresume_rejected_alert*>(a.get()) == 0 || allow_failed_fastresume);

		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->message() == "connecting to peer"
			|| a->message() == "closing connection to ourself"
			|| a->message() == "duplicate connection"
			|| a->message() == "duplicate peer-id, connection closed"
			|| (allow_disconnects && a->message() == "Broken pipe")
			|| (allow_disconnects && a->message() == "Connection reset by peer")
			|| (allow_disconnects && a->message() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port, bool ssl)
{
	stop_web_server(port);

	if (ssl)
	{
		system("echo . > tmp");
		system("echo test province >>tmp");
		system("echo test city >> tmp");
		system("echo test company >> tmp");
		system("echo test department >> tmp");
		system("echo tester >> tmp");
		system("echo test@test.com >> tmp");
		system("openssl req -new -x509 -keyout server.pem -out server.pem "
			"-days 365 -nodes <tmp");
	}

	std::ofstream f("lighty_config");
	f << "server.modules = (\"mod_access\", \"mod_redirect\", \"mod_setenv\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n"
		"url.redirect = ("
			"\"^/redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\""
			", \"^/infinite_redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\""
			", \"^/relative/redirect$\" => \"../test_file\""
			")\n"
		"$HTTP[\"url\"] == \"/test_file.gz\" {\n"
		"    setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
		"#    mimetype.assign = ()\n"
		"}\n";
	// this requires lighttpd to be built with ssl support.
	// The port distribution for mac is not built with ssl
	// support by default.
	if (ssl)
		f << "ssl.engine = \"enable\"\n"
			"ssl.pemfile = \"server.pem\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com "
		"PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
	test_sleep(1000);
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size, int num_pieces)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	file_storage fs;
	int total_size = piece_size * num_pieces;
	fs.add_file(path("temporary"), total_size);
	libtorrent::create_torrent t(fs, piece_size);
	t.add_tracker(tracker_url);

	std::vector<char> piece(piece_size);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t.num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t.set_hash(i, ph);

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	std::vector<char> tmp;
	std::back_insert_iterator<std::vector<char> > out(tmp);
	bencode(out, t.generate());
	return boost::intrusive_ptr<torrent_info>(new torrent_info(&tmp[0], tmp.size()));
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix, int piece_size
	, boost::intrusive_ptr<torrent_info>* torrent)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	boost::intrusive_ptr<torrent_info> t;
	if (torrent == 0)
	{
		create_directory("./tmp1" + suffix);
		std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
		t = ::create_torrent(&file, piece_size, 1024 / 8);
		file.close();
		if (clear_files)
		{
			remove_all("./tmp2" + suffix + "/temporary");
			remove_all("./tmp3" + suffix + "/temporary");
		}
		std::cerr << "generated torrent: " << t->info_hash() << std::endl;
	}
	else
	{
		t = *torrent;
	}

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<commit_msg>fixed setup transfer for the test<commit_after>/*

Copyright (c) 2008, 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 <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/create_torrent.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name
	, bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (peer_disconnected_alert* p = dynamic_cast<peer_disconnected_alert*>(a.get()))
		{
			std::cerr << name << "(" << p->ip << "): " << p->message() << "\n";
		}
		else if (a->message() != "block downloading"
			&& a->message() != "block finished"
			&& a->message() != "piece finished")
		{
			std::cerr << name << ": " << a->message() << "\n";
		}
		TEST_CHECK(dynamic_cast<fastresume_rejected_alert*>(a.get()) == 0 || allow_failed_fastresume);

		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->message() == "connecting to peer"
			|| a->message() == "closing connection to ourself"
			|| a->message() == "duplicate connection"
			|| a->message() == "duplicate peer-id, connection closed"
			|| (allow_disconnects && a->message() == "Broken pipe")
			|| (allow_disconnects && a->message() == "Connection reset by peer")
			|| (allow_disconnects && a->message() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port, bool ssl)
{
	stop_web_server(port);

	if (ssl)
	{
		system("echo . > tmp");
		system("echo test province >>tmp");
		system("echo test city >> tmp");
		system("echo test company >> tmp");
		system("echo test department >> tmp");
		system("echo tester >> tmp");
		system("echo test@test.com >> tmp");
		system("openssl req -new -x509 -keyout server.pem -out server.pem "
			"-days 365 -nodes <tmp");
	}

	std::ofstream f("lighty_config");
	f << "server.modules = (\"mod_access\", \"mod_redirect\", \"mod_setenv\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n"
		"url.redirect = ("
			"\"^/redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\""
			", \"^/infinite_redirect$\" => \"" << (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\""
			", \"^/relative/redirect$\" => \"../test_file\""
			")\n"
		"$HTTP[\"url\"] == \"/test_file.gz\" {\n"
		"    setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
		"#    mimetype.assign = ()\n"
		"}\n";
	// this requires lighttpd to be built with ssl support.
	// The port distribution for mac is not built with ssl
	// support by default.
	if (ssl)
		f << "ssl.engine = \"enable\"\n"
			"ssl.pemfile = \"server.pem\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com "
		"PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
	test_sleep(1000);
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size, int num_pieces)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	file_storage fs;
	int total_size = piece_size * num_pieces;
	fs.add_file(path("temporary"), total_size);
	libtorrent::create_torrent t(fs, piece_size);
	t.add_tracker(tracker_url);

	std::vector<char> piece(piece_size);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t.num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t.set_hash(i, ph);

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	std::vector<char> tmp;
	std::back_insert_iterator<std::vector<char> > out(tmp);
	bencode(out, t.generate());
	return boost::intrusive_ptr<torrent_info>(new torrent_info(&tmp[0], tmp.size()));
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix, int piece_size
	, boost::intrusive_ptr<torrent_info>* torrent)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	std::srand(time(0));
	peer_id pid;
	std::generate(&pid[0], &pid[0] + 20, std::rand);
	ses1->set_peer_id(pid);
	std::generate(&pid[0], &pid[0] + 20, std::rand);
	ses2->set_peer_id(pid);
	assert(ses1->id() != ses2->id());
	if (ses3)
	{
		std::generate(&pid[0], &pid[0] + 20, std::rand);
		ses3->set_peer_id(pid);
		assert(ses3->id() != ses2->id());
	}

	boost::intrusive_ptr<torrent_info> t;
	if (torrent == 0)
	{
		create_directory("./tmp1" + suffix);
		std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
		t = ::create_torrent(&file, piece_size, 1024 / 8);
		file.close();
		if (clear_files)
		{
			remove_all("./tmp2" + suffix + "/temporary");
			remove_all("./tmp3" + suffix + "/temporary");
		}
		std::cerr << "generated torrent: " << t->info_hash() << std::endl;
	}
	else
	{
		t = *torrent;
	}

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2013 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "SamplePlugin.h"
#include "VolumeCSG.h"

#include "OgreVolumeCSGSource.h"
#include "OgreVolumeCacheSource.h"
#include "OgreVolumeTextureSource.h"
#include "OgreVolumeMeshBuilder.h"
#include "OgreMath.h"

using namespace Ogre;
using namespace OgreBites;
using namespace Ogre::Volume;

void Sample_VolumeCSG::setupContent(void)
{
    setupControls();
    setupShaderGenerator();
    Real size = (Real)31.0;
    Vector3 to(size);

    // Light
    Light* directionalLight0 = mSceneMgr->createLight("directionalLight0");
    directionalLight0->setType(Light::LT_DIRECTIONAL);
    directionalLight0->setDirection(Vector3((Real)1, (Real)-1, (Real)1));
    directionalLight0->setDiffuseColour((Real)1, (Real)0.98, (Real)0.73);
    directionalLight0->setSpecularColour((Real)0.1, (Real)0.1, (Real)0.1);

    // Spheres
    CSGSphereSource sphere1((Real)5.0, Vector3((Real)5.5));
    CSGSphereSource sphere2((Real)5.0, Vector3((Real)25.5, (Real)5.5, (Real)5.5));
    CSGSphereSource sphere3((Real)5.0, Vector3((Real)25.5, (Real)5.5, (Real)25.5));
    CSGSphereSource sphere4((Real)5.0, Vector3((Real)5.5, (Real)5.5, (Real)25.5));

    // Cubes
    Real halfWidth = (Real)(2.5 / 2.0);
    CSGCubeSource cube1(Vector3((Real)5.5 - halfWidth), Vector3((Real)25.5 + halfWidth, (Real)5.5 + halfWidth, (Real)25.5 + halfWidth));
    CSGCubeSource cube2(Vector3((Real)5.5 + halfWidth, (Real)0.0, (Real)5.5 + halfWidth), Vector3((Real)25.5 - halfWidth, to.y, (Real)25.5 - halfWidth));
    CSGDifferenceSource difference1(&cube1, &cube2);

    // Inner rounded cube
    Real innerHalfWidth = (Real)(7.0 / 2.0);
    Vector3 center((Real)15.5, (Real)5.5, (Real)15.5);
    CSGCubeSource cube3(center - innerHalfWidth, center + innerHalfWidth);
    CSGSphereSource sphere5(innerHalfWidth + (Real)0.75, center);
    CSGIntersectionSource intersection1(&cube3, &sphere5);

    // A plane with noise
    CSGPlaneSource plane1((Real)1.0, Vector3::UNIT_Y);
    Real frequencies[] = {(Real)1.01, (Real)0.48};
    Real amplitudes[] = {(Real)0.25, (Real)0.5};
    CSGNoiseSource noise1(&plane1, frequencies, amplitudes, 2, 100);

    // Combine everything
    CSGUnionSource union1(&sphere1, &sphere2);
    CSGUnionSource union2(&union1, &sphere3);
    CSGUnionSource union3(&union2, &sphere4);
    CSGUnionSource union4(&union3, &difference1);
    CSGUnionSource union5(&union4, &intersection1);
    CSGUnionSource union6(&union5, &noise1);
    Source *src = &union6;

    src->serialize(Vector3::ZERO, to, (Real)0.12109375, "volume.dat");

    mVolumeRoot = OGRE_NEW Chunk();
    SceneNode *volumeRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("VolumeParent");

    ChunkParameters parameters;
    parameters.sceneManager = mSceneMgr;
    parameters.src = src;
    parameters.baseError = (Real)0.25;

    mVolumeRoot->load(volumeRootNode, Vector3::ZERO, to, 1, &parameters);

    mVolumeRoot->setMaterial("Ogre/RTShader/TriplanarTexturing");

    // Camera
    mCamera->setPosition(to + (Real)7.5);
    mCamera->lookAt(center + (Real)11.0);
    mCamera->setNearClipDistance((Real)0.5);

    mRotation = (Real)0.0;

}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::setupControls(void)
{
    mTrayMgr->showCursor();
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
        setDragLook(true);
#endif
    mCameraMan->setStyle(OgreBites::CS_MANUAL);
    mCameraMan->setTopSpeed((Real)25.0);
    // make room for the volume
    mTrayMgr->showLogo(TL_TOPRIGHT);
    mTrayMgr->showFrameStats(TL_TOPRIGHT);
    mTrayMgr->toggleAdvancedFrameStats();
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::setupShaderGenerator()
{
    RTShader::ShaderGenerator* mGen = RTShader::ShaderGenerator::getSingletonPtr();

    RTShader::RenderState* pMainRenderState =
        mGen->createOrRetrieveRenderState(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME).first;
    pMainRenderState->reset();

    mGen->invalidateScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);

    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::cleanupContent(void)
{
    OGRE_DELETE mVolumeRoot;
    mVolumeRoot = 0;
}

//-----------------------------------------------------------------------

Sample_VolumeCSG::Sample_VolumeCSG(void) : mVolumeRoot(0), mHideAll(false)
{
    mInfo["Title"] = "Volume CSG and RTSS triplanar texturing";
    mInfo["Description"] = "Demonstrates a volumetric CSG scene, showing sphere, cube, plane, union, difference and intersection. The triplanar texturing is generated by the RTSS.";
    mInfo["Thumbnail"] = "thumb_volumecsg.png";
    mInfo["Category"] = "Geometry";
}

//-----------------------------------------------------------------------

bool Sample_VolumeCSG::keyPressed(const OIS::KeyEvent& evt)
{
    if (evt.key == OIS::KC_H)
    {
        if (mHideAll)
        {
            mTrayMgr->showAll();
        }
        else
        {
            mTrayMgr->hideAll();
        }
        mHideAll = !mHideAll;
    }
    return SdkSample::keyPressed(evt);
}

bool Sample_VolumeCSG::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    Vector3 center((Real)15.5, (Real)5.5, (Real)15.5);
    mRotation += Radian(evt.timeSinceLastFrame * (Real)0.5);
    Real r = (Real)35.0;
    mCamera->setPosition(
        Math::Sin(mRotation) * r + center.x,
        (Real)15.0 + center.y,
        Math::Cos(mRotation) * r + center.z
    );
    mCamera->lookAt(center);
    return SdkSample::frameRenderingQueued(evt);
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::_shutdown()
{
    RTShader::RenderState* pMainRenderState =
        RTShader::ShaderGenerator::getSingleton().createOrRetrieveRenderState(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME).first;
    pMainRenderState->reset();

    SdkSample::_shutdown();
}

//-----------------------------------------------------------------------

#ifndef OGRE_STATIC_LIB

SamplePlugin* sp;
Sample* s;

//-----------------------------------------------------------------------

extern "C" _OgreSampleExport void dllStartPlugin()
{
    s = new Sample_VolumeCSG();
    sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
    sp->addSample(s);
    Root::getSingleton().installPlugin(sp);
}

//-----------------------------------------------------------------------

extern "C" _OgreSampleExport void dllStopPlugin()
{
    Root::getSingleton().uninstallPlugin(sp);
    OGRE_DELETE sp;
    delete s;
}

#endif
<commit_msg>Volume Rendering: don't serialize on sample start...<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2013 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "SamplePlugin.h"
#include "VolumeCSG.h"

#include "OgreVolumeCSGSource.h"
#include "OgreVolumeCacheSource.h"
#include "OgreVolumeTextureSource.h"
#include "OgreVolumeMeshBuilder.h"
#include "OgreMath.h"

using namespace Ogre;
using namespace OgreBites;
using namespace Ogre::Volume;

void Sample_VolumeCSG::setupContent(void)
{
    setupControls();
    setupShaderGenerator();
    Real size = (Real)31.0;
    Vector3 to(size);

    // Light
    Light* directionalLight0 = mSceneMgr->createLight("directionalLight0");
    directionalLight0->setType(Light::LT_DIRECTIONAL);
    directionalLight0->setDirection(Vector3((Real)1, (Real)-1, (Real)1));
    directionalLight0->setDiffuseColour((Real)1, (Real)0.98, (Real)0.73);
    directionalLight0->setSpecularColour((Real)0.1, (Real)0.1, (Real)0.1);

    // Spheres
    CSGSphereSource sphere1((Real)5.0, Vector3((Real)5.5));
    CSGSphereSource sphere2((Real)5.0, Vector3((Real)25.5, (Real)5.5, (Real)5.5));
    CSGSphereSource sphere3((Real)5.0, Vector3((Real)25.5, (Real)5.5, (Real)25.5));
    CSGSphereSource sphere4((Real)5.0, Vector3((Real)5.5, (Real)5.5, (Real)25.5));

    // Cubes
    Real halfWidth = (Real)(2.5 / 2.0);
    CSGCubeSource cube1(Vector3((Real)5.5 - halfWidth), Vector3((Real)25.5 + halfWidth, (Real)5.5 + halfWidth, (Real)25.5 + halfWidth));
    CSGCubeSource cube2(Vector3((Real)5.5 + halfWidth, (Real)0.0, (Real)5.5 + halfWidth), Vector3((Real)25.5 - halfWidth, to.y, (Real)25.5 - halfWidth));
    CSGDifferenceSource difference1(&cube1, &cube2);

    // Inner rounded cube
    Real innerHalfWidth = (Real)(7.0 / 2.0);
    Vector3 center((Real)15.5, (Real)5.5, (Real)15.5);
    CSGCubeSource cube3(center - innerHalfWidth, center + innerHalfWidth);
    CSGSphereSource sphere5(innerHalfWidth + (Real)0.75, center);
    CSGIntersectionSource intersection1(&cube3, &sphere5);

    // A plane with noise
    CSGPlaneSource plane1((Real)1.0, Vector3::UNIT_Y);
    Real frequencies[] = {(Real)1.01, (Real)0.48};
    Real amplitudes[] = {(Real)0.25, (Real)0.5};
    CSGNoiseSource noise1(&plane1, frequencies, amplitudes, 2, 100);

    // Combine everything
    CSGUnionSource union1(&sphere1, &sphere2);
    CSGUnionSource union2(&union1, &sphere3);
    CSGUnionSource union3(&union2, &sphere4);
    CSGUnionSource union4(&union3, &difference1);
    CSGUnionSource union5(&union4, &intersection1);
    CSGUnionSource union6(&union5, &noise1);
    Source *src = &union6;

    mVolumeRoot = OGRE_NEW Chunk();
    SceneNode *volumeRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("VolumeParent");

    ChunkParameters parameters;
    parameters.sceneManager = mSceneMgr;
    parameters.src = src;
    parameters.baseError = (Real)0.25;

    mVolumeRoot->load(volumeRootNode, Vector3::ZERO, to, 1, &parameters);

    mVolumeRoot->setMaterial("Ogre/RTShader/TriplanarTexturing");

    // Camera
    mCamera->setPosition(to + (Real)7.5);
    mCamera->lookAt(center + (Real)11.0);
    mCamera->setNearClipDistance((Real)0.5);

    mRotation = (Real)0.0;

}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::setupControls(void)
{
    mTrayMgr->showCursor();
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
        setDragLook(true);
#endif
    mCameraMan->setStyle(OgreBites::CS_MANUAL);
    mCameraMan->setTopSpeed((Real)25.0);
    // make room for the volume
    mTrayMgr->showLogo(TL_TOPRIGHT);
    mTrayMgr->showFrameStats(TL_TOPRIGHT);
    mTrayMgr->toggleAdvancedFrameStats();
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::setupShaderGenerator()
{
    RTShader::ShaderGenerator* mGen = RTShader::ShaderGenerator::getSingletonPtr();

    RTShader::RenderState* pMainRenderState =
        mGen->createOrRetrieveRenderState(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME).first;
    pMainRenderState->reset();

    mGen->invalidateScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);

    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::cleanupContent(void)
{
    OGRE_DELETE mVolumeRoot;
    mVolumeRoot = 0;
}

//-----------------------------------------------------------------------

Sample_VolumeCSG::Sample_VolumeCSG(void) : mVolumeRoot(0), mHideAll(false)
{
    mInfo["Title"] = "Volume CSG and RTSS triplanar texturing";
    mInfo["Description"] = "Demonstrates a volumetric CSG scene, showing sphere, cube, plane, union, difference and intersection. The triplanar texturing is generated by the RTSS.";
    mInfo["Thumbnail"] = "thumb_volumecsg.png";
    mInfo["Category"] = "Geometry";
}

//-----------------------------------------------------------------------

bool Sample_VolumeCSG::keyPressed(const OIS::KeyEvent& evt)
{
    if (evt.key == OIS::KC_H)
    {
        if (mHideAll)
        {
            mTrayMgr->showAll();
        }
        else
        {
            mTrayMgr->hideAll();
        }
        mHideAll = !mHideAll;
    }
    return SdkSample::keyPressed(evt);
}

bool Sample_VolumeCSG::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    Vector3 center((Real)15.5, (Real)5.5, (Real)15.5);
    mRotation += Radian(evt.timeSinceLastFrame * (Real)0.5);
    Real r = (Real)35.0;
    mCamera->setPosition(
        Math::Sin(mRotation) * r + center.x,
        (Real)15.0 + center.y,
        Math::Cos(mRotation) * r + center.z
    );
    mCamera->lookAt(center);
    return SdkSample::frameRenderingQueued(evt);
}

//-----------------------------------------------------------------------

void Sample_VolumeCSG::_shutdown()
{
    RTShader::RenderState* pMainRenderState =
        RTShader::ShaderGenerator::getSingleton().createOrRetrieveRenderState(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME).first;
    pMainRenderState->reset();

    SdkSample::_shutdown();
}

//-----------------------------------------------------------------------

#ifndef OGRE_STATIC_LIB

SamplePlugin* sp;
Sample* s;

//-----------------------------------------------------------------------

extern "C" _OgreSampleExport void dllStartPlugin()
{
    s = new Sample_VolumeCSG();
    sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
    sp->addSample(s);
    Root::getSingleton().installPlugin(sp);
}

//-----------------------------------------------------------------------

extern "C" _OgreSampleExport void dllStopPlugin()
{
    Root::getSingleton().uninstallPlugin(sp);
    OGRE_DELETE sp;
    delete s;
}

#endif
<|endoftext|>


<commit_before>/*
    alsa_sink.cpp

    Copyright (c) 2013, Nikita Karnauhov

    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.

    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 "sink.h"

#include <alsa/asoundlib.h>

#include "alsa.h"
#include "settings.h"

class ALSASink : public Sink {
public:
    ALSASink(Log &_log);

    virtual ~ALSASink();

    virtual bool is_prepared() const {
        return m_pPcm != nullptr;
    }

    virtual void init(size_t _cChannels, const size_t _cRate, const std::string &_strFormat);
    virtual bool prepare();
    virtual void pause(bool _bEnable);

    virtual unsigned long get_buffer_size() const {
        return m_cBufferSize;
    }

    virtual unsigned long get_period_size() const {
        return m_cPeriodSize;
    }

    virtual unsigned int get_rate() const {
        return m_cRate;
    }

    virtual unsigned int get_frame_bytes() const {
        return m_cFrameBytes;
    }

    virtual bool can_be_paused() const {
        return m_bCanBePaused;
    }

    virtual long get_delay();
    virtual long get_avail(bool _bSync);
    virtual void recover(int _nError);

    virtual void report_state() {
        m_pLog->debug("State: %d", alsa::state(m_pPcm));
    }

    virtual bool is_buffering() const {
        return alsa::state(m_pPcm) == SND_PCM_STATE_PREPARED;
    }

    virtual bool is_running() const {
        return alsa::state(m_pPcm) == SND_PCM_STATE_RUNNING;
    }

    virtual bool is_paused() const {
        return alsa::state(m_pPcm) == SND_PCM_STATE_PAUSED;
    }

    virtual bool is_underrun() const {
        return alsa::state(m_pPcm) == SND_PCM_STATE_XRUN;
    }

    virtual void start();
    virtual void close();
    virtual long write(const void *_pBuffer, unsigned long _cFrames);

private:
    snd_pcm_t *m_pPcm = nullptr;
    snd_pcm_uframes_t m_cBufferSize = 2048;
    snd_pcm_uframes_t m_cPeriodSize = 512;
    size_t m_cChannelCount = 0;
    unsigned int m_cRate = 0;
    snd_pcm_format_t m_format = SND_PCM_FORMAT_UNKNOWN;
    size_t m_cFrameBytes = 0;
    Log *m_pLog;
    bool m_bReady = false;
    bool m_bCanBePaused = false;
    snd_pcm_sframes_t m_nBufferedFrames = 0;

    void _handle(alsa::Error &_e) const __attribute__((noreturn));
};

ALSASink::ALSASink(Log &_log) : m_pLog(&_log) {
}

ALSASink::~ALSASink() {
    try {
        if (m_pPcm) {
            alsa::drain(m_pPcm);
            alsa::close(m_pPcm);
        }

        m_pPcm = nullptr;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::init(size_t _cChannels, const size_t _cRate, const std::string &_strFormat) {
    m_cChannelCount = _cChannels;
    m_cRate = _cRate;
    m_format = alsa::get_format(_strFormat);
}

bool ALSASink::prepare() {
    try {
        snd_pcm_hw_params_t *pParams;

        if (m_pPcm == nullptr) {
            alsa::open(&m_pPcm, g_settings.strALSADevice.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
            alsa::hw_params_malloc(&pParams);
            alsa::hw_params_any(m_pPcm, pParams);
            alsa::hw_params_set_access(m_pPcm, pParams, SND_PCM_ACCESS_RW_INTERLEAVED);
            alsa::hw_params_set_format(m_pPcm, pParams, m_format);
            alsa::hw_params_set_rate_near(m_pPcm, pParams, &m_cRate, 0);
            alsa::hw_params_set_channels(m_pPcm, pParams, m_cChannelCount);
            alsa::hw_params_set_buffer_size_near(m_pPcm, pParams, &m_cBufferSize);
            alsa::hw_params_set_period_size_near(m_pPcm, pParams, &m_cPeriodSize, NULL);
            alsa::hw_params(m_pPcm, pParams);
            m_bCanBePaused = alsa::hw_params_can_pause(pParams);
            alsa::hw_params_free(pParams);

            snd_pcm_sw_params_t *pSWParams;
            snd_pcm_uframes_t cBoundary;

            snd_pcm_sw_params_alloca(&pSWParams);
            alsa::sw_params_current(m_pPcm, pSWParams);
            alsa::sw_params_get_boundary(pSWParams, &cBoundary);
            alsa::sw_params_set_start_threshold(m_pPcm, pSWParams, cBoundary);
            alsa::sw_params(m_pPcm, pSWParams);

            m_pLog->info("Opened ALSA device \"%s\"", g_settings.strALSADevice.c_str());
        }

        alsa::prepare(m_pPcm);

        m_cFrameBytes = alsa::format_physical_width(m_format)*m_cChannelCount/8;
        m_nBufferedFrames = 0;
        m_bReady = true;
    } catch (std::exception &e) {
        m_pLog->error(e.what());
        m_bReady = false;

        if (m_pPcm) {
            alsa::close(m_pPcm);
            m_pPcm = nullptr;
        }

        return false;
    }

    return true;
}

void ALSASink::pause(bool _bEnable) {
    try {
        alsa::pause(m_pPcm, _bEnable);

        if (_bEnable)
            m_nBufferedFrames = get_delay();
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

long ALSASink::get_delay() {
    snd_pcm_sframes_t nDelay = m_cBufferSize;

    if (is_buffering() || is_running())
        try {
            alsa::delay(m_pPcm, &nDelay);
            m_nBufferedFrames = nDelay;
        } catch (alsa::Error &e) {
            if (e.get_error() == -EIO) {
                m_pLog->warning(e.what());
                nDelay = std::min<snd_pcm_sframes_t>(m_cBufferSize, m_nBufferedFrames);
            } else
                _handle(e);
        }
    else if (is_paused())
        nDelay = std::min<snd_pcm_sframes_t>(m_cBufferSize, m_nBufferedFrames);

    return nDelay;
}

long ALSASink::get_avail(bool _bSync) {
    snd_pcm_sframes_t nFrames = 0;

    if (is_buffering() || is_running())
        try {
            nFrames = _bSync ? alsa::avail(m_pPcm) : alsa::avail_update(m_pPcm);
        } catch (alsa::Error &e) {
            if (e.get_error() == -EIO) {
                m_pLog->warning(e.what());
                nFrames = std::max<snd_pcm_sframes_t>(0, get_buffer_size() - m_nBufferedFrames);
            } else
                _handle(e);
        }
    else if (is_paused())
        nFrames = std::max<snd_pcm_sframes_t>(0, get_buffer_size() - m_nBufferedFrames);

    return nFrames;
}

void ALSASink::recover(int _nError) {
    try {
        alsa::recover(m_pPcm, _nError, true);
        m_nBufferedFrames = 0;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::start() {
    try {
        alsa::start(m_pPcm);
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::close() {
    try {
        alsa::close(m_pPcm);
        m_pPcm = nullptr;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

long ALSASink::write(const void *_pBuffer, unsigned long _cFrames) {
    try {
        const snd_pcm_sframes_t nFramesWritten = alsa::writei(m_pPcm, _pBuffer, _cFrames);
        m_nBufferedFrames += nFramesWritten;
        return nFramesWritten;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::_handle(alsa::Error &_e) const {
    if (_e.get_error() == -EPIPE)
        throw Error(Error::seUnderrun, _e.get_error(), _e.what());

    // Cannot recover from EIO: someone tells us device was unplugged.
    if (_e.get_error() == -EIO)
        throw Error(Error::seFatal, _e.get_error(), _e.what());

    throw Error(Error::seNormal, _e.get_error(), _e.what());
}

Sink *create_alsa_sink(Log &_log) {
    return new ALSASink(_log);
}
<commit_msg>Add 'override' specifiers.<commit_after>/*
    alsa_sink.cpp

    Copyright (c) 2013, Nikita Karnauhov

    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.

    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 "sink.h"

#include <alsa/asoundlib.h>

#include "alsa.h"
#include "settings.h"

class ALSASink : public Sink {
public:
    ALSASink(Log &_log);

    virtual ~ALSASink() override;

    virtual bool is_prepared() const override {
        return m_pPcm != nullptr;
    }

    virtual void init(size_t _cChannels, const size_t _cRate,
            const std::string &_strFormat) override;

    virtual bool prepare() override;
    virtual void pause(bool _bEnable) override;

    virtual unsigned long get_buffer_size() const override {
        return m_cBufferSize;
    }

    virtual unsigned long get_period_size() const override {
        return m_cPeriodSize;
    }

    virtual unsigned int get_rate() const override {
        return m_cRate;
    }

    virtual unsigned int get_frame_bytes() const override {
        return m_cFrameBytes;
    }

    virtual bool can_be_paused() const override {
        return m_bCanBePaused;
    }

    virtual long get_delay() override;
    virtual long get_avail(bool _bSync) override;
    virtual void recover(int _nError) override;

    virtual void report_state() override {
        m_pLog->debug("State: %d", alsa::state(m_pPcm));
    }

    virtual bool is_buffering() const override {
        return alsa::state(m_pPcm) == SND_PCM_STATE_PREPARED;
    }

    virtual bool is_running() const override {
        return alsa::state(m_pPcm) == SND_PCM_STATE_RUNNING;
    }

    virtual bool is_paused() const override {
        return alsa::state(m_pPcm) == SND_PCM_STATE_PAUSED;
    }

    virtual bool is_underrun() const override {
        return alsa::state(m_pPcm) == SND_PCM_STATE_XRUN;
    }

    virtual void start() override;
    virtual void close() override;
    virtual long write(const void *_pBuffer, unsigned long _cFrames) override;

private:
    snd_pcm_t *m_pPcm = nullptr;
    snd_pcm_uframes_t m_cBufferSize = 2048;
    snd_pcm_uframes_t m_cPeriodSize = 512;
    size_t m_cChannelCount = 0;
    unsigned int m_cRate = 0;
    snd_pcm_format_t m_format = SND_PCM_FORMAT_UNKNOWN;
    size_t m_cFrameBytes = 0;
    Log *m_pLog;
    bool m_bReady = false;
    bool m_bCanBePaused = false;
    snd_pcm_sframes_t m_nBufferedFrames = 0;

    void _handle(alsa::Error &_e) const __attribute__((noreturn));
};

ALSASink::ALSASink(Log &_log) : m_pLog(&_log) {
}

ALSASink::~ALSASink() {
    try {
        if (m_pPcm) {
            alsa::drain(m_pPcm);
            alsa::close(m_pPcm);
        }

        m_pPcm = nullptr;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::init(size_t _cChannels, const size_t _cRate, const std::string &_strFormat) {
    m_cChannelCount = _cChannels;
    m_cRate = _cRate;
    m_format = alsa::get_format(_strFormat);
}

bool ALSASink::prepare() {
    try {
        snd_pcm_hw_params_t *pParams;

        if (m_pPcm == nullptr) {
            alsa::open(&m_pPcm, g_settings.strALSADevice.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
            alsa::hw_params_malloc(&pParams);
            alsa::hw_params_any(m_pPcm, pParams);
            alsa::hw_params_set_access(m_pPcm, pParams, SND_PCM_ACCESS_RW_INTERLEAVED);
            alsa::hw_params_set_format(m_pPcm, pParams, m_format);
            alsa::hw_params_set_rate_near(m_pPcm, pParams, &m_cRate, 0);
            alsa::hw_params_set_channels(m_pPcm, pParams, m_cChannelCount);
            alsa::hw_params_set_buffer_size_near(m_pPcm, pParams, &m_cBufferSize);
            alsa::hw_params_set_period_size_near(m_pPcm, pParams, &m_cPeriodSize, NULL);
            alsa::hw_params(m_pPcm, pParams);
            m_bCanBePaused = alsa::hw_params_can_pause(pParams);
            alsa::hw_params_free(pParams);

            snd_pcm_sw_params_t *pSWParams;
            snd_pcm_uframes_t cBoundary;

            snd_pcm_sw_params_alloca(&pSWParams);
            alsa::sw_params_current(m_pPcm, pSWParams);
            alsa::sw_params_get_boundary(pSWParams, &cBoundary);
            alsa::sw_params_set_start_threshold(m_pPcm, pSWParams, cBoundary);
            alsa::sw_params(m_pPcm, pSWParams);

            m_pLog->info("Opened ALSA device \"%s\"", g_settings.strALSADevice.c_str());
        }

        alsa::prepare(m_pPcm);

        m_cFrameBytes = alsa::format_physical_width(m_format)*m_cChannelCount/8;
        m_nBufferedFrames = 0;
        m_bReady = true;
    } catch (std::exception &e) {
        m_pLog->error(e.what());
        m_bReady = false;

        if (m_pPcm) {
            alsa::close(m_pPcm);
            m_pPcm = nullptr;
        }

        return false;
    }

    return true;
}

void ALSASink::pause(bool _bEnable) {
    try {
        alsa::pause(m_pPcm, _bEnable);

        if (_bEnable)
            m_nBufferedFrames = get_delay();
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

long ALSASink::get_delay() {
    snd_pcm_sframes_t nDelay = m_cBufferSize;

    if (is_buffering() || is_running())
        try {
            alsa::delay(m_pPcm, &nDelay);
            m_nBufferedFrames = nDelay;
        } catch (alsa::Error &e) {
            if (e.get_error() == -EIO) {
                m_pLog->warning(e.what());
                nDelay = std::min<snd_pcm_sframes_t>(m_cBufferSize, m_nBufferedFrames);
            } else
                _handle(e);
        }
    else if (is_paused())
        nDelay = std::min<snd_pcm_sframes_t>(m_cBufferSize, m_nBufferedFrames);

    return nDelay;
}

long ALSASink::get_avail(bool _bSync) {
    snd_pcm_sframes_t nFrames = 0;

    if (is_buffering() || is_running())
        try {
            nFrames = _bSync ? alsa::avail(m_pPcm) : alsa::avail_update(m_pPcm);
        } catch (alsa::Error &e) {
            if (e.get_error() == -EIO) {
                m_pLog->warning(e.what());
                nFrames = std::max<snd_pcm_sframes_t>(0, get_buffer_size() - m_nBufferedFrames);
            } else
                _handle(e);
        }
    else if (is_paused())
        nFrames = std::max<snd_pcm_sframes_t>(0, get_buffer_size() - m_nBufferedFrames);

    return nFrames;
}

void ALSASink::recover(int _nError) {
    try {
        alsa::recover(m_pPcm, _nError, true);
        m_nBufferedFrames = 0;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::start() {
    try {
        alsa::start(m_pPcm);
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::close() {
    try {
        alsa::close(m_pPcm);
        m_pPcm = nullptr;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

long ALSASink::write(const void *_pBuffer, unsigned long _cFrames) {
    try {
        const snd_pcm_sframes_t nFramesWritten = alsa::writei(m_pPcm, _pBuffer, _cFrames);
        m_nBufferedFrames += nFramesWritten;
        return nFramesWritten;
    } catch (alsa::Error &e) {
        _handle(e);
    }
}

void ALSASink::_handle(alsa::Error &_e) const {
    if (_e.get_error() == -EPIPE)
        throw Error(Error::seUnderrun, _e.get_error(), _e.what());

    // Cannot recover from EIO: someone tells us device was unplugged.
    if (_e.get_error() == -EIO)
        throw Error(Error::seFatal, _e.get_error(), _e.what());

    throw Error(Error::seNormal, _e.get_error(), _e.what());
}

Sink *create_alsa_sink(Log &_log) {
    return new ALSASink(_log);
}
<|endoftext|>