<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/browser/ui/webui/sync_promo/sync_promo_ui.h"

#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/browser/ui/webui/options/core_options_handler.h"
#include "chrome/browser/ui/webui/sync_promo/sync_promo_handler.h"
#include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
#include "chrome/browser/ui/webui/theme_source.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "googleurl/src/url_util.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"

using content::WebContents;

namespace {

const char kStringsJsFile[] = "strings.js";
const char kSyncPromoJsFile[] = "sync_promo.js";

const char kSyncPromoQueryKeyIsLaunchPage[] = "is_launch_page";
const char kSyncPromoQueryKeyNextPage[] = "next_page";
const char kSyncPromoQueryKeySource[] = "source";

// The maximum number of times we want to show the sync promo at startup.
const int kSyncPromoShowAtStartupMaximum = 10;

// Checks we want to show the sync promo for the given brand.
bool AllowPromoAtStartupForCurrentBrand() {
  std::string brand;
  google_util::GetBrand(&brand);

  if (brand.empty())
    return true;

  if (google_util::IsInternetCafeBrandCode(brand))
    return false;

  if (google_util::IsOrganic(brand))
    return true;

  if (StartsWithASCII(brand, "CH", true))
    return true;

  // Default to disallow for all other brand codes.
  return false;
}

// The Web UI data source for the sync promo page.
class SyncPromoUIHTMLSource : public ChromeWebUIDataSource {
 public:
  explicit SyncPromoUIHTMLSource(content::WebUI* web_ui);

 private:
  ~SyncPromoUIHTMLSource() {}
  DISALLOW_COPY_AND_ASSIGN(SyncPromoUIHTMLSource);
};

SyncPromoUIHTMLSource::SyncPromoUIHTMLSource(content::WebUI* web_ui)
    : ChromeWebUIDataSource(chrome::kChromeUISyncPromoHost) {
  DictionaryValue localized_strings;
  CoreOptionsHandler::GetStaticLocalizedValues(&localized_strings);
  SyncSetupHandler::GetStaticLocalizedValues(&localized_strings, web_ui);
  AddLocalizedStrings(localized_strings);
}

// Looks for |search_key| in the query portion of |url|. Returns true if the
// key is found and sets |out_value| to the value for the key. Returns false if
// the key is not found.
bool GetValueForKeyInQuery(const GURL& url, const std::string& search_key,
                           std::string* out_value) {
  url_parse::Component query = url.parsed_for_possibly_invalid_spec().query;
  url_parse::Component key, value;
  while (url_parse::ExtractQueryKeyValue(
      url.spec().c_str(), &query, &key, &value)) {
    if (key.is_nonempty()) {
      std::string key_string = url.spec().substr(key.begin, key.len);
      if (key_string == search_key) {
        if (value.is_nonempty())
          *out_value = url.spec().substr(value.begin, value.len);
        else
          *out_value = "";
        return true;
      }
    }
  }
  return false;
}

}  // namespace

SyncPromoUI::SyncPromoUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  SyncPromoHandler* handler = new SyncPromoHandler(
      GetSourceForSyncPromoURL(web_ui->GetWebContents()->GetURL()),
      g_browser_process->profile_manager());
  web_ui->AddMessageHandler(handler);

  // Set up the chrome://theme/ source.
  Profile* profile = Profile::FromWebUI(web_ui);
  ThemeSource* theme = new ThemeSource(profile);
  profile->GetChromeURLDataManager()->AddDataSource(theme);

  // Set up the sync promo source.
  SyncPromoUIHTMLSource* html_source = new SyncPromoUIHTMLSource(web_ui);
  html_source->set_json_path(kStringsJsFile);
  html_source->add_resource_path(kSyncPromoJsFile, IDR_SYNC_PROMO_JS);
  html_source->set_default_resource(IDR_SYNC_PROMO_HTML);
  profile->GetChromeURLDataManager()->AddDataSource(html_source);

  sync_promo_trial::RecordUserShownPromo(web_ui);
}

// static
bool SyncPromoUI::HasShownPromoAtStartup(Profile* profile) {
  return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount);
}

// static
bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) {
#if defined(OS_CHROMEOS)
  // There's no need to show the sync promo on cros since cros users are logged
  // into sync already.
  return false;
#endif

  // Honor the sync policies.
  if (!profile->GetOriginalProfile()->IsSyncAccessible())
    return false;

  // If the user is already signed into sync then don't show the promo.
  ProfileSyncService* service =
      ProfileSyncServiceFactory::GetInstance()->GetForProfile(
          profile->GetOriginalProfile());
  if (!service || service->HasSyncSetupCompleted())
    return false;

  // Default to allow the promo.
  return true;
}

// static
void SyncPromoUI::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterIntegerPref(
      prefs::kSyncPromoStartupCount, 0, PrefService::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(
      prefs::kSyncPromoUserSkipped, false, PrefService::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kSyncPromoShowOnFirstRunAllowed, true,
      PrefService::UNSYNCABLE_PREF);

  SyncPromoHandler::RegisterUserPrefs(prefs);
}

// static
bool SyncPromoUI::ShouldShowSyncPromoAtStartup(Profile* profile,
                                               bool is_new_profile,
                                               bool* promo_suppressed) {
  DCHECK(profile);
  DCHECK(promo_suppressed);
  *promo_suppressed = false;

  if (!ShouldShowSyncPromo(profile))
    return false;

  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kNoFirstRun))
    is_new_profile = false;

  if (!is_new_profile) {
    if (!HasShownPromoAtStartup(profile))
      return false;
  }

  if (HasUserSkippedSyncPromo(profile))
    return false;

  // For Chinese users skip the sync promo.
  if (g_browser_process->GetApplicationLocale() == "zh-CN")
    return false;

  PrefService* prefs = profile->GetPrefs();
  int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount);
  if (show_count >= kSyncPromoShowAtStartupMaximum)
    return false;

  // If the current install is part of trial then let the trial determine if we
  // should show the promo or not.
  switch (sync_promo_trial::GetStartupOverrideForCurrentTrial()) {
    case sync_promo_trial::STARTUP_OVERRIDE_NONE:
      // No override so simply continue.
      break;
    case sync_promo_trial::STARTUP_OVERRIDE_SHOW:
      return true;
    case sync_promo_trial::STARTUP_OVERRIDE_HIDE:
      *promo_suppressed = true;
      return false;
  }

  // This pref can be set in the master preferences file to allow or disallow
  // showing the sync promo at startup.
  if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed))
    return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed);

  // For now don't show the promo for some brands.
  if (!AllowPromoAtStartupForCurrentBrand())
    return false;

  // Default to show the promo for Google Chrome builds.
#if defined(GOOGLE_CHROME_BUILD)
  return true;
#else
  return false;
#endif
}

void SyncPromoUI::DidShowSyncPromoAtStartup(Profile* profile) {
  int show_count = profile->GetPrefs()->GetInteger(
      prefs::kSyncPromoStartupCount);
  show_count++;
  profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count);
}

bool SyncPromoUI::HasUserSkippedSyncPromo(Profile* profile) {
  return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped);
}

void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) {
  profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true);
}

// static
GURL SyncPromoUI::GetSyncPromoURL(const GURL& next_page,
                                  bool show_title,
                                  const std::string& source) {
  std::stringstream stream;
  stream << chrome::kChromeUISyncPromoURL << "?"
         << kSyncPromoQueryKeyIsLaunchPage << "="
         << (show_title ? "true" : "false") << "&"
         << kSyncPromoQueryKeySource << "=" << source;

  if (!next_page.spec().empty()) {
    url_canon::RawCanonOutputT<char> output;
    url_util::EncodeURIComponent(
        next_page.spec().c_str(), next_page.spec().length(), &output);
    std::string escaped_spec(output.data(), output.length());
    stream << "&" << kSyncPromoQueryKeyNextPage << "=" << escaped_spec;
  }

  return GURL(stream.str());
}

// static
bool SyncPromoUI::GetIsLaunchPageForSyncPromoURL(const GURL& url) {
  std::string value;
  // Show the title if the promo is currently the Chrome launch page (and not
  // the page accessed through the NTP).
  if (GetValueForKeyInQuery(url, kSyncPromoQueryKeyIsLaunchPage, &value))
    return value == "true";
  return false;
}

// static
GURL SyncPromoUI::GetNextPageURLForSyncPromoURL(const GURL& url) {
  std::string value;
  if (GetValueForKeyInQuery(url, kSyncPromoQueryKeyNextPage, &value)) {
    url_canon::RawCanonOutputT<char16> output;
    url_util::DecodeURLEscapeSequences(value.c_str(), value.length(), &output);
    std::string url;
    UTF16ToUTF8(output.data(), output.length(), &url);
    return GURL(url);
  }
  return GURL();
}

// static
std::string SyncPromoUI::GetSourceForSyncPromoURL(const GURL& url) {
  std::string value;
  return GetValueForKeyInQuery(url, kSyncPromoQueryKeySource, &value) ?
      value : std::string();
}

// static
SyncPromoUI::Version SyncPromoUI::GetSyncPromoVersion() {
  Version version;
  if (sync_promo_trial::GetSyncPromoVersionForCurrentTrial(&version)) {
    // Currently the sync promo dialog has two problems. First, it's not modal
    // so the user can interact with other browser windows. Second, it uses
    // a nested message loop that can cause the sync promo page not to render.
    // To work around these problems the sync promo dialog is only shown for
    // the first profile. TODO(sail): Fix these issues if the sync promo dialog
    // is more widely deployed.
    ProfileInfoCache& cache =
        g_browser_process->profile_manager()->GetProfileInfoCache();
    if (cache.GetNumberOfProfiles() > 1 &&
        version == SyncPromoUI::VERSION_DIALOG) {
      return SyncPromoUI::VERSION_SIMPLE;
    }
    return version;
  }

  return VERSION_DEFAULT;
}
<commit_msg>Change the default sync promo<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/browser/ui/webui/sync_promo/sync_promo_ui.h"

#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/browser/ui/webui/options/core_options_handler.h"
#include "chrome/browser/ui/webui/sync_promo/sync_promo_handler.h"
#include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
#include "chrome/browser/ui/webui/theme_source.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "googleurl/src/url_util.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"

using content::WebContents;

namespace {

const char kStringsJsFile[] = "strings.js";
const char kSyncPromoJsFile[] = "sync_promo.js";

const char kSyncPromoQueryKeyIsLaunchPage[] = "is_launch_page";
const char kSyncPromoQueryKeyNextPage[] = "next_page";
const char kSyncPromoQueryKeySource[] = "source";

// The maximum number of times we want to show the sync promo at startup.
const int kSyncPromoShowAtStartupMaximum = 10;

// Checks we want to show the sync promo for the given brand.
bool AllowPromoAtStartupForCurrentBrand() {
  std::string brand;
  google_util::GetBrand(&brand);

  if (brand.empty())
    return true;

  if (google_util::IsInternetCafeBrandCode(brand))
    return false;

  if (google_util::IsOrganic(brand))
    return true;

  if (StartsWithASCII(brand, "CH", true))
    return true;

  // Default to disallow for all other brand codes.
  return false;
}

// The Web UI data source for the sync promo page.
class SyncPromoUIHTMLSource : public ChromeWebUIDataSource {
 public:
  explicit SyncPromoUIHTMLSource(content::WebUI* web_ui);

 private:
  ~SyncPromoUIHTMLSource() {}
  DISALLOW_COPY_AND_ASSIGN(SyncPromoUIHTMLSource);
};

SyncPromoUIHTMLSource::SyncPromoUIHTMLSource(content::WebUI* web_ui)
    : ChromeWebUIDataSource(chrome::kChromeUISyncPromoHost) {
  DictionaryValue localized_strings;
  CoreOptionsHandler::GetStaticLocalizedValues(&localized_strings);
  SyncSetupHandler::GetStaticLocalizedValues(&localized_strings, web_ui);
  AddLocalizedStrings(localized_strings);
}

// Looks for |search_key| in the query portion of |url|. Returns true if the
// key is found and sets |out_value| to the value for the key. Returns false if
// the key is not found.
bool GetValueForKeyInQuery(const GURL& url, const std::string& search_key,
                           std::string* out_value) {
  url_parse::Component query = url.parsed_for_possibly_invalid_spec().query;
  url_parse::Component key, value;
  while (url_parse::ExtractQueryKeyValue(
      url.spec().c_str(), &query, &key, &value)) {
    if (key.is_nonempty()) {
      std::string key_string = url.spec().substr(key.begin, key.len);
      if (key_string == search_key) {
        if (value.is_nonempty())
          *out_value = url.spec().substr(value.begin, value.len);
        else
          *out_value = "";
        return true;
      }
    }
  }
  return false;
}

}  // namespace

SyncPromoUI::SyncPromoUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  SyncPromoHandler* handler = new SyncPromoHandler(
      GetSourceForSyncPromoURL(web_ui->GetWebContents()->GetURL()),
      g_browser_process->profile_manager());
  web_ui->AddMessageHandler(handler);

  // Set up the chrome://theme/ source.
  Profile* profile = Profile::FromWebUI(web_ui);
  ThemeSource* theme = new ThemeSource(profile);
  profile->GetChromeURLDataManager()->AddDataSource(theme);

  // Set up the sync promo source.
  SyncPromoUIHTMLSource* html_source = new SyncPromoUIHTMLSource(web_ui);
  html_source->set_json_path(kStringsJsFile);
  html_source->add_resource_path(kSyncPromoJsFile, IDR_SYNC_PROMO_JS);
  html_source->set_default_resource(IDR_SYNC_PROMO_HTML);
  profile->GetChromeURLDataManager()->AddDataSource(html_source);

  sync_promo_trial::RecordUserShownPromo(web_ui);
}

// static
bool SyncPromoUI::HasShownPromoAtStartup(Profile* profile) {
  return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount);
}

// static
bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) {
#if defined(OS_CHROMEOS)
  // There's no need to show the sync promo on cros since cros users are logged
  // into sync already.
  return false;
#endif

  // Honor the sync policies.
  if (!profile->GetOriginalProfile()->IsSyncAccessible())
    return false;

  // If the user is already signed into sync then don't show the promo.
  ProfileSyncService* service =
      ProfileSyncServiceFactory::GetInstance()->GetForProfile(
          profile->GetOriginalProfile());
  if (!service || service->HasSyncSetupCompleted())
    return false;

  // Default to allow the promo.
  return true;
}

// static
void SyncPromoUI::RegisterUserPrefs(PrefService* prefs) {
  prefs->RegisterIntegerPref(
      prefs::kSyncPromoStartupCount, 0, PrefService::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(
      prefs::kSyncPromoUserSkipped, false, PrefService::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kSyncPromoShowOnFirstRunAllowed, true,
      PrefService::UNSYNCABLE_PREF);

  SyncPromoHandler::RegisterUserPrefs(prefs);
}

// static
bool SyncPromoUI::ShouldShowSyncPromoAtStartup(Profile* profile,
                                               bool is_new_profile,
                                               bool* promo_suppressed) {
  DCHECK(profile);
  DCHECK(promo_suppressed);
  *promo_suppressed = false;

  if (!ShouldShowSyncPromo(profile))
    return false;

  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kNoFirstRun))
    is_new_profile = false;

  if (!is_new_profile) {
    if (!HasShownPromoAtStartup(profile))
      return false;
  }

  if (HasUserSkippedSyncPromo(profile))
    return false;

  // For Chinese users skip the sync promo.
  if (g_browser_process->GetApplicationLocale() == "zh-CN")
    return false;

  PrefService* prefs = profile->GetPrefs();
  int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount);
  if (show_count >= kSyncPromoShowAtStartupMaximum)
    return false;

  // If the current install is part of trial then let the trial determine if we
  // should show the promo or not.
  switch (sync_promo_trial::GetStartupOverrideForCurrentTrial()) {
    case sync_promo_trial::STARTUP_OVERRIDE_NONE:
      // No override so simply continue.
      break;
    case sync_promo_trial::STARTUP_OVERRIDE_SHOW:
      return true;
    case sync_promo_trial::STARTUP_OVERRIDE_HIDE:
      *promo_suppressed = true;
      return false;
  }

  // This pref can be set in the master preferences file to allow or disallow
  // showing the sync promo at startup.
  if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed))
    return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed);

  // For now don't show the promo for some brands.
  if (!AllowPromoAtStartupForCurrentBrand())
    return false;

  // Default to show the promo for Google Chrome builds.
#if defined(GOOGLE_CHROME_BUILD)
  return true;
#else
  return false;
#endif
}

void SyncPromoUI::DidShowSyncPromoAtStartup(Profile* profile) {
  int show_count = profile->GetPrefs()->GetInteger(
      prefs::kSyncPromoStartupCount);
  show_count++;
  profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count);
}

bool SyncPromoUI::HasUserSkippedSyncPromo(Profile* profile) {
  return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped);
}

void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) {
  profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true);
}

// static
GURL SyncPromoUI::GetSyncPromoURL(const GURL& next_page,
                                  bool show_title,
                                  const std::string& source) {
  std::stringstream stream;
  stream << chrome::kChromeUISyncPromoURL << "?"
         << kSyncPromoQueryKeyIsLaunchPage << "="
         << (show_title ? "true" : "false") << "&"
         << kSyncPromoQueryKeySource << "=" << source;

  if (!next_page.spec().empty()) {
    url_canon::RawCanonOutputT<char> output;
    url_util::EncodeURIComponent(
        next_page.spec().c_str(), next_page.spec().length(), &output);
    std::string escaped_spec(output.data(), output.length());
    stream << "&" << kSyncPromoQueryKeyNextPage << "=" << escaped_spec;
  }

  return GURL(stream.str());
}

// static
bool SyncPromoUI::GetIsLaunchPageForSyncPromoURL(const GURL& url) {
  std::string value;
  // Show the title if the promo is currently the Chrome launch page (and not
  // the page accessed through the NTP).
  if (GetValueForKeyInQuery(url, kSyncPromoQueryKeyIsLaunchPage, &value))
    return value == "true";
  return false;
}

// static
GURL SyncPromoUI::GetNextPageURLForSyncPromoURL(const GURL& url) {
  std::string value;
  if (GetValueForKeyInQuery(url, kSyncPromoQueryKeyNextPage, &value)) {
    url_canon::RawCanonOutputT<char16> output;
    url_util::DecodeURLEscapeSequences(value.c_str(), value.length(), &output);
    std::string url;
    UTF16ToUTF8(output.data(), output.length(), &url);
    return GURL(url);
  }
  return GURL();
}

// static
std::string SyncPromoUI::GetSourceForSyncPromoURL(const GURL& url) {
  std::string value;
  return GetValueForKeyInQuery(url, kSyncPromoQueryKeySource, &value) ?
      value : std::string();
}

// static
SyncPromoUI::Version SyncPromoUI::GetSyncPromoVersion() {
  Version version;
  if (sync_promo_trial::GetSyncPromoVersionForCurrentTrial(&version)) {
    // Currently the sync promo dialog has two problems. First, it's not modal
    // so the user can interact with other browser windows. Second, it uses
    // a nested message loop that can cause the sync promo page not to render.
    // To work around these problems the sync promo dialog is only shown for
    // the first profile. TODO(sail): Fix these issues if the sync promo dialog
    // is more widely deployed.
    ProfileInfoCache& cache =
        g_browser_process->profile_manager()->GetProfileInfoCache();
    if (cache.GetNumberOfProfiles() > 1 &&
        version == SyncPromoUI::VERSION_DIALOG) {
      return SyncPromoUI::VERSION_SIMPLE;
    }
    return version;
  }

  return VERSION_SIMPLE;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file defines specific implementation of BrowserDistribution class for
// Google Chrome.

#include "chrome/installer/util/google_chrome_distribution.h"

#include <atlbase.h>
#include <windows.h>
#include <msi.h>

#include "base/file_path.h"
#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/wmi_util.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/util_constants.h"

#include "installer_util_strings.h"

namespace {
// Substitute the locale parameter in uninstall URL with whatever
// Google Update tells us is the locale. In case we fail to find
// the locale, we use US English.
std::wstring GetUninstallSurveyUrl() {
  std::wstring kSurveyUrl = L"http://www.google.com/support/chrome/bin/"
                            L"request.py?hl=$1&contact_type=uninstall";

  std::wstring language;
  if (!GoogleUpdateSettings::GetLanguage(&language))
    language = L"en-US";  // Default to US English.

  return ReplaceStringPlaceholders(kSurveyUrl.c_str(), language.c_str(), NULL);
}
}

bool GoogleChromeDistribution::BuildUninstallMetricsString(
    DictionaryValue* uninstall_metrics_dict, std::wstring* metrics) {
  DCHECK(NULL != metrics);
  bool has_values = false;

  DictionaryValue::key_iterator iter(uninstall_metrics_dict->begin_keys());
  for (; iter != uninstall_metrics_dict->end_keys(); ++iter) {
    has_values = true;
    metrics->append(L"&");
    metrics->append(*iter);
    metrics->append(L"=");

    std::wstring value;
    uninstall_metrics_dict->GetString(*iter, &value);
    metrics->append(value);
  }

  return has_values;
}

bool GoogleChromeDistribution::ExtractUninstallMetricsFromFile(
    const std::wstring& file_path, std::wstring* uninstall_metrics_string) {

  JSONFileValueSerializer json_serializer(FilePath::FromWStringHack(file_path));

  std::string json_error_string;
  scoped_ptr<Value> root(json_serializer.Deserialize(NULL));
  if (!root.get())
    return false;

  // Preferences should always have a dictionary root.
  if (!root->IsType(Value::TYPE_DICTIONARY))
    return false;

  return ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
                                 uninstall_metrics_string);
}

bool GoogleChromeDistribution::ExtractUninstallMetrics(
    const DictionaryValue& root, std::wstring* uninstall_metrics_string) {
  // Make sure that the user wants us reporting metrics. If not, don't
  // add our uninstall metrics.
  bool metrics_reporting_enabled = false;
  if (!root.GetBoolean(prefs::kMetricsReportingEnabled,
                       &metrics_reporting_enabled) ||
      !metrics_reporting_enabled) {
    return false;
  }

  DictionaryValue* uninstall_metrics_dict;
  if (!root.HasKey(installer_util::kUninstallMetricsName) ||
      !root.GetDictionary(installer_util::kUninstallMetricsName,
                          &uninstall_metrics_dict)) {
    return false;
  }

  if (!BuildUninstallMetricsString(uninstall_metrics_dict,
                                   uninstall_metrics_string)) {
    return false;
  }

  return true;
}

void GoogleChromeDistribution::DoPostUninstallOperations(
    const installer::Version& version, const std::wstring& local_data_path,
    const std::wstring& distribution_data) {
  // Send the Chrome version and OS version as params to the form.
  // It would be nice to send the locale, too, but I don't see an
  // easy way to get that in the existing code. It's something we
  // can add later, if needed.
  // We depend on installed_version.GetString() not having spaces or other
  // characters that need escaping: 0.2.13.4. Should that change, we will
  // need to escape the string before using it in a URL.
  const std::wstring kVersionParam = L"crversion";
  const std::wstring kVersion = version.GetString();
  const std::wstring kOSParam = L"os";
  std::wstring os_version = L"na";
  OSVERSIONINFO version_info;
  version_info.dwOSVersionInfoSize = sizeof(version_info);
  if (GetVersionEx(&version_info)) {
    os_version = StringPrintf(L"%d.%d.%d", version_info.dwMajorVersion,
                                           version_info.dwMinorVersion,
                                           version_info.dwBuildNumber);
  }

  FilePath iexplore;
  if (!PathService::Get(base::DIR_PROGRAM_FILES, &iexplore))
    return;

  iexplore = iexplore.AppendASCII("Internet Explorer");
  iexplore = iexplore.AppendASCII("iexplore.exe");

  std::wstring command = iexplore.value() + L" " + GetUninstallSurveyUrl() +
      L"&" + kVersionParam + L"=" + kVersion + L"&" + kOSParam + L"=" +
      os_version;

  std::wstring uninstall_metrics;
  if (ExtractUninstallMetricsFromFile(local_data_path, &uninstall_metrics)) {
    // The user has opted into anonymous usage data collection, so append
    // metrics and distribution data.
    command += uninstall_metrics;
    if (!distribution_data.empty()) {
      command += L"&";
      command += distribution_data;
    }
  }

  int pid = 0;
  WMIProcessUtil::Launch(command, &pid);
}

std::wstring GoogleChromeDistribution::GetApplicationName() {
  const std::wstring& product_name =
      installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
  return product_name;
}

std::wstring GoogleChromeDistribution::GetAlternateApplicationName() {
  const std::wstring& alt_product_name =
      installer_util::GetLocalizedString(IDS_OEM_MAIN_SHORTCUT_NAME_BASE);
  return alt_product_name;
}

std::wstring GoogleChromeDistribution::GetInstallSubDir() {
  return L"Google\\Chrome";
}

std::wstring GoogleChromeDistribution::GetNewGoogleUpdateApKey(
    bool diff_install, installer_util::InstallStatus status,
    const std::wstring& value) {
  // Magic suffix that we need to add or remove to "ap" key value.
  const std::wstring kMagicSuffix = L"-full";

  bool has_magic_string = false;
  if ((value.length() >= kMagicSuffix.length()) &&
      (value.rfind(kMagicSuffix) == (value.length() - kMagicSuffix.length()))) {
    LOG(INFO) << "Incremental installer failure key already set.";
    has_magic_string = true;
  }

  std::wstring new_value(value);
  if ((!diff_install || !GetInstallReturnCode(status)) && has_magic_string) {
    LOG(INFO) << "Removing failure key from value " << value;
    new_value = value.substr(0, value.length() - kMagicSuffix.length());
  } else if ((diff_install && GetInstallReturnCode(status)) &&
             !has_magic_string) {
    LOG(INFO) << "Incremental installer failed, setting failure key.";
    new_value.append(kMagicSuffix);
  }

  return new_value;
}

std::wstring GoogleChromeDistribution::GetPublisherName() {
  const std::wstring& publisher_name =
      installer_util::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE);
  return publisher_name;
}

std::wstring GoogleChromeDistribution::GetAppDescription() {
  const std::wstring& app_description =
      installer_util::GetLocalizedString(IDS_SHORTCUT_TOOLTIP_BASE);
  return app_description;
}

int GoogleChromeDistribution::GetInstallReturnCode(
    installer_util::InstallStatus status) {
  switch (status) {
    case installer_util::FIRST_INSTALL_SUCCESS:
    case installer_util::INSTALL_REPAIRED:
    case installer_util::NEW_VERSION_UPDATED:
    case installer_util::HIGHER_VERSION_EXISTS:
      return 0;  // For Google Update's benefit we need to return 0 for success
    default:
      return status;
  }
}

std::wstring GoogleChromeDistribution::GetStateKey() {
  std::wstring key(google_update::kRegPathClientState);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

std::wstring GoogleChromeDistribution::GetStateMediumKey() {
  std::wstring key(google_update::kRegPathClientStateMedium);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

std::wstring GoogleChromeDistribution::GetStatsServerURL() {
  return L"https://clients4.google.com/firefox/metrics/collect";
}

std::wstring GoogleChromeDistribution::GetDistributionData(RegKey* key) {
  DCHECK(NULL != key);
  std::wstring sub_key(google_update::kRegPathClientState);
  sub_key.append(L"\\");
  sub_key.append(google_update::kChromeGuid);

  RegKey client_state_key(key->Handle(), sub_key.c_str());
  std::wstring result;
  std::wstring brand_value;
  if (client_state_key.ReadValue(google_update::kRegRLZBrandField,
                                 &brand_value)) {
    result = google_update::kRegRLZBrandField;
    result.append(L"=");
    result.append(brand_value);
  }

  return result;
}

std::wstring GoogleChromeDistribution::GetUninstallLinkName() {
  const std::wstring& link_name =
      installer_util::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE);
  return link_name;
}

std::wstring GoogleChromeDistribution::GetUninstallRegPath() {
  return L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
         L"Google Chrome";
}

std::wstring GoogleChromeDistribution::GetVersionKey() {
  std::wstring key(google_update::kRegPathClients);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

// This method checks if we need to change "ap" key in Google Update to try
// full installer as fall back method in case incremental installer fails.
// - If incremental installer fails we append a magic string ("-full"), if
// it is not present already, so that Google Update server next time will send
// full installer to update Chrome on the local machine
// - If we are currently running full installer, we remove this magic
// string (if it is present) regardless of whether installer failed or not.
// There is no fall-back for full installer :)
void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
    bool incremental_install, installer_util::InstallStatus install_status) {
  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

  RegKey key;
  std::wstring ap_key_value;
  std::wstring reg_key(google_update::kRegPathClientState);
  reg_key.append(L"\\");
  reg_key.append(google_update::kChromeGuid);
  if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
      !key.ReadValue(google_update::kRegApField, &ap_key_value)) {
    LOG(INFO) << "Application key not found.";
    if (!incremental_install || !GetInstallReturnCode(install_status)) {
      LOG(INFO) << "Returning without changing application key.";
      key.Close();
      return;
    } else if (!key.Valid()) {
      reg_key.assign(google_update::kRegPathClientState);
      if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
          !key.CreateKey(google_update::kChromeGuid, KEY_ALL_ACCESS)) {
        LOG(ERROR) << "Failed to create application key.";
        key.Close();
        return;
      }
    }
  }

  std::wstring new_value = GoogleChromeDistribution::GetNewGoogleUpdateApKey(
      incremental_install, install_status, ap_key_value);
  if ((new_value.compare(ap_key_value) != 0) &&
      !key.WriteValue(google_update::kRegApField, new_value.c_str())) {
    LOG(ERROR) << "Failed to write value " << new_value
               << " to the registry field " << google_update::kRegApField;
  }
  key.Close();
}
<commit_msg>Adding ap key inclusion to uninstall metrics.<commit_after>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file defines specific implementation of BrowserDistribution class for
// Google Chrome.

#include "chrome/installer/util/google_chrome_distribution.h"

#include <atlbase.h>
#include <windows.h>
#include <msi.h>

#include "base/file_path.h"
#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/wmi_util.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/util_constants.h"

#include "installer_util_strings.h"

namespace {
// Substitute the locale parameter in uninstall URL with whatever
// Google Update tells us is the locale. In case we fail to find
// the locale, we use US English.
std::wstring GetUninstallSurveyUrl() {
  std::wstring kSurveyUrl = L"http://www.google.com/support/chrome/bin/"
                            L"request.py?hl=$1&contact_type=uninstall";

  std::wstring language;
  if (!GoogleUpdateSettings::GetLanguage(&language))
    language = L"en-US";  // Default to US English.

  return ReplaceStringPlaceholders(kSurveyUrl.c_str(), language.c_str(), NULL);
}
}

bool GoogleChromeDistribution::BuildUninstallMetricsString(
    DictionaryValue* uninstall_metrics_dict, std::wstring* metrics) {
  DCHECK(NULL != metrics);
  bool has_values = false;

  DictionaryValue::key_iterator iter(uninstall_metrics_dict->begin_keys());
  for (; iter != uninstall_metrics_dict->end_keys(); ++iter) {
    has_values = true;
    metrics->append(L"&");
    metrics->append(*iter);
    metrics->append(L"=");

    std::wstring value;
    uninstall_metrics_dict->GetString(*iter, &value);
    metrics->append(value);
  }

  return has_values;
}

bool GoogleChromeDistribution::ExtractUninstallMetricsFromFile(
    const std::wstring& file_path, std::wstring* uninstall_metrics_string) {

  JSONFileValueSerializer json_serializer(FilePath::FromWStringHack(file_path));

  std::string json_error_string;
  scoped_ptr<Value> root(json_serializer.Deserialize(NULL));
  if (!root.get())
    return false;

  // Preferences should always have a dictionary root.
  if (!root->IsType(Value::TYPE_DICTIONARY))
    return false;

  return ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
                                 uninstall_metrics_string);
}

bool GoogleChromeDistribution::ExtractUninstallMetrics(
    const DictionaryValue& root, std::wstring* uninstall_metrics_string) {
  // Make sure that the user wants us reporting metrics. If not, don't
  // add our uninstall metrics.
  bool metrics_reporting_enabled = false;
  if (!root.GetBoolean(prefs::kMetricsReportingEnabled,
                       &metrics_reporting_enabled) ||
      !metrics_reporting_enabled) {
    return false;
  }

  DictionaryValue* uninstall_metrics_dict;
  if (!root.HasKey(installer_util::kUninstallMetricsName) ||
      !root.GetDictionary(installer_util::kUninstallMetricsName,
                          &uninstall_metrics_dict)) {
    return false;
  }

  if (!BuildUninstallMetricsString(uninstall_metrics_dict,
                                   uninstall_metrics_string)) {
    return false;
  }

  return true;
}

void GoogleChromeDistribution::DoPostUninstallOperations(
    const installer::Version& version, const std::wstring& local_data_path,
    const std::wstring& distribution_data) {
  // Send the Chrome version and OS version as params to the form.
  // It would be nice to send the locale, too, but I don't see an
  // easy way to get that in the existing code. It's something we
  // can add later, if needed.
  // We depend on installed_version.GetString() not having spaces or other
  // characters that need escaping: 0.2.13.4. Should that change, we will
  // need to escape the string before using it in a URL.
  const std::wstring kVersionParam = L"crversion";
  const std::wstring kVersion = version.GetString();
  const std::wstring kOSParam = L"os";
  std::wstring os_version = L"na";
  OSVERSIONINFO version_info;
  version_info.dwOSVersionInfoSize = sizeof(version_info);
  if (GetVersionEx(&version_info)) {
    os_version = StringPrintf(L"%d.%d.%d", version_info.dwMajorVersion,
                                           version_info.dwMinorVersion,
                                           version_info.dwBuildNumber);
  }

  FilePath iexplore;
  if (!PathService::Get(base::DIR_PROGRAM_FILES, &iexplore))
    return;

  iexplore = iexplore.AppendASCII("Internet Explorer");
  iexplore = iexplore.AppendASCII("iexplore.exe");

  std::wstring command = iexplore.value() + L" " + GetUninstallSurveyUrl() +
      L"&" + kVersionParam + L"=" + kVersion + L"&" + kOSParam + L"=" +
      os_version;

  std::wstring uninstall_metrics;
  if (ExtractUninstallMetricsFromFile(local_data_path, &uninstall_metrics)) {
    // The user has opted into anonymous usage data collection, so append
    // metrics and distribution data.
    command += uninstall_metrics;
    if (!distribution_data.empty()) {
      command += L"&";
      command += distribution_data;
    }
  }

  int pid = 0;
  WMIProcessUtil::Launch(command, &pid);
}

std::wstring GoogleChromeDistribution::GetApplicationName() {
  const std::wstring& product_name =
      installer_util::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
  return product_name;
}

std::wstring GoogleChromeDistribution::GetAlternateApplicationName() {
  const std::wstring& alt_product_name =
      installer_util::GetLocalizedString(IDS_OEM_MAIN_SHORTCUT_NAME_BASE);
  return alt_product_name;
}

std::wstring GoogleChromeDistribution::GetInstallSubDir() {
  return L"Google\\Chrome";
}

std::wstring GoogleChromeDistribution::GetNewGoogleUpdateApKey(
    bool diff_install, installer_util::InstallStatus status,
    const std::wstring& value) {
  // Magic suffix that we need to add or remove to "ap" key value.
  const std::wstring kMagicSuffix = L"-full";

  bool has_magic_string = false;
  if ((value.length() >= kMagicSuffix.length()) &&
      (value.rfind(kMagicSuffix) == (value.length() - kMagicSuffix.length()))) {
    LOG(INFO) << "Incremental installer failure key already set.";
    has_magic_string = true;
  }

  std::wstring new_value(value);
  if ((!diff_install || !GetInstallReturnCode(status)) && has_magic_string) {
    LOG(INFO) << "Removing failure key from value " << value;
    new_value = value.substr(0, value.length() - kMagicSuffix.length());
  } else if ((diff_install && GetInstallReturnCode(status)) &&
             !has_magic_string) {
    LOG(INFO) << "Incremental installer failed, setting failure key.";
    new_value.append(kMagicSuffix);
  }

  return new_value;
}

std::wstring GoogleChromeDistribution::GetPublisherName() {
  const std::wstring& publisher_name =
      installer_util::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE);
  return publisher_name;
}

std::wstring GoogleChromeDistribution::GetAppDescription() {
  const std::wstring& app_description =
      installer_util::GetLocalizedString(IDS_SHORTCUT_TOOLTIP_BASE);
  return app_description;
}

int GoogleChromeDistribution::GetInstallReturnCode(
    installer_util::InstallStatus status) {
  switch (status) {
    case installer_util::FIRST_INSTALL_SUCCESS:
    case installer_util::INSTALL_REPAIRED:
    case installer_util::NEW_VERSION_UPDATED:
    case installer_util::HIGHER_VERSION_EXISTS:
      return 0;  // For Google Update's benefit we need to return 0 for success
    default:
      return status;
  }
}

std::wstring GoogleChromeDistribution::GetStateKey() {
  std::wstring key(google_update::kRegPathClientState);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

std::wstring GoogleChromeDistribution::GetStateMediumKey() {
  std::wstring key(google_update::kRegPathClientStateMedium);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

std::wstring GoogleChromeDistribution::GetStatsServerURL() {
  return L"https://clients4.google.com/firefox/metrics/collect";
}

std::wstring GoogleChromeDistribution::GetDistributionData(RegKey* key) {
  DCHECK(NULL != key);
  std::wstring sub_key(google_update::kRegPathClientState);
  sub_key.append(L"\\");
  sub_key.append(google_update::kChromeGuid);

  RegKey client_state_key(key->Handle(), sub_key.c_str());
  std::wstring result;
  std::wstring brand_value;
  if (client_state_key.ReadValue(google_update::kRegRLZBrandField,
                                 &brand_value)) {
    result = google_update::kRegRLZBrandField;
    result.append(L"=");
    result.append(brand_value);
    result.append(L"&");
  }

  std::wstring ap_value;
  // If we fail to read the ap key, send up "&ap=" anyway to indicate
  // that this was probably a stable channel release.
  client_state_key.ReadValue(google_update::kRegApField, &ap_value);
  result.append(google_update::kRegApField);
  result.append(L"=");
  result.append(ap_value);

  return result;
}

std::wstring GoogleChromeDistribution::GetUninstallLinkName() {
  const std::wstring& link_name =
      installer_util::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE);
  return link_name;
}

std::wstring GoogleChromeDistribution::GetUninstallRegPath() {
  return L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
         L"Google Chrome";
}

std::wstring GoogleChromeDistribution::GetVersionKey() {
  std::wstring key(google_update::kRegPathClients);
  key.append(L"\\");
  key.append(google_update::kChromeGuid);
  return key;
}

// This method checks if we need to change "ap" key in Google Update to try
// full installer as fall back method in case incremental installer fails.
// - If incremental installer fails we append a magic string ("-full"), if
// it is not present already, so that Google Update server next time will send
// full installer to update Chrome on the local machine
// - If we are currently running full installer, we remove this magic
// string (if it is present) regardless of whether installer failed or not.
// There is no fall-back for full installer :)
void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
    bool incremental_install, installer_util::InstallStatus install_status) {
  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

  RegKey key;
  std::wstring ap_key_value;
  std::wstring reg_key(google_update::kRegPathClientState);
  reg_key.append(L"\\");
  reg_key.append(google_update::kChromeGuid);
  if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
      !key.ReadValue(google_update::kRegApField, &ap_key_value)) {
    LOG(INFO) << "Application key not found.";
    if (!incremental_install || !GetInstallReturnCode(install_status)) {
      LOG(INFO) << "Returning without changing application key.";
      key.Close();
      return;
    } else if (!key.Valid()) {
      reg_key.assign(google_update::kRegPathClientState);
      if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
          !key.CreateKey(google_update::kChromeGuid, KEY_ALL_ACCESS)) {
        LOG(ERROR) << "Failed to create application key.";
        key.Close();
        return;
      }
    }
  }

  std::wstring new_value = GoogleChromeDistribution::GetNewGoogleUpdateApKey(
      incremental_install, install_status, ap_key_value);
  if ((new_value.compare(ap_key_value) != 0) &&
      !key.WriteValue(google_update::kRegApField, new_value.c_str())) {
    LOG(ERROR) << "Failed to write value " << new_value
               << " to the registry field " << google_update::kRegApField;
  }
  key.Close();
}
<|endoftext|>


<commit_before>// Copyright 2014 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/utility/printing_handler_win.h"

#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/scoped_native_library.h"
#include "chrome/common/print_messages.h"
#include "content/public/utility/utility_thread.h"
#include "printing/emf_win.h"
#include "printing/page_range.h"
#include "printing/pdf_render_settings.h"
#include "ui/gfx/gdi_util.h"

namespace {

bool Send(IPC::Message* message) {
  return content::UtilityThread::Get()->Send(message);
}

void ReleaseProcessIfNeeded() {
  content::UtilityThread::Get()->ReleaseProcessIfNeeded();
}

class PdfFunctions {
 public:
  PdfFunctions() : get_pdf_doc_info_func_(NULL),
                   render_pdf_to_dc_func_(NULL) {}

  bool Init() {
    base::FilePath pdf_module_path(FILE_PATH_LITERAL("pdf.dll"));
    pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL));
    if (!pdf_lib_.is_valid()) {
      LOG(WARNING) << "Couldn't load PDF plugin";
      return false;
    }

    get_pdf_doc_info_func_ =
        reinterpret_cast<GetPDFDocInfoProc>(
            pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
    LOG_IF(WARNING, !get_pdf_doc_info_func_) << "Missing GetPDFDocInfo";

    render_pdf_to_dc_func_ =
      reinterpret_cast<RenderPDFPageToDCProc>(
          pdf_lib_.GetFunctionPointer("RenderPDFPageToDC"));
    LOG_IF(WARNING, !render_pdf_to_dc_func_) << "Missing RenderPDFPageToDC";

    if (!get_pdf_doc_info_func_ || !render_pdf_to_dc_func_) {
      Reset();
    }

    return IsValid();
  }

  bool IsValid() const {
    return pdf_lib_.is_valid();
  }

  void Reset() {
    pdf_lib_.Reset(NULL);
  }

  bool GetPDFDocInfo(const void* pdf_buffer,
                     int buffer_size,
                     int* page_count,
                     double* max_page_width) {
    if (!get_pdf_doc_info_func_)
      return false;
    return get_pdf_doc_info_func_(pdf_buffer, buffer_size, page_count,
                                  max_page_width);
  }

  bool RenderPDFPageToDC(const void* pdf_buffer,
                         int buffer_size,
                         int page_number,
                         HDC dc,
                         int dpi,
                         int bounds_origin_x,
                         int bounds_origin_y,
                         int bounds_width,
                         int bounds_height,
                         bool fit_to_bounds,
                         bool stretch_to_bounds,
                         bool keep_aspect_ratio,
                         bool center_in_bounds,
                         bool autorotate) {
    if (!render_pdf_to_dc_func_)
      return false;
    return render_pdf_to_dc_func_(pdf_buffer, buffer_size, page_number,
                                  dc, dpi, bounds_origin_x,
                                  bounds_origin_y, bounds_width, bounds_height,
                                  fit_to_bounds, stretch_to_bounds,
                                  keep_aspect_ratio, center_in_bounds,
                                  autorotate);
  }

 private:
  // Exported by PDF plugin.
  typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
                                    int buffer_size, int* page_count,
                                    double* max_page_width);
  typedef bool (*RenderPDFPageToDCProc)(
      const void* pdf_buffer, int buffer_size, int page_number, HDC dc,
      int dpi, int bounds_origin_x, int bounds_origin_y,
      int bounds_width, int bounds_height, bool fit_to_bounds,
      bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
      bool autorotate);

  RenderPDFPageToDCProc render_pdf_to_dc_func_;
  GetPDFDocInfoProc get_pdf_doc_info_func_;

  base::ScopedNativeLibrary pdf_lib_;

  DISALLOW_COPY_AND_ASSIGN(PdfFunctions);
};

base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER;

}  // namespace

PrintingHandlerWin::PrintingHandlerWin() {}

PrintingHandlerWin::~PrintingHandlerWin() {}

// static
void PrintingHandlerWin::PreSandboxStartup() {
  g_pdf_lib.Get().Init();
}

bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
                        OnRenderPDFPagesToMetafile)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage,
                        OnRenderPDFPagesToMetafileGetPage)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop,
                        OnRenderPDFPagesToMetafileStop)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafile(
    IPC::PlatformFileForTransit pdf_transit,
    const printing::PdfRenderSettings& settings) {
  pdf_rendering_settings_ = settings;
  base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
  int page_count = LoadPDF(pdf_file.Pass());
  //int page_count = 1;
  Send(
      new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count));
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafileGetPage(
    int page_number,
    IPC::PlatformFileForTransit output_file) {
  base::File emf_file = IPC::PlatformFileForTransitToFile(output_file);
  float scale_factor = 1.0f;
  bool success =
      RenderPdfPageToMetafile(page_number, emf_file.Pass(), &scale_factor);
  Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone(
      success, scale_factor));
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafileStop() {
  ReleaseProcessIfNeeded();
}

int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
  if (!g_pdf_lib.Get().IsValid())
    return 0;

  int64 length64 = pdf_file.GetLength();
  if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
    return 0;
  int length = static_cast<int>(length64);

  pdf_data_.resize(length);
  if (length != pdf_file.Read(0, pdf_data_.data(), pdf_data_.size()))
    return 0;

  int total_page_count = 0;
  if (!g_pdf_lib.Get().GetPDFDocInfo(
          &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) {
    return 0;
  }
  return total_page_count;
}

bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
                                                 base::File output_file,
                                                 float* scale_factor) {
  printing::Emf metafile;
  metafile.Init();

  // We need to scale down DC to fit an entire page into DC available area.
  // Current metafile is based on screen DC and have current screen size.
  // Writing outside of those boundaries will result in the cut-off output.
  // On metafiles (this is the case here), scaling down will still record
  // original coordinates and we'll be able to print in full resolution.
  // Before playback we'll need to counter the scaling up that will happen
  // in the service (print_system_win.cc).
  *scale_factor =
      gfx::CalculatePageScale(metafile.context(),
                              pdf_rendering_settings_.area().right(),
                              pdf_rendering_settings_.area().bottom());
  gfx::ScaleDC(metafile.context(), *scale_factor);

  // The underlying metafile is of type Emf and ignores the arguments passed
  // to StartPage.
  metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
  if (!g_pdf_lib.Get().RenderPDFPageToDC(
          &pdf_data_.front(),
          pdf_data_.size(),
          page_number,
          metafile.context(),
          pdf_rendering_settings_.dpi(),
          pdf_rendering_settings_.area().x(),
          pdf_rendering_settings_.area().y(),
          pdf_rendering_settings_.area().width(),
          pdf_rendering_settings_.area().height(),
          true,
          false,
          true,
          true,
          pdf_rendering_settings_.autorotate())) {
    return false;
  }
  metafile.FinishPage();
  metafile.FinishDocument();
  return metafile.SaveTo(&output_file);
}
<commit_msg>win: Load pdf.dll with abosolute path, fix #1826<commit_after>// Copyright 2014 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/utility/printing_handler_win.h"

#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/scoped_native_library.h"
#include "chrome/common/print_messages.h"
#include "content/public/utility/utility_thread.h"
#include "printing/emf_win.h"
#include "printing/page_range.h"
#include "printing/pdf_render_settings.h"
#include "ui/gfx/gdi_util.h"

namespace {

bool Send(IPC::Message* message) {
  return content::UtilityThread::Get()->Send(message);
}

void ReleaseProcessIfNeeded() {
  content::UtilityThread::Get()->ReleaseProcessIfNeeded();
}

class PdfFunctions {
 public:
  PdfFunctions() : get_pdf_doc_info_func_(NULL),
                   render_pdf_to_dc_func_(NULL) {}

  bool Init() {
    base::FilePath module_path;
    if (!PathService::Get(base::DIR_MODULE, &module_path))
      return false;
    base::FilePath::StringType name(FILE_PATH_LITERAL("pdf.dll"));
    pdf_lib_.Reset(base::LoadNativeLibrary(module_path.Append(name), NULL));
    if (!pdf_lib_.is_valid()) {
      LOG(WARNING) << "Couldn't load PDF plugin";
      return false;
    }

    get_pdf_doc_info_func_ =
        reinterpret_cast<GetPDFDocInfoProc>(
            pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
    LOG_IF(WARNING, !get_pdf_doc_info_func_) << "Missing GetPDFDocInfo";

    render_pdf_to_dc_func_ =
      reinterpret_cast<RenderPDFPageToDCProc>(
          pdf_lib_.GetFunctionPointer("RenderPDFPageToDC"));
    LOG_IF(WARNING, !render_pdf_to_dc_func_) << "Missing RenderPDFPageToDC";

    if (!get_pdf_doc_info_func_ || !render_pdf_to_dc_func_) {
      Reset();
    }

    return IsValid();
  }

  bool IsValid() const {
    return pdf_lib_.is_valid();
  }

  void Reset() {
    pdf_lib_.Reset(NULL);
  }

  bool GetPDFDocInfo(const void* pdf_buffer,
                     int buffer_size,
                     int* page_count,
                     double* max_page_width) {
    if (!get_pdf_doc_info_func_)
      return false;
    return get_pdf_doc_info_func_(pdf_buffer, buffer_size, page_count,
                                  max_page_width);
  }

  bool RenderPDFPageToDC(const void* pdf_buffer,
                         int buffer_size,
                         int page_number,
                         HDC dc,
                         int dpi,
                         int bounds_origin_x,
                         int bounds_origin_y,
                         int bounds_width,
                         int bounds_height,
                         bool fit_to_bounds,
                         bool stretch_to_bounds,
                         bool keep_aspect_ratio,
                         bool center_in_bounds,
                         bool autorotate) {
    if (!render_pdf_to_dc_func_)
      return false;
    return render_pdf_to_dc_func_(pdf_buffer, buffer_size, page_number,
                                  dc, dpi, bounds_origin_x,
                                  bounds_origin_y, bounds_width, bounds_height,
                                  fit_to_bounds, stretch_to_bounds,
                                  keep_aspect_ratio, center_in_bounds,
                                  autorotate);
  }

 private:
  // Exported by PDF plugin.
  typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
                                    int buffer_size, int* page_count,
                                    double* max_page_width);
  typedef bool (*RenderPDFPageToDCProc)(
      const void* pdf_buffer, int buffer_size, int page_number, HDC dc,
      int dpi, int bounds_origin_x, int bounds_origin_y,
      int bounds_width, int bounds_height, bool fit_to_bounds,
      bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
      bool autorotate);

  RenderPDFPageToDCProc render_pdf_to_dc_func_;
  GetPDFDocInfoProc get_pdf_doc_info_func_;

  base::ScopedNativeLibrary pdf_lib_;

  DISALLOW_COPY_AND_ASSIGN(PdfFunctions);
};

base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER;

}  // namespace

PrintingHandlerWin::PrintingHandlerWin() {}

PrintingHandlerWin::~PrintingHandlerWin() {}

// static
void PrintingHandlerWin::PreSandboxStartup() {
  g_pdf_lib.Get().Init();
}

bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
                        OnRenderPDFPagesToMetafile)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage,
                        OnRenderPDFPagesToMetafileGetPage)
    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop,
                        OnRenderPDFPagesToMetafileStop)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafile(
    IPC::PlatformFileForTransit pdf_transit,
    const printing::PdfRenderSettings& settings) {
  pdf_rendering_settings_ = settings;
  base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
  int page_count = LoadPDF(pdf_file.Pass());
  //int page_count = 1;
  Send(
      new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count));
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafileGetPage(
    int page_number,
    IPC::PlatformFileForTransit output_file) {
  base::File emf_file = IPC::PlatformFileForTransitToFile(output_file);
  float scale_factor = 1.0f;
  bool success =
      RenderPdfPageToMetafile(page_number, emf_file.Pass(), &scale_factor);
  Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone(
      success, scale_factor));
}

void PrintingHandlerWin::OnRenderPDFPagesToMetafileStop() {
  ReleaseProcessIfNeeded();
}

int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
  if (!g_pdf_lib.Get().IsValid())
    return 0;

  int64 length64 = pdf_file.GetLength();
  if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
    return 0;
  int length = static_cast<int>(length64);

  pdf_data_.resize(length);
  if (length != pdf_file.Read(0, pdf_data_.data(), pdf_data_.size()))
    return 0;

  int total_page_count = 0;
  if (!g_pdf_lib.Get().GetPDFDocInfo(
          &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) {
    return 0;
  }
  return total_page_count;
}

bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
                                                 base::File output_file,
                                                 float* scale_factor) {
  printing::Emf metafile;
  metafile.Init();

  // We need to scale down DC to fit an entire page into DC available area.
  // Current metafile is based on screen DC and have current screen size.
  // Writing outside of those boundaries will result in the cut-off output.
  // On metafiles (this is the case here), scaling down will still record
  // original coordinates and we'll be able to print in full resolution.
  // Before playback we'll need to counter the scaling up that will happen
  // in the service (print_system_win.cc).
  *scale_factor =
      gfx::CalculatePageScale(metafile.context(),
                              pdf_rendering_settings_.area().right(),
                              pdf_rendering_settings_.area().bottom());
  gfx::ScaleDC(metafile.context(), *scale_factor);

  // The underlying metafile is of type Emf and ignores the arguments passed
  // to StartPage.
  metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
  if (!g_pdf_lib.Get().RenderPDFPageToDC(
          &pdf_data_.front(),
          pdf_data_.size(),
          page_number,
          metafile.context(),
          pdf_rendering_settings_.dpi(),
          pdf_rendering_settings_.area().x(),
          pdf_rendering_settings_.area().y(),
          pdf_rendering_settings_.area().width(),
          pdf_rendering_settings_.area().height(),
          true,
          false,
          true,
          true,
          pdf_rendering_settings_.autorotate())) {
    return false;
  }
  metafile.FinishPage();
  metafile.FinishDocument();
  return metafile.SaveTo(&output_file);
}
<|endoftext|>


<commit_before>#include "omp.h"

 inline
 kth_cv_omp::kth_cv_omp(const std::string in_path,
		const std::string in_actionNames,
		const field<std::string> in_all_people,
		const int in_scale_factor,
		const int in_shift,
		const int in_scene, //only for kth
		const int in_segment_length,
		const int in_dim
 ):path(in_path), actionNames(in_actionNames), all_people (in_all_people), scale_factor(in_scale_factor), shift(in_shift), total_scenes(in_scene), segment_length(in_segment_length), dim(in_dim)
 {
   actions.load( actionNames );

 }

 // Log-Euclidean Distance
 inline
 void
 kth_cv_omp::logEucl()
 {

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   float acc;
   acc = 0;

   int n_test = n_peo*n_actions*total_scenes - 1; // - person13_handclapping_d3
   vec real_labels;
   vec est_labels;
   field<std::string> test_video_list(n_test);

   real_labels.zeros(n_test);
   est_labels.zeros(n_test);

   int k=0;

   for (int sc = 1; sc<=total_scenes; ++sc) //scene
   {
     for (int pe = 0; pe< n_peo; ++pe)
     {
       for (int act=0; act<n_actions; ++act)
       {
	 if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	 {

	   //load number of segments

	   vec total_seg;
	   int num_s;
	   std::stringstream load_sub_path;
	   std::stringstream load_num_seg;

	   load_sub_path  << path << "/kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	   load_num_seg << load_sub_path.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);
	   uvec  est_lab_segm;
	   est_lab_segm.zeros(num_s);
	   vec count = zeros<vec>( n_actions );

	   for (int s=0; s<num_s; ++s)
	   {
	     std::stringstream load_cov_seg;
	     load_cov_seg << load_sub_path.str() << "/LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     //cout << "LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5" << endl;
	     //debe devolver el est_labe de ese segmento
	     est_lab_segm(s) = logEucl_one_seg_est_lab( pe, load_sub_path.str(),  load_cov_seg.str());
	     count( est_lab_segm(s) )++;
	     //getchar();
	   }

	   uword  index_video;
	   double max_val = count.max(index_video);
	   //est_lab_segm.t().print("est_lab_segm");
	   cout << "This video is " << actions(act) << " and was classified as class: " << actions(index_video ) << endl;

	   real_labels(k) = act;
	   est_labels(k) = index_video;
	   test_video_list(k) = load_sub_path.str();

	   real_labels.save("Log_Eucl_real_labels.dat", raw_ascii);
	   est_labels.save("Log_Eucl_est_labels.dat", raw_ascii);
	   test_video_list.save("Log_Eucl_test_video_list.dat", raw_ascii);
	   k++;

	   if (index_video == act)  {
	     acc++;

	   }

	   //getchar();
	 }
       }

     }
   }

   cout << "Performance: " << acc*100/n_test << " %" << endl;

 }

 inline
 uword
 kth_cv_omp::logEucl_one_seg_est_lab(int pe_test, std::string load_sub_path, std::string segm_name)
 {
   //wall_clock timer;
   //timer.tic();

   mat logMtest_cov;
   logMtest_cov.load(segm_name);

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   double dist, tmp_dist;
   tmp_dist = datum::inf;

   double est_lab;
   //cout << "Comparing with person ";

   for (int pe_tr = 0; pe_tr< n_peo; ++pe_tr)
   {
     if (pe_tr!= pe_test)
     {

       //cout << " " << all_people (pe_tr);

       for (int sc = 1; sc<=total_scenes; ++sc) //scene
       {
	 for (int act=0; act<n_actions; ++act)
	 {
	   vec total_seg;
	   int num_s;
	   std::stringstream load_num_seg;
	   load_num_seg << load_sub_path << "/num_seg_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);

	   vec dist_segm_s = zeros<vec> (num_s);

	   omp_set_num_threads(6);
	   #pragma omp for
	   for (int s_tr=0; s_tr<num_s; ++s_tr)
	   {
	     std::stringstream load_cov_seg_tr;
	     load_cov_seg_tr << load_sub_path << "/LogMcov_seg" << s_tr << "_" << all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     //cout << "Comparing with cov_seg" << s_tr << "_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5" << endl;
	     mat logMtrain_cov;
	     logMtrain_cov.load( load_cov_seg_tr.str() );

	     //logMtest_cov.print("logMtest_cov");
	     //train_cov.print("train_cov");

	     dist_segm_s(s_tr) = norm( logMtest_cov - logMtrain_cov, "fro");

	     //cout << "dist " << dis
	     //cout << "Press a key" << endl;
	     //getchar();
	   }
	   cout << omp_get_thread_num() << endl;
	   #pragma omp barrier

	   dist_segm_s.t().print("dist_segm_s");
	   getchar();
	 }
       }
     }
   }

   //double n = timer.toc();
   //cout << "number of seconds: " << n << endl;
   //cout << " est_lab "<< est_lab << endl << endl;
   //getchar();
   return est_lab;

 }

 //DO IT
 // Stein Divergence

 inline
 void
 kth_cv_omp::SteinDiv()
 {

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   float acc;
   acc = 0;

      int n_test = n_peo*n_actions*total_scenes - 1; // - person13_handclapping_d3

   vec real_labels;
   vec est_labels;
   field<std::string> test_video_list(n_test);

   real_labels.zeros(n_test);
   est_labels.zeros(n_test);

   int k=0;

   for (int sc = 1; sc<=total_scenes; ++sc) //scene
   {
     for (int pe = 0; pe< n_peo; ++pe)
     {
       for (int act=0; act<n_actions; ++act)
       {
	 if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	 {
	   //load number of segments

	   vec total_seg;
	   int num_s;
	   std::stringstream load_sub_path;
	   std::stringstream load_num_seg;

	   load_sub_path  << path << "/kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	   load_num_seg << load_sub_path.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);
	   uvec  est_lab_segm;
	   est_lab_segm.zeros(num_s);
	   vec count = zeros<vec>( n_actions );

	   for (int s=0; s<num_s; ++s)
	   {
	     std::stringstream load_cov_seg;
	     load_cov_seg << load_sub_path.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     est_lab_segm(s) = SteinDiv_one_seg_est_lab( pe, load_sub_path.str(),  load_cov_seg.str());
	     count( est_lab_segm(s) )++;
	     //getchar();
	   }

	   uword  index_video;
	   double max_val = count.max(index_video);
	   //est_lab_segm.t().print("est_lab_segm");
	   cout << "This video is " << actions(act) << " and was classified as class: " << actions(index_video ) << endl;

	   real_labels(k) = act;
	   est_labels(k) = index_video;
	   test_video_list(k) = load_sub_path.str();

	   real_labels.save("Stein_div_real_labels.dat", raw_ascii);
	   est_labels.save("Stein_div__est_labels.dat", raw_ascii);
	   test_video_list.save("Stein_div_test_video_list.dat", raw_ascii);
	   k++;

	   if (index_video == act)  {
	     acc++;

	   }

	   //getchar();
	 }

       }
     }
   }

   cout << "Performance: " << acc*100/n_test << " %" << endl;

 }

 //DO IT!!!!!!!!!
 inline
 uword
 kth_cv_omp::SteinDiv_one_seg_est_lab(int pe_test, std::string load_sub_path, std::string segm_name)
 {
   //wall_clock timer;
   //timer.tic();

   mat test_cov;
   test_cov.load(segm_name);

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   double dist_stein, tmp_dist;
   tmp_dist = datum::inf;

   double est_lab;
   //cout << "Comparing with person ";

   for (int pe_tr = 0; pe_tr< n_peo; ++pe_tr)
   {
     if (pe_tr!= pe_test)
     {

       //cout << " " << all_people (pe_tr);

       for (int sc = 1; sc<=total_scenes; ++sc) //scene
       {
	 for (int act=0; act<n_actions; ++act)
	 {
	   vec total_seg;
	   int num_s;
	   std::stringstream load_num_seg;
	   load_num_seg << load_sub_path << "/num_seg_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);

	   for (int s_tr=0; s_tr<num_s; ++s_tr)
	   {
	     std::stringstream load_cov_seg_tr;
	     load_cov_seg_tr << load_sub_path << "/cov_seg" << s_tr << "_" << all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     mat train_cov;
	     train_cov.load( load_cov_seg_tr.str() );

	     //Esto vienen de PartI4. No recuerdo mas :(
	     double det_op1 = det( diagmat( (test_cov + train_cov)/2 ) );
	     double det_op2 = det( diagmat( ( test_cov%train_cov ) ) );
	     dist_stein =  log( det_op1 ) - 0.5*log( det_op2 ) ;

	     //dist_stein = norm( logMtest_cov - logMtrain_cov, "fro");

	     //cout << "dist " << dist << endl;

	     if (dist_stein < tmp_dist)
	     {
	       //cout << "Es menor" << endl;
	       tmp_dist = dist_stein;
	       est_lab = act;
	     }
	     //cout << "Press a key" << endl;
	     //getchar();
	   }
	 }
       }
     }
   }

   //double n = timer.toc();
   //cout << "number of seconds: " << n << endl;
   //cout << " est_lab "<< est_lab << endl << endl;
   //getchar();
   return est_lab;

 }

 <commit_msg>try oPenMP<commit_after>#include "omp.h"

 inline
 kth_cv_omp::kth_cv_omp(const std::string in_path,
		const std::string in_actionNames,
		const field<std::string> in_all_people,
		const int in_scale_factor,
		const int in_shift,
		const int in_scene, //only for kth
		const int in_segment_length,
		const int in_dim
 ):path(in_path), actionNames(in_actionNames), all_people (in_all_people), scale_factor(in_scale_factor), shift(in_shift), total_scenes(in_scene), segment_length(in_segment_length), dim(in_dim)
 {
   actions.load( actionNames );

 }

 // Log-Euclidean Distance
 inline
 void
 kth_cv_omp::logEucl()
 {

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   float acc;
   acc = 0;

   int n_test = n_peo*n_actions*total_scenes - 1; // - person13_handclapping_d3
   vec real_labels;
   vec est_labels;
   field<std::string> test_video_list(n_test);

   real_labels.zeros(n_test);
   est_labels.zeros(n_test);

   int k=0;

   for (int sc = 1; sc<=total_scenes; ++sc) //scene
   {
     for (int pe = 0; pe< n_peo; ++pe)
     {
       for (int act=0; act<n_actions; ++act)
       {
	 if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	 {

	   //load number of segments

	   vec total_seg;
	   int num_s;
	   std::stringstream load_sub_path;
	   std::stringstream load_num_seg;

	   load_sub_path  << path << "/kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	   load_num_seg << load_sub_path.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);
	   uvec  est_lab_segm;
	   est_lab_segm.zeros(num_s);
	   vec count = zeros<vec>( n_actions );

	   for (int s=0; s<num_s; ++s)
	   {
	     std::stringstream load_cov_seg;
	     load_cov_seg << load_sub_path.str() << "/LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     //cout << "LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5" << endl;
	     //debe devolver el est_labe de ese segmento
	     est_lab_segm(s) = logEucl_one_seg_est_lab( pe, load_sub_path.str(),  load_cov_seg.str());
	     count( est_lab_segm(s) )++;
	     //getchar();
	   }

	   uword  index_video;
	   double max_val = count.max(index_video);
	   //est_lab_segm.t().print("est_lab_segm");
	   cout << "This video is " << actions(act) << " and was classified as class: " << actions(index_video ) << endl;

	   real_labels(k) = act;
	   est_labels(k) = index_video;
	   test_video_list(k) = load_sub_path.str();

	   real_labels.save("Log_Eucl_real_labels.dat", raw_ascii);
	   est_labels.save("Log_Eucl_est_labels.dat", raw_ascii);
	   test_video_list.save("Log_Eucl_test_video_list.dat", raw_ascii);
	   k++;

	   if (index_video == act)  {
	     acc++;

	   }

	   //getchar();
	 }
       }

     }
   }

   cout << "Performance: " << acc*100/n_test << " %" << endl;

 }

 inline
 uword
 kth_cv_omp::logEucl_one_seg_est_lab(int pe_test, std::string load_sub_path, std::string segm_name)
 {
   //wall_clock timer;
   //timer.tic();

   mat logMtest_cov;
   logMtest_cov.load(segm_name);

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   double dist, tmp_dist;
   tmp_dist = datum::inf;

   double est_lab;
   //cout << "Comparing with person ";

   for (int pe_tr = 0; pe_tr< n_peo; ++pe_tr)
   {
     if (pe_tr!= pe_test)
     {

       //cout << " " << all_people (pe_tr);

       for (int sc = 1; sc<=total_scenes; ++sc) //scene
       {
	 for (int act=0; act<n_actions; ++act)
	 {
	   vec total_seg;
	   int num_s;
	   std::stringstream load_num_seg;
	   load_num_seg << load_sub_path << "/num_seg_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);

	   vec dist_segm_s = zeros<vec> (num_s);

	   omp_set_num_threads(6);
	   cout << omp_get_thread_num() << endl;
	   #pragma omp for
	   for (int s_tr=0; s_tr<num_s; ++s_tr)
	   {
	     std::stringstream load_cov_seg_tr;
	     load_cov_seg_tr << load_sub_path << "/LogMcov_seg" << s_tr << "_" << all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     //cout << "Comparing with cov_seg" << s_tr << "_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5" << endl;
	     mat logMtrain_cov;
	     logMtrain_cov.load( load_cov_seg_tr.str() );

	     //logMtest_cov.print("logMtest_cov");
	     //train_cov.print("train_cov");

	     dist_segm_s(s_tr) = norm( logMtest_cov - logMtrain_cov, "fro");

	     //cout << "dist " << dis
	     //cout << "Press a key" << endl;
	     //getchar();
	   }

	   #pragma omp barrier

	   dist_segm_s.t().print("dist_segm_s");
	   getchar();
	 }
       }
     }
   }

   //double n = timer.toc();
   //cout << "number of seconds: " << n << endl;
   //cout << " est_lab "<< est_lab << endl << endl;
   //getchar();
   return est_lab;

 }

 //DO IT
 // Stein Divergence

 inline
 void
 kth_cv_omp::SteinDiv()
 {

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   float acc;
   acc = 0;

      int n_test = n_peo*n_actions*total_scenes - 1; // - person13_handclapping_d3

   vec real_labels;
   vec est_labels;
   field<std::string> test_video_list(n_test);

   real_labels.zeros(n_test);
   est_labels.zeros(n_test);

   int k=0;

   for (int sc = 1; sc<=total_scenes; ++sc) //scene
   {
     for (int pe = 0; pe< n_peo; ++pe)
     {
       for (int act=0; act<n_actions; ++act)
       {
	 if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	 {
	   //load number of segments

	   vec total_seg;
	   int num_s;
	   std::stringstream load_sub_path;
	   std::stringstream load_num_seg;

	   load_sub_path  << path << "/kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	   load_num_seg << load_sub_path.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);
	   uvec  est_lab_segm;
	   est_lab_segm.zeros(num_s);
	   vec count = zeros<vec>( n_actions );

	   for (int s=0; s<num_s; ++s)
	   {
	     std::stringstream load_cov_seg;
	     load_cov_seg << load_sub_path.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     est_lab_segm(s) = SteinDiv_one_seg_est_lab( pe, load_sub_path.str(),  load_cov_seg.str());
	     count( est_lab_segm(s) )++;
	     //getchar();
	   }

	   uword  index_video;
	   double max_val = count.max(index_video);
	   //est_lab_segm.t().print("est_lab_segm");
	   cout << "This video is " << actions(act) << " and was classified as class: " << actions(index_video ) << endl;

	   real_labels(k) = act;
	   est_labels(k) = index_video;
	   test_video_list(k) = load_sub_path.str();

	   real_labels.save("Stein_div_real_labels.dat", raw_ascii);
	   est_labels.save("Stein_div__est_labels.dat", raw_ascii);
	   test_video_list.save("Stein_div_test_video_list.dat", raw_ascii);
	   k++;

	   if (index_video == act)  {
	     acc++;

	   }

	   //getchar();
	 }

       }
     }
   }

   cout << "Performance: " << acc*100/n_test << " %" << endl;

 }

 //DO IT!!!!!!!!!
 inline
 uword
 kth_cv_omp::SteinDiv_one_seg_est_lab(int pe_test, std::string load_sub_path, std::string segm_name)
 {
   //wall_clock timer;
   //timer.tic();

   mat test_cov;
   test_cov.load(segm_name);

   int n_actions = actions.n_rows;
   int n_peo =  all_people.n_rows;

   double dist_stein, tmp_dist;
   tmp_dist = datum::inf;

   double est_lab;
   //cout << "Comparing with person ";

   for (int pe_tr = 0; pe_tr< n_peo; ++pe_tr)
   {
     if (pe_tr!= pe_test)
     {

       //cout << " " << all_people (pe_tr);

       for (int sc = 1; sc<=total_scenes; ++sc) //scene
       {
	 for (int act=0; act<n_actions; ++act)
	 {
	   vec total_seg;
	   int num_s;
	   std::stringstream load_num_seg;
	   load_num_seg << load_sub_path << "/num_seg_"<< all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".dat";
	   total_seg.load( load_num_seg.str());
	   num_s = total_seg(0);

	   for (int s_tr=0; s_tr<num_s; ++s_tr)
	   {
	     std::stringstream load_cov_seg_tr;
	     load_cov_seg_tr << load_sub_path << "/cov_seg" << s_tr << "_" << all_people (pe_tr) << "_" << actions(act) << "_dim" << dim  << ".h5";

	     mat train_cov;
	     train_cov.load( load_cov_seg_tr.str() );

	     //Esto vienen de PartI4. No recuerdo mas :(
	     double det_op1 = det( diagmat( (test_cov + train_cov)/2 ) );
	     double det_op2 = det( diagmat( ( test_cov%train_cov ) ) );
	     dist_stein =  log( det_op1 ) - 0.5*log( det_op2 ) ;

	     //dist_stein = norm( logMtest_cov - logMtrain_cov, "fro");

	     //cout << "dist " << dist << endl;

	     if (dist_stein < tmp_dist)
	     {
	       //cout << "Es menor" << endl;
	       tmp_dist = dist_stein;
	       est_lab = act;
	     }
	     //cout << "Press a key" << endl;
	     //getchar();
	   }
	 }
       }
     }
   }

   //double n = timer.toc();
   //cout << "number of seconds: " << n << endl;
   //cout << " est_lab "<< est_lab << endl << endl;
   //getchar();
   return est_lab;

 }

 <|endoftext|>


<commit_before>#include "pch.h"
#include "httprequest_service.h"
#include "service_manager.h"
#include "main/memory_stream.h"
#include "curl/curl.h"

#ifdef __EMSCRIPTEN__
extern "C"
{
    extern int emscripten_async_wget3_data(const char* url, const char* requesttype, const char* param, const char* additionalHeader, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
}
#endif

static char errorBuffer[CURL_ERROR_SIZE];
const char * HTTP_REQUEST_SERVICE_QUEUE = "HTTPRequestServiceQueue";

HTTPRequestService::HTTPRequestService(const ServiceManager * manager)
    : Service(manager)
    , _curl(NULL)
    , _taskQueueService(NULL)
{
}

HTTPRequestService::~HTTPRequestService()
{
}

bool HTTPRequestService::onPreInit()
{
    _taskQueueService = _manager->findService<TaskQueueService>();
    _taskQueueService->createQueue(HTTP_REQUEST_SERVICE_QUEUE);

#ifndef __EMSCRIPTEN__
    _curl = curl_easy_init();
    if (_curl)
    {
        curl_easy_setopt(_curl, CURLOPT_USERAGENT, gameplay::Game::getInstance()->getUserAgentString());
        //curl_easy_setopt( _curl, CURLOPT_DNS_CACHE_TIMEOUT, -1 );
        curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(_curl, CURLOPT_TIMEOUT, 120);
        curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, errorBuffer);
        curl_easy_setopt(_curl, CURLOPT_TCP_NODELAY, 1);  // make sure packets are sent immediately
        curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, &writeFunction);
        curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1);
        curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0);
    }
#endif

    return true;
}

bool HTTPRequestService::onInit()
{
    return true;
}

bool HTTPRequestService::onTick()
{
    // service has no work to do every frame
    return true;
}

bool HTTPRequestService::onShutdown()
{
    if (_taskQueueService)
        _taskQueueService->removeQueue(HTTP_REQUEST_SERVICE_QUEUE);

#ifndef __EMSCRIPTEN__
    if (_curl)
        curl_easy_cleanup(_curl);
#endif

    return true;
}

int HTTPRequestService::makeRequestAsync(const Request& request, bool headOnly)
{
    // note: request is copied by value
    return _taskQueueService->addWorkItem(HTTP_REQUEST_SERVICE_QUEUE, std::bind(&HTTPRequestService::sendRequest, this, request, headOnly));
}

void HTTPRequestService::makeRequestSync(const Request& request, bool headOnly)
{
    sendRequest(request, headOnly);
}

static int __requestCount = 0;
void HTTPRequestService::requestLoadCallback(unsigned, void * arg, void *buf, unsigned length)
{
    Request * request = reinterpret_cast<Request *>(arg);
    request->responseCallback(CURLE_OK, MemoryStream::create(buf, length), NULL, 200);
    delete request;

    __requestCount--;
}

void HTTPRequestService::requestErrorCallback(unsigned, void *arg, int errorCode, const char * status)
{
    Request * request = reinterpret_cast<Request *>(arg);
    GP_LOG("Failed to perform HTTP request to %s: error %d %s", request->url.c_str(), errorCode, status);
    request->responseCallback(-1, NULL, status, errorCode);  // there is no 'curl' error for emscripten callback, errorCode is HTTP status code
    delete request;

    __requestCount--;
}

void HTTPRequestService::requestProgressCallback(unsigned, void * arg, int dlnow, int dltotal)
{
    Request * request = reinterpret_cast<Request *>(arg);
    request->progressCallback(static_cast<uint64_t>(dltotal), static_cast<uint64_t>(dlnow), 0, 0);
}

int progressFunction(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
    HTTPRequestService::Request * request = reinterpret_cast<HTTPRequestService::Request *>(userp);
    GP_ASSERT(request->progressCallback);
    return request->progressCallback(static_cast<uint64_t>(dltotal), static_cast<uint64_t>(dlnow), static_cast<uint64_t>(ultotal), static_cast<uint64_t>(ulnow));
}

bool HTTPRequestService::hasActiveEmscriptenHTTPRequest() const
{
    return __requestCount > 0;
}

void HTTPRequestService::sendRequest(const Request& request, bool headOnly)
{
#ifdef _DEBUG
    GP_LOG("Sending HTTP request: %s, POST: %s", request.url.c_str(), request.postPayload.c_str());
#endif

    // make sure curl is used only for one thread in any moment
    std::unique_lock<std::mutex> lock(_requestProcessingMutex);

#ifndef __EMSCRIPTEN__
    MemoryStream * response = MemoryStream::create();

    curl_easy_setopt(_curl, CURLOPT_URL, request.url.c_str());
    curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, request.postPayload.c_str());
    curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, request.postPayload.size());
    curl_easy_setopt(_curl, CURLOPT_POST, request.postPayload.empty() ? 0 : 1);
    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, request.progressCallback ? 0 : 1);
    curl_easy_setopt(_curl, CURLOPT_XFERINFOFUNCTION, &progressFunction);
    curl_easy_setopt(_curl, CURLOPT_XFERINFODATA, &request);
    curl_easy_setopt(_curl, CURLOPT_HEADER, headOnly ? 1 : 0);
    curl_easy_setopt(_curl, CURLOPT_NOBODY, headOnly ? 1 : 0);

    struct curl_slist *list = NULL;
    if (!request.headers.empty())
    {
        for (auto& h : request.headers)
            list = curl_slist_append(list, (h.first + ": " + h.second).c_str());
    }
    curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, list);

    CURLcode res = curl_easy_perform(_curl);
    curl_slist_free_all(list);

    long httpResponseCode = 0;
    curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &httpResponseCode);

    if (res != CURLE_OK)
        GP_LOG("Failed to perform HTTP request: error %d - %s", res, request.url.c_str());

    // response is copied by value since callback is invoked on main thread
    _taskQueueService->runOnMainThread([=]() { response->rewind(); request.responseCallback(res, response, curl_easy_strerror(res), httpResponseCode); delete response; });

#else

    // HEAD request are currently not supported
    if (headOnly)
    {
        request.responseCallback(-1, NULL, "Unsupported", 404);
        return;
    }

    std::string additionalHeaders;  // headers in JSON format
    if (!request.headers.empty())
    {
        additionalHeaders += "{";
        for (auto& h : request.headers)
        {
            additionalHeaders += "\"";
            additionalHeaders += h.first;
            additionalHeaders += "\":\"";
            additionalHeaders += h.second;
            additionalHeaders += "\",";
        }
        additionalHeaders.pop_back();
        additionalHeaders += "}";
    }

    Request * newRequest = new Request(request);

    __requestCount++;
    emscripten_async_wget3_data(request.url.c_str(), request.postPayload.empty() ? "GET" : "POST", request.postPayload.c_str(), request.postPayload.size(),
        additionalHeaders.c_str(), newRequest, true, &HTTPRequestService::requestLoadCallback, &HTTPRequestService::requestErrorCallback,
        request.progressCallback ? &HTTPRequestService::requestProgressCallback : NULL);

#endif
}

size_t HTTPRequestService::writeFunction(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realSize = size * nmemb;
    gameplay::Stream * response = reinterpret_cast<gameplay::Stream *>(userp);

    response->write(contents, size, nmemb);

    return realSize;
}

const char * HTTPRequestService::getTaskQueueName()
{
    return HTTP_REQUEST_SERVICE_QUEUE;
}<commit_msg>fixed compilation on emscripten<commit_after>#include "pch.h"
#include "httprequest_service.h"
#include "service_manager.h"
#include "main/memory_stream.h"
#include "curl/curl.h"

#ifdef __EMSCRIPTEN__
extern "C"
{
    extern int emscripten_async_wget3_data(const char* url, const char* requesttype, const char* data, int dataSize, const char* additionalHeader, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
}
#endif

static char errorBuffer[CURL_ERROR_SIZE];
const char * HTTP_REQUEST_SERVICE_QUEUE = "HTTPRequestServiceQueue";

HTTPRequestService::HTTPRequestService(const ServiceManager * manager)
    : Service(manager)
    , _curl(NULL)
    , _taskQueueService(NULL)
{
}

HTTPRequestService::~HTTPRequestService()
{
}

bool HTTPRequestService::onPreInit()
{
    _taskQueueService = _manager->findService<TaskQueueService>();
    _taskQueueService->createQueue(HTTP_REQUEST_SERVICE_QUEUE);

#ifndef __EMSCRIPTEN__
    _curl = curl_easy_init();
    if (_curl)
    {
        curl_easy_setopt(_curl, CURLOPT_USERAGENT, gameplay::Game::getInstance()->getUserAgentString());
        //curl_easy_setopt( _curl, CURLOPT_DNS_CACHE_TIMEOUT, -1 );
        curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(_curl, CURLOPT_TIMEOUT, 120);
        curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, errorBuffer);
        curl_easy_setopt(_curl, CURLOPT_TCP_NODELAY, 1);  // make sure packets are sent immediately
        curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, &writeFunction);
        curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1);
        curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0);
    }
#endif

    return true;
}

bool HTTPRequestService::onInit()
{
    return true;
}

bool HTTPRequestService::onTick()
{
    // service has no work to do every frame
    return true;
}

bool HTTPRequestService::onShutdown()
{
    if (_taskQueueService)
        _taskQueueService->removeQueue(HTTP_REQUEST_SERVICE_QUEUE);

#ifndef __EMSCRIPTEN__
    if (_curl)
        curl_easy_cleanup(_curl);
#endif

    return true;
}

int HTTPRequestService::makeRequestAsync(const Request& request, bool headOnly)
{
    // note: request is copied by value
    return _taskQueueService->addWorkItem(HTTP_REQUEST_SERVICE_QUEUE, std::bind(&HTTPRequestService::sendRequest, this, request, headOnly));
}

void HTTPRequestService::makeRequestSync(const Request& request, bool headOnly)
{
    sendRequest(request, headOnly);
}

static int __requestCount = 0;
void HTTPRequestService::requestLoadCallback(unsigned, void * arg, void *buf, unsigned length)
{
    Request * request = reinterpret_cast<Request *>(arg);
    request->responseCallback(CURLE_OK, MemoryStream::create(buf, length), NULL, 200);
    delete request;

    __requestCount--;
}

void HTTPRequestService::requestErrorCallback(unsigned, void *arg, int errorCode, const char * status)
{
    Request * request = reinterpret_cast<Request *>(arg);
    GP_LOG("Failed to perform HTTP request to %s: error %d %s", request->url.c_str(), errorCode, status);
    request->responseCallback(-1, NULL, status, errorCode);  // there is no 'curl' error for emscripten callback, errorCode is HTTP status code
    delete request;

    __requestCount--;
}

void HTTPRequestService::requestProgressCallback(unsigned, void * arg, int dlnow, int dltotal)
{
    Request * request = reinterpret_cast<Request *>(arg);
    request->progressCallback(static_cast<uint64_t>(dltotal), static_cast<uint64_t>(dlnow), 0, 0);
}

int progressFunction(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
    HTTPRequestService::Request * request = reinterpret_cast<HTTPRequestService::Request *>(userp);
    GP_ASSERT(request->progressCallback);
    return request->progressCallback(static_cast<uint64_t>(dltotal), static_cast<uint64_t>(dlnow), static_cast<uint64_t>(ultotal), static_cast<uint64_t>(ulnow));
}

bool HTTPRequestService::hasActiveEmscriptenHTTPRequest() const
{
    return __requestCount > 0;
}

void HTTPRequestService::sendRequest(const Request& request, bool headOnly)
{
#ifdef _DEBUG
    GP_LOG("Sending HTTP request: %s, POST: %s", request.url.c_str(), request.postPayload.c_str());
#endif

    // make sure curl is used only for one thread in any moment
    std::unique_lock<std::mutex> lock(_requestProcessingMutex);

#ifndef __EMSCRIPTEN__
    MemoryStream * response = MemoryStream::create();

    curl_easy_setopt(_curl, CURLOPT_URL, request.url.c_str());
    curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, request.postPayload.c_str());
    curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, request.postPayload.size());
    curl_easy_setopt(_curl, CURLOPT_POST, request.postPayload.empty() ? 0 : 1);
    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, request.progressCallback ? 0 : 1);
    curl_easy_setopt(_curl, CURLOPT_XFERINFOFUNCTION, &progressFunction);
    curl_easy_setopt(_curl, CURLOPT_XFERINFODATA, &request);
    curl_easy_setopt(_curl, CURLOPT_HEADER, headOnly ? 1 : 0);
    curl_easy_setopt(_curl, CURLOPT_NOBODY, headOnly ? 1 : 0);

    struct curl_slist *list = NULL;
    if (!request.headers.empty())
    {
        for (auto& h : request.headers)
            list = curl_slist_append(list, (h.first + ": " + h.second).c_str());
    }
    curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, list);

    CURLcode res = curl_easy_perform(_curl);
    curl_slist_free_all(list);

    long httpResponseCode = 0;
    curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &httpResponseCode);

    if (res != CURLE_OK)
        GP_LOG("Failed to perform HTTP request: error %d - %s", res, request.url.c_str());

    // response is copied by value since callback is invoked on main thread
    _taskQueueService->runOnMainThread([=]() { response->rewind(); request.responseCallback(res, response, curl_easy_strerror(res), httpResponseCode); delete response; });

#else

    // HEAD request are currently not supported
    if (headOnly)
    {
        request.responseCallback(-1, NULL, "Unsupported", 404);
        return;
    }

    std::string additionalHeaders;  // headers in JSON format
    if (!request.headers.empty())
    {
        additionalHeaders += "{";
        for (auto& h : request.headers)
        {
            additionalHeaders += "\"";
            additionalHeaders += h.first;
            additionalHeaders += "\":\"";
            additionalHeaders += h.second;
            additionalHeaders += "\",";
        }
        additionalHeaders.pop_back();
        additionalHeaders += "}";
    }

    Request * newRequest = new Request(request);

    __requestCount++;
    emscripten_async_wget3_data(request.url.c_str(), request.postPayload.empty() ? "GET" : "POST", request.postPayload.c_str(), request.postPayload.size(),
        additionalHeaders.c_str(), newRequest, true, &HTTPRequestService::requestLoadCallback, &HTTPRequestService::requestErrorCallback,
        request.progressCallback ? &HTTPRequestService::requestProgressCallback : NULL);

#endif
}

size_t HTTPRequestService::writeFunction(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realSize = size * nmemb;
    gameplay::Stream * response = reinterpret_cast<gameplay::Stream *>(userp);

    response->write(contents, size, nmemb);

    return realSize;
}

const char * HTTPRequestService::getTaskQueueName()
{
    return HTTP_REQUEST_SERVICE_QUEUE;
}<|endoftext|>