<commit_before>// Copyright (c) 2011 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 "base/bind.h"
#include "base/file_path.h"
#include "base/stl_util.h"
#include "base/test/thread_test_helper.h"
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/ui/ui_test.h"
#include "content/browser/browser_thread.h"

class FastShutdown : public UITest {
 protected:
  FastShutdown()
      : db_thread_(BrowserThread::DB),
        io_thread_(BrowserThread::IO),
        thread_helper_(new base::ThreadTestHelper(
            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))) {
    dom_automation_enabled_ = true;
  }

  void Init() {
    ASSERT_TRUE(db_thread_.Start());
    ASSERT_TRUE(io_thread_.Start());
    // Cache this, so that we can still access it after the browser exits.
    user_data_dir_ = user_data_dir();
  }

  // Looks for the given |cookie| in the cookie store. If it exists, puts the
  // cookie's value in |cookie_value| and sets |has_cookie| to true. Sets
  // |has_cookie| to false if the |cookie| wasn't found.
  void GetCookie(const net::CookieMonster::CanonicalCookie& cookie,
                 bool* has_cookie, std::string* cookie_value) {
    scoped_refptr<SQLitePersistentCookieStore> cookie_store(
       new SQLitePersistentCookieStore(
           user_data_dir_.AppendASCII(chrome::kInitialProfile)
                         .Append(chrome::kCookieFilename)));
    std::vector<net::CookieMonster::CanonicalCookie*> cookies;
    ASSERT_TRUE(cookie_store->Load(
        base::Bind(&FastShutdown::LoadCookiesCallback,
                   base::Unretained(this),
                   MessageLoop::current(),
                   base::Unretained(&cookies))));
    // Will receive a QuitTask when LoadCookiesCallback is invoked.
    MessageLoop::current()->Run();
    *has_cookie = false;
    for (size_t i = 0; i < cookies.size(); ++i) {
      if (cookies[i]->IsEquivalent(cookie)) {
        *has_cookie = true;
        *cookie_value = cookies[i]->Value();
      }
    }
    cookie_store = NULL;
    ASSERT_TRUE(thread_helper_->Run());
    STLDeleteElements(&cookies);
  }

 private:
  void LoadCookiesCallback(
      MessageLoop* to_notify,
      std::vector<net::CookieMonster::CanonicalCookie*>* cookies,
      const std::vector<net::CookieMonster::CanonicalCookie*>& cookies_get) {
    *cookies = cookies_get;
    to_notify->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  BrowserThread db_thread_;
  BrowserThread io_thread_;
  scoped_refptr<base::ThreadTestHelper> thread_helper_;
  FilePath user_data_dir_;

  DISALLOW_COPY_AND_ASSIGN(FastShutdown);
};

// This tests for a previous error where uninstalling an onbeforeunload handler
// would enable fast shutdown even if an onunload handler still existed.
TEST_F(FastShutdown, SlowTermination) {
  Init();

  // Only the name, domain and path are used in IsEquivalent(), so we don't care
  // what the other fields have.
  net::CookieMonster::CanonicalCookie cookie(
      GURL(),        // url
      "unloaded",    // name
      "",            // value
      "",            // domain
      "/",           // path
      "",            // mac_key
      "",            // mac_algorithm
      base::Time(),  // creation
      base::Time(),  // expiration
      base::Time(),  // last_access
      false,         // secure
      false,         // httponly
      false);        // has_expires

  // This page has an unload handler.
  const FilePath dir(FILE_PATH_LITERAL("fast_shutdown"));
  const FilePath file(FILE_PATH_LITERAL("on_unloader.html"));

  NavigateToURL(ui_test_utils::GetTestUrl(dir, file));

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));

  // This page has a beforeunload handler.
  ASSERT_TRUE(browser->GetTab(0)->ExecuteJavaScript(
      "open('on_before_unloader.html')"));
  WaitUntilTabCount(2);

  // Close the tab, removing the one and only beforeunload handler.
  ASSERT_TRUE(browser->GetTab(1)->Close(true));

  // Close the browser. This should launch the unload handler, which sets a
  // cookie that's stored to disk.
  QuitBrowser();

  bool has_cookie = false;
  std::string cookie_value;
  // Read the cookie and check that it has the expected value.
  GetCookie(cookie, &has_cookie, &cookie_value);
  EXPECT_TRUE(has_cookie);
  EXPECT_EQ("ohyeah", cookie_value);
}
<commit_msg>Mark FastShutdown.SlowTermination flaky.<commit_after>// Copyright (c) 2011 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 "base/bind.h"
#include "base/file_path.h"
#include "base/stl_util.h"
#include "base/test/thread_test_helper.h"
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/ui/ui_test.h"
#include "content/browser/browser_thread.h"

class FastShutdown : public UITest {
 protected:
  FastShutdown()
      : db_thread_(BrowserThread::DB),
        io_thread_(BrowserThread::IO),
        thread_helper_(new base::ThreadTestHelper(
            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB))) {
    dom_automation_enabled_ = true;
  }

  void Init() {
    ASSERT_TRUE(db_thread_.Start());
    ASSERT_TRUE(io_thread_.Start());
    // Cache this, so that we can still access it after the browser exits.
    user_data_dir_ = user_data_dir();
  }

  // Looks for the given |cookie| in the cookie store. If it exists, puts the
  // cookie's value in |cookie_value| and sets |has_cookie| to true. Sets
  // |has_cookie| to false if the |cookie| wasn't found.
  void GetCookie(const net::CookieMonster::CanonicalCookie& cookie,
                 bool* has_cookie, std::string* cookie_value) {
    scoped_refptr<SQLitePersistentCookieStore> cookie_store(
       new SQLitePersistentCookieStore(
           user_data_dir_.AppendASCII(chrome::kInitialProfile)
                         .Append(chrome::kCookieFilename)));
    std::vector<net::CookieMonster::CanonicalCookie*> cookies;
    ASSERT_TRUE(cookie_store->Load(
        base::Bind(&FastShutdown::LoadCookiesCallback,
                   base::Unretained(this),
                   MessageLoop::current(),
                   base::Unretained(&cookies))));
    // Will receive a QuitTask when LoadCookiesCallback is invoked.
    MessageLoop::current()->Run();
    *has_cookie = false;
    for (size_t i = 0; i < cookies.size(); ++i) {
      if (cookies[i]->IsEquivalent(cookie)) {
        *has_cookie = true;
        *cookie_value = cookies[i]->Value();
      }
    }
    cookie_store = NULL;
    ASSERT_TRUE(thread_helper_->Run());
    STLDeleteElements(&cookies);
  }

 private:
  void LoadCookiesCallback(
      MessageLoop* to_notify,
      std::vector<net::CookieMonster::CanonicalCookie*>* cookies,
      const std::vector<net::CookieMonster::CanonicalCookie*>& cookies_get) {
    *cookies = cookies_get;
    to_notify->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  BrowserThread db_thread_;
  BrowserThread io_thread_;
  scoped_refptr<base::ThreadTestHelper> thread_helper_;
  FilePath user_data_dir_;

  DISALLOW_COPY_AND_ASSIGN(FastShutdown);
};

// This tests for a previous error where uninstalling an onbeforeunload handler
// would enable fast shutdown even if an onunload handler still existed.
// Flaky on all platforms, http://crbug.com/89173
TEST_F(FastShutdown, FLAKY_SlowTermination) {
  Init();

  // Only the name, domain and path are used in IsEquivalent(), so we don't care
  // what the other fields have.
  net::CookieMonster::CanonicalCookie cookie(
      GURL(),        // url
      "unloaded",    // name
      "",            // value
      "",            // domain
      "/",           // path
      "",            // mac_key
      "",            // mac_algorithm
      base::Time(),  // creation
      base::Time(),  // expiration
      base::Time(),  // last_access
      false,         // secure
      false,         // httponly
      false);        // has_expires

  // This page has an unload handler.
  const FilePath dir(FILE_PATH_LITERAL("fast_shutdown"));
  const FilePath file(FILE_PATH_LITERAL("on_unloader.html"));

  NavigateToURL(ui_test_utils::GetTestUrl(dir, file));

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));

  // This page has a beforeunload handler.
  ASSERT_TRUE(browser->GetTab(0)->ExecuteJavaScript(
      "open('on_before_unloader.html')"));
  WaitUntilTabCount(2);

  // Close the tab, removing the one and only beforeunload handler.
  ASSERT_TRUE(browser->GetTab(1)->Close(true));

  // Close the browser. This should launch the unload handler, which sets a
  // cookie that's stored to disk.
  QuitBrowser();

  bool has_cookie = false;
  std::string cookie_value;
  // Read the cookie and check that it has the expected value.
  GetCookie(cookie, &has_cookie, &cookie_value);
  EXPECT_TRUE(has_cookie);
  EXPECT_EQ("ohyeah", cookie_value);
}
<|endoftext|>


<commit_before>/*$Id$
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 2000 Stefan Seefeld <stefan@fresco.org>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */
#ifndef _resolve_hh
#define _resolve_hh

#include <Fresco/Server.hh>
#include <Fresco/exception.hh>
#include <string>
#include <assert.h>
#include <Prague/Sys/GetOpt.hh>
#ifdef ORB_TAO
#include "orbsvcs/orbsvcs/CosNamingC.h"
#endif

template <class T>
typename T::_ptr_type resolve_init(CORBA::ORB_ptr orb, const char *name)
{
  CORBA::Object_var object;
  try
    {
      object = orb->resolve_initial_references(name);
    }
  catch (const CORBA::ORB::InvalidName &e)
    {
      std::cerr << "Invalid Name : " << name << std::endl;
      throw;
    }
  catch (const CORBA::Exception &e)
    {
      std::cerr << "Cannot get initial reference for " << name << ": " << e << std::endl;
      throw 0;
    }
  assert(!CORBA::is_nil(object));

  typename T::_var_type reference;
  try
    {
      reference = T::_narrow(object);
    }
  catch (const CORBA::Exception &e)
    {
      std::cerr << "Cannot downcast reference for " << name << ": " << e << std::endl;
      throw 0;
    }
  if (CORBA::is_nil(reference))
    {
      std::cerr << "Incorrect type of reference for " << name << std::endl;
      throw 0;
    }
  return reference._retn();
}

template <class T>
typename T::_ptr_type resolve_name(CosNaming::NamingContext_ptr context, const CosNaming::Name &name)
{
  CORBA::Object_var object;
  try
    {
      object = context->resolve(name);
    }
  catch (const CosNaming::NamingContext::NotFound &e)
    {
      throw;
    }
  catch (const CORBA::Exception &e)
    {
      std::cerr << "Cannot resolve binding: " << e << std::endl;
      throw 0;
    }
  if (CORBA::is_nil(object))
    {
      std::cerr << "Nil binding in Naming service" << std::endl;
      throw 0;
    }

  typename T::_var_type reference;
  try
    {
      reference = T::_narrow(object);
    }
  catch (const CORBA::Exception &e)
    {
      std::cerr << "Cannot narrow reference: " << e << std::endl;
      throw 0;
    }
  if (CORBA::is_nil(reference))
    {
      std::cerr << "Reference has incorrect type" << std::endl;
      throw 0;
    }
  return reference._retn();
}

template <class T>
typename T::_ptr_type resolve_name(CosNaming::NamingContext_ptr context, const char * name)
{
  CosNaming::Name cosname;
  cosname.length(1);
  cosname[0].id   = name;
  cosname[0].kind = "Object"; // string_dup ??
  return resolve_name<T>(context, cosname);
}

inline void bind_name(CORBA::ORB_ptr orb, CORBA::Object_ptr object, const char *name)
{
  CosNaming::NamingContext_var context = resolve_init<CosNaming::NamingContext>(orb, "NameService");
  CosNaming::Name cosname;
  cosname.length(1);
  cosname[0].id   = name;
  cosname[0].kind = "Object"; // string_dup ??
  context->rebind(cosname, object);
}

template <class T>
typename T::_ptr_type resolve_kit(Fresco::ServerContext_ptr context, const char *name, const Fresco::Kit::PropertySeq &props)
{
  CORBA::Object_ptr object;
  try
    {
      object = context->resolve(name, props);
    }
  catch(const CORBA::Exception &e)
    {
      std::cerr << "Cannot resolve reference for " << name << ": " << e << std::endl;
      return T::_nil();
    }
  typename T::_var_type reference;
  try
    {
      reference = T::_narrow(object);
    }
  catch (const CORBA::Exception &e)
    {
      std::cerr << "Cannot narrow reference: " << e << std::endl;
      throw 0;
    }
  if (CORBA::is_nil(reference))
    {
      std::cerr << "Reference has incorrect type" << std::endl;
      throw 0;
    }
  return reference._retn();
}

template <class T>
typename T::_ptr_type resolve_kit(Fresco::ServerContext_ptr context, const char *name)
{
  Fresco::Kit::PropertySeq empty;
  empty.length(0);
  return resolve_kit<T>(context, name, empty);
}

// -----------------------------------------------------------------------------
// Ways to find default settings for server-reference transfer
// -----------------------------------------------------------------------------
char const * default_reference_transfer_method();
char const * default_server_id();
char const * default_ior_file_path();

// -----------------------------------------------------------------------------
// Resolve server using strings directly
// -----------------------------------------------------------------------------

// resolve server using strings directly
Fresco::Server_ptr resolve_server(std::string server_id,
                                  std::string reference_transfer_method,
                                  std::string ior_file_path,
                                  CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Used to publish the server reference (call in order)
// -----------------------------------------------------------------------------

// check export_method is valid, and set method
void set_server_reference_export_method(std::string export_method);

// get poa to use for creating server
PortableServer::POA_ptr get_server_poa(CORBA::ORB_ptr orb,
                                       PortableServer::POA_ptr default_poa);

// publish server reference
void publish_server(Fresco::Server_ptr server,
                    std::string server_id,
                    std::string ior_file_path,
                    CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Un-publish the server reference (once server is finished)
// -----------------------------------------------------------------------------

void unpublish_server(CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Helpers if using external Prague::Getopt
// -----------------------------------------------------------------------------

// add server-publishing/resolving options to a getopt
void add_resolving_options_to_getopt(Prague::GetOpt &getopt);

// resolve server using getopt
Fresco::Server_ptr resolve_server(Prague::GetOpt const &getopt,
                                  CORBA::ORB_ptr orb);

// publish server using getopt
// NOTE: call set_server_reference_export_method and get_server_poa before this,
//       as with publish_server above.
void publish_server(Fresco::Server_ptr server,
                    Prague::GetOpt const &getopt,
                    CORBA::ORB_ptr orb);

#endif
<commit_msg>Tidy up to get more in line with coding standard & insert comments. (before hopefully extending the resolve-kit method as per task54)<commit_after>/*$Id$
 *
 * This source file is a part of the Fresco Project.
 * Copyright (C) 2000 Stefan Seefeld <stefan@fresco.org>
 * http://www.fresco.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */
#ifndef _resolve_hh
#define _resolve_hh

#include <Fresco/Server.hh>
#include <Fresco/exception.hh>
#include <string>
#include <assert.h>
#include <Prague/Sys/GetOpt.hh>
#ifdef ORB_TAO
#include "orbsvcs/orbsvcs/CosNamingC.h"
#endif

// -----------------------------------------------------------------------------
// Wrapper for resolving CORBA initial references
// -----------------------------------------------------------------------------
template <class T>
typename T::_ptr_type resolve_init(CORBA::ORB_ptr orb,
                                   char const * name)
{
    CORBA::Object_var object;
    try
    {
        object = orb->resolve_initial_references(name);
    }
    catch (const CORBA::ORB::InvalidName &e)
    {
        std::cerr << "Invalid Name : " << name << std::endl;
        throw;
    }
    catch (const CORBA::Exception &e)
    {
        std::cerr << "Cannot get initial reference for " << name << ": " << e
                  << std::endl;
        throw 0;
    }
    assert(!CORBA::is_nil(object));

    typename T::_var_type reference;
    try
    {
        reference = T::_narrow(object);
    }
    catch (const CORBA::Exception &e)
    {
        std::cerr << "Cannot downcast reference for " << name << ": " << e
                  << std::endl;
        throw 0;
    }
    if (CORBA::is_nil(reference))
    {
        std::cerr << "Incorrect type of reference for " << name << std::endl;
        throw 0;
    }
    return reference._retn();
}

// -----------------------------------------------------------------------------
// Wrappers for using the CORBA Nameservice
// -----------------------------------------------------------------------------
template <class T>
typename T::_ptr_type resolve_name(CosNaming::NamingContext_ptr context,
                                   CosNaming::Name const &name)
{
    CORBA::Object_var object;
    try
    {
        object = context->resolve(name);
    }
    catch (const CosNaming::NamingContext::NotFound &e)
    {
        // XXX: insert warning message here? -- neiljp
        throw;
    }
    catch (const CORBA::Exception &e)
    {
        std::cerr << "Cannot resolve binding: " << e << std::endl;
        throw 0;
    }
    if (CORBA::is_nil(object))
    {
        std::cerr << "Nil binding in Naming service" << std::endl;
        throw 0;
    }

    typename T::_var_type reference;
    try
    {
        reference = T::_narrow(object);
    }
    catch (const CORBA::Exception &e)
    {
        std::cerr << "Cannot narrow reference: " << e << std::endl;
        throw 0;
    }
    if (CORBA::is_nil(reference))
    {
        std::cerr << "Reference has incorrect type" << std::endl;
        throw 0;
    }
    return reference._retn();
}

template <class T>
typename T::_ptr_type resolve_name(CosNaming::NamingContext_ptr context,
                                   char const * name)
{
    CosNaming::Name cosname;
    cosname.length(1);
    cosname[0].id   = name;
    cosname[0].kind = "Object"; // string_dup ??
    return resolve_name<T>(context, cosname);
}

inline void bind_name(CORBA::ORB_ptr orb,
                      CORBA::Object_ptr object,
                      char const * name)
{
    CosNaming::NamingContext_var context =
      resolve_init<CosNaming::NamingContext>(orb, "NameService");
    CosNaming::Name cosname;
    cosname.length(1);
    cosname[0].id   = name;
    cosname[0].kind = "Object"; // string_dup ??
    context->rebind(cosname, object);
}

// -----------------------------------------------------------------------------
// Wrappers for resolving Fresco kits
// -----------------------------------------------------------------------------
template <class T>
typename T::_ptr_type resolve_kit(Fresco::ServerContext_ptr context,
                                  char const * name,
                                  Fresco::Kit::PropertySeq const &props)
{
    CORBA::Object_ptr object;
    try
    {
        object = context->resolve(name, props);
    }
    catch(const CORBA::Exception &e)
    {
        std::cerr << "Cannot resolve reference for " << name << ": " << e
                  << std::endl;
        return T::_nil();
    }
    typename T::_var_type reference;
    try
    {
        reference = T::_narrow(object);
    }
    catch (const CORBA::Exception &e)
    {
        std::cerr << "Cannot narrow reference: " << e << std::endl;
        throw 0;
    }
    if (CORBA::is_nil(reference))
    {
        std::cerr << "Reference has incorrect type" << std::endl;
        throw 0;
    }
    return reference._retn();
}

template <class T>
typename T::_ptr_type resolve_kit(Fresco::ServerContext_ptr context,
                                  char const * name)
{
    Fresco::Kit::PropertySeq empty;
    empty.length(0);
    return resolve_kit<T>(context, name, empty);
}

// -----------------------------------------------------------------------------
// Ways to find default settings for server-reference transfer
// -----------------------------------------------------------------------------
char const * default_reference_transfer_method();
char const * default_server_id();
char const * default_ior_file_path();

// -----------------------------------------------------------------------------
// Resolve server using strings directly
// -----------------------------------------------------------------------------

// resolve server using strings directly
Fresco::Server_ptr resolve_server(std::string server_id,
                                  std::string reference_transfer_method,
                                  std::string ior_file_path,
                                  CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Used to publish the server reference (call in order)
// -----------------------------------------------------------------------------

// check export_method is valid, and set method
void set_server_reference_export_method(std::string export_method);

// get poa to use for creating server
PortableServer::POA_ptr get_server_poa(CORBA::ORB_ptr orb,
                                       PortableServer::POA_ptr default_poa);

// publish server reference
void publish_server(Fresco::Server_ptr server,
                    std::string server_id,
                    std::string ior_file_path,
                    CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Un-publish the server reference (once server is finished)
// -----------------------------------------------------------------------------

void unpublish_server(CORBA::ORB_ptr orb);

// -----------------------------------------------------------------------------
// Helpers if using external Prague::Getopt
// -----------------------------------------------------------------------------

// add server-publishing/resolving options to a getopt
void add_resolving_options_to_getopt(Prague::GetOpt &getopt);

// resolve server using getopt
Fresco::Server_ptr resolve_server(Prague::GetOpt const &getopt,
                                  CORBA::ORB_ptr orb);

// publish server using getopt
// NOTE: call set_server_reference_export_method and get_server_poa before this,
//       as with publish_server above.
void publish_server(Fresco::Server_ptr server,
                    Prague::GetOpt const &getopt,
                    CORBA::ORB_ptr orb);

#endif
<|endoftext|>


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

#include "chrome/browser/google/google_update.h"

#include <atlbase.h>
#include <atlcom.h>

#include "base/bind.h"
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/threading/thread.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "content/public/browser/browser_thread.h"
#include "google_update/google_update_idl.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget.h"

using content::BrowserThread;

namespace {

// Check if the currently running instance can be updated by Google Update.
// Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
// Chrome distribution installed in a standard location.
GoogleUpdateErrorCode CanUpdateCurrentChrome(
    const FilePath& chrome_exe_path) {
#if !defined(GOOGLE_CHROME_BUILD)
  return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
#else
  // TODO(tommi): Check if using the default distribution is always the right
  // thing to do.
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
  FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
  if (!FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
                                        user_exe_path.value()) &&
      !FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
                                        machine_exe_path.value())) {
    LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
               << L"non-standard location: " << chrome_exe_path.value().c_str()
               << L". The standard location is: "
                   << user_exe_path.value().c_str()
               << L" or " << machine_exe_path.value().c_str() << L".";
    return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
  }

  string16 app_guid = installer::GetAppGuidForUpdates(
      !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
  DCHECK(!app_guid.empty());

  if (GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL) ==
      GoogleUpdateSettings::UPDATES_DISABLED)
    return GOOGLE_UPDATE_DISABLED_BY_POLICY;

  return GOOGLE_UPDATE_NO_ERROR;
#endif
}

// Creates an instance of a COM Local Server class using either plain vanilla
// CoCreateInstance, or using the Elevation moniker if running on Vista.
// hwnd must refer to a foregound window in order to get the UAC prompt
// showing up in the foreground if running on Vista. It can also be NULL if
// background UAC prompts are desired.
HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
                                HWND hwnd, void** interface_ptr) {
  if (!interface_ptr)
    return E_POINTER;

  // For Vista we need to instantiate the COM server via the elevation
  // moniker. This ensures that the UAC dialog shows up.
  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    wchar_t class_id_as_string[MAX_PATH] = {0};
    StringFromGUID2(class_id, class_id_as_string,
                    arraysize(class_id_as_string));

    string16 elevation_moniker_name =
        base::StringPrintf(L"Elevation:Administrator!new:%ls",
                           class_id_as_string);

    BIND_OPTS3 bind_opts;
    memset(&bind_opts, 0, sizeof(bind_opts));
    bind_opts.cbStruct = sizeof(bind_opts);
    bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
    bind_opts.hwnd = hwnd;

    return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
                       interface_id, reinterpret_cast<void**>(interface_ptr));
  }

  return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
                          interface_id,
                          reinterpret_cast<void**>(interface_ptr));
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
//
// The GoogleUpdateJobObserver COM class is responsible for receiving status
// reports from google Update. It keeps track of the progress as Google Update
// notifies us and ends the message loop we are spinning in once Google Update
// reports that it is done.
//
////////////////////////////////////////////////////////////////////////////////
class GoogleUpdateJobObserver
  : public CComObjectRootEx<CComSingleThreadModel>,
    public IJobObserver {
 public:
  BEGIN_COM_MAP(GoogleUpdateJobObserver)
    COM_INTERFACE_ENTRY(IJobObserver)
  END_COM_MAP()

  GoogleUpdateJobObserver()
    : result_(UPGRADE_ERROR) {
  }
  virtual ~GoogleUpdateJobObserver() {}

  // Notifications from Google Update:
  STDMETHOD(OnShow)() {
    return S_OK;
  }
  STDMETHOD(OnCheckingForUpdate)() {
    result_ = UPGRADE_CHECK_STARTED;
    return S_OK;
  }
  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
    result_ = UPGRADE_IS_AVAILABLE;
    new_version_ = version_string;
    return S_OK;
  }
  STDMETHOD(OnWaitingToDownload)() {
    return S_OK;
  }
  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
    return S_OK;
  }
  STDMETHOD(OnWaitingToInstall)() {
    return S_OK;
  }
  STDMETHOD(OnInstalling)() {
    result_ = UPGRADE_STARTED;
    return S_OK;
  }
  STDMETHOD(OnPause)() {
    return S_OK;
  }
  STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
    switch (code) {
      case COMPLETION_CODE_SUCCESS_CLOSE_UI:
      case COMPLETION_CODE_SUCCESS: {
        if (result_ == UPGRADE_STARTED)
          result_ = UPGRADE_SUCCESSFUL;
        else if (result_ == UPGRADE_CHECK_STARTED)
          result_ = UPGRADE_ALREADY_UP_TO_DATE;
        break;
      }
      case COMPLETION_CODE_ERROR:
        error_message_ = text;
      default: {
        NOTREACHED();
        result_ = UPGRADE_ERROR;
        break;
      }
    }

    event_sink_ = NULL;

    // We no longer need to spin the message loop that we started spinning in
    // InitiateGoogleUpdateCheck.
    MessageLoop::current()->Quit();
    return S_OK;
  }
  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
    event_sink_ = event_sink;
    return S_OK;
  }

  // Returns the results of the update operation.
  STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
    // Intermediary steps should never be reported to the client.
    DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);

    *result = result_;
    return S_OK;
  }

  // Returns which version Google Update found on the server (if a more
  // recent version was found). Otherwise, this will be blank.
  STDMETHOD(GetVersionInfo)(string16* version_string) {
    *version_string = new_version_;
    return S_OK;
  }

  // Returns the Google Update supplied error string that describes the error
  // that occurred during the update check/upgrade.
  STDMETHOD(GetErrorMessage)(string16* error_message) {
    *error_message = error_message_;
    return S_OK;
  }

 private:
  // The status/result of the Google Update operation.
  GoogleUpdateUpgradeResult result_;

  // The version string Google Update found.
  string16 new_version_;

  // An error message, if any.
  string16 error_message_;

  // Allows us control the upgrade process to a small degree. After OnComplete
  // has been called, this object can not be used.
  base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
};

////////////////////////////////////////////////////////////////////////////////
// GoogleUpdate, public:

GoogleUpdate::GoogleUpdate()
    : listener_(NULL) {
}

GoogleUpdate::~GoogleUpdate() {
}

////////////////////////////////////////////////////////////////////////////////
// GoogleUpdate, views::DialogDelegate implementation:

void GoogleUpdate::CheckForUpdate(bool install_if_newer,
                                  views::Widget* window) {
  // We need to shunt this request over to InitiateGoogleUpdateCheck and have
  // it run in the file thread.
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this,
                 install_if_newer, window, MessageLoop::current()));
}

////////////////////////////////////////////////////////////////////////////////
// GoogleUpdate, private:

void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
                                             views::Widget* window,
                                             MessageLoop* main_loop) {
  FilePath chrome_exe;
  if (!PathService::Get(base::DIR_EXE, &chrome_exe))
    NOTREACHED();

  GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
  if (error_code != GOOGLE_UPDATE_NO_ERROR) {
    main_loop->PostTask(
        FROM_HERE,
        base::Bind(&GoogleUpdate::ReportResults, this,
                   UPGRADE_ERROR, error_code, string16()));
    return;
  }

  CComObject<GoogleUpdateJobObserver>* job_observer;
  HRESULT hr =
      CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
  if (hr != S_OK) {
    // Most of the error messages come straight from Google Update. This one is
    // deemed worthy enough to also warrant its own error.
    string16 error_code = base::StringPrintf(L"0x%x", hr);
    ReportFailure(
        hr, GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED,
        l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_COCREATE_FAILED,
            error_code),
        main_loop);
    return;
  }

  base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);

  base::win::ScopedComPtr<IGoogleUpdate> on_demand;

  bool system_level = false;

  if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
    hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
  } else {
    // The Update operation needs Admin privileges for writing
    // to %ProgramFiles%. On Vista we need to elevate before instantiating
    // the updater instance.
    if (!install_if_newer) {
      hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
    } else {
      HWND foreground_hwnd = NULL;
      if (window != NULL) {
        foreground_hwnd = window->GetNativeWindow();
      }

      hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
          IID_IGoogleUpdate, foreground_hwnd,
          reinterpret_cast<void**>(on_demand.Receive()));
    }
    system_level = true;
  }

  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND,
                  string16(), main_loop);
    return;
  }

  string16 app_guid = installer::GetAppGuidForUpdates(system_level);
  DCHECK(!app_guid.empty());

  if (!install_if_newer)
    hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
  else
    hr = on_demand->Update(app_guid.c_str(), job_observer);

  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR,
                  string16(), main_loop);
    return;
  }

  // We need to spin the message loop while Google Update is running so that it
  // can report back to us through GoogleUpdateJobObserver. This message loop
  // will terminate once Google Update sends us the completion status
  // (success/error). See OnComplete().
  MessageLoop::current()->Run();

  GoogleUpdateUpgradeResult results;
  hr = job_observer->GetResult(&results);
  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_GET_RESULT_CALL_FAILED,
                  string16(), main_loop);
    return;
  }

  if (results == UPGRADE_ERROR) {
    string16 error_message;
    job_observer->GetErrorMessage(&error_message);
    ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop);
    return;
  }

  hr = job_observer->GetVersionInfo(&version_available_);
  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_GET_VERSION_INFO_FAILED,
                  string16(), main_loop);
    return;
  }

  main_loop->PostTask(
      FROM_HERE,
      base::Bind(&GoogleUpdate::ReportResults, this,
                 results, GOOGLE_UPDATE_NO_ERROR, string16()));
  job_holder = NULL;
  on_demand = NULL;
}

void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
                                 GoogleUpdateErrorCode error_code,
                                 const string16& error_message) {
  // If we get an error, then error code must not be blank, and vice versa.
  DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
                                    error_code == GOOGLE_UPDATE_NO_ERROR);
  if (listener_) {
    listener_->OnReportResults(
        results, error_code, error_message, version_available_);
  }
}

bool GoogleUpdate::ReportFailure(HRESULT hr,
                                 GoogleUpdateErrorCode error_code,
                                 const string16& error_message,
                                 MessageLoop* main_loop) {
  NOTREACHED() << "Communication with Google Update failed: " << hr
               << " error: " << error_code
               << ", message: " << error_message.c_str();
  main_loop->PostTask(
      FROM_HERE,
      base::Bind(&GoogleUpdate::ReportResults, this,
                 UPGRADE_ERROR, error_code, error_message));
  return false;
}
<commit_msg>google: Remove wrong comment about views::DialogDelegate implementation.<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/google/google_update.h"

#include <atlbase.h>
#include <atlcom.h>

#include "base/bind.h"
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/threading/thread.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "content/public/browser/browser_thread.h"
#include "google_update/google_update_idl.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget.h"

using content::BrowserThread;

namespace {

// Check if the currently running instance can be updated by Google Update.
// Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
// Chrome distribution installed in a standard location.
GoogleUpdateErrorCode CanUpdateCurrentChrome(
    const FilePath& chrome_exe_path) {
#if !defined(GOOGLE_CHROME_BUILD)
  return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
#else
  // TODO(tommi): Check if using the default distribution is always the right
  // thing to do.
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
  FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
  if (!FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
                                        user_exe_path.value()) &&
      !FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
                                        machine_exe_path.value())) {
    LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
               << L"non-standard location: " << chrome_exe_path.value().c_str()
               << L". The standard location is: "
                   << user_exe_path.value().c_str()
               << L" or " << machine_exe_path.value().c_str() << L".";
    return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
  }

  string16 app_guid = installer::GetAppGuidForUpdates(
      !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
  DCHECK(!app_guid.empty());

  if (GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL) ==
      GoogleUpdateSettings::UPDATES_DISABLED)
    return GOOGLE_UPDATE_DISABLED_BY_POLICY;

  return GOOGLE_UPDATE_NO_ERROR;
#endif
}

// Creates an instance of a COM Local Server class using either plain vanilla
// CoCreateInstance, or using the Elevation moniker if running on Vista.
// hwnd must refer to a foregound window in order to get the UAC prompt
// showing up in the foreground if running on Vista. It can also be NULL if
// background UAC prompts are desired.
HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
                                HWND hwnd, void** interface_ptr) {
  if (!interface_ptr)
    return E_POINTER;

  // For Vista we need to instantiate the COM server via the elevation
  // moniker. This ensures that the UAC dialog shows up.
  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    wchar_t class_id_as_string[MAX_PATH] = {0};
    StringFromGUID2(class_id, class_id_as_string,
                    arraysize(class_id_as_string));

    string16 elevation_moniker_name =
        base::StringPrintf(L"Elevation:Administrator!new:%ls",
                           class_id_as_string);

    BIND_OPTS3 bind_opts;
    memset(&bind_opts, 0, sizeof(bind_opts));
    bind_opts.cbStruct = sizeof(bind_opts);
    bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
    bind_opts.hwnd = hwnd;

    return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
                       interface_id, reinterpret_cast<void**>(interface_ptr));
  }

  return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
                          interface_id,
                          reinterpret_cast<void**>(interface_ptr));
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
//
// The GoogleUpdateJobObserver COM class is responsible for receiving status
// reports from google Update. It keeps track of the progress as Google Update
// notifies us and ends the message loop we are spinning in once Google Update
// reports that it is done.
//
////////////////////////////////////////////////////////////////////////////////
class GoogleUpdateJobObserver
  : public CComObjectRootEx<CComSingleThreadModel>,
    public IJobObserver {
 public:
  BEGIN_COM_MAP(GoogleUpdateJobObserver)
    COM_INTERFACE_ENTRY(IJobObserver)
  END_COM_MAP()

  GoogleUpdateJobObserver()
    : result_(UPGRADE_ERROR) {
  }
  virtual ~GoogleUpdateJobObserver() {}

  // Notifications from Google Update:
  STDMETHOD(OnShow)() {
    return S_OK;
  }
  STDMETHOD(OnCheckingForUpdate)() {
    result_ = UPGRADE_CHECK_STARTED;
    return S_OK;
  }
  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
    result_ = UPGRADE_IS_AVAILABLE;
    new_version_ = version_string;
    return S_OK;
  }
  STDMETHOD(OnWaitingToDownload)() {
    return S_OK;
  }
  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
    return S_OK;
  }
  STDMETHOD(OnWaitingToInstall)() {
    return S_OK;
  }
  STDMETHOD(OnInstalling)() {
    result_ = UPGRADE_STARTED;
    return S_OK;
  }
  STDMETHOD(OnPause)() {
    return S_OK;
  }
  STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
    switch (code) {
      case COMPLETION_CODE_SUCCESS_CLOSE_UI:
      case COMPLETION_CODE_SUCCESS: {
        if (result_ == UPGRADE_STARTED)
          result_ = UPGRADE_SUCCESSFUL;
        else if (result_ == UPGRADE_CHECK_STARTED)
          result_ = UPGRADE_ALREADY_UP_TO_DATE;
        break;
      }
      case COMPLETION_CODE_ERROR:
        error_message_ = text;
      default: {
        NOTREACHED();
        result_ = UPGRADE_ERROR;
        break;
      }
    }

    event_sink_ = NULL;

    // We no longer need to spin the message loop that we started spinning in
    // InitiateGoogleUpdateCheck.
    MessageLoop::current()->Quit();
    return S_OK;
  }
  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
    event_sink_ = event_sink;
    return S_OK;
  }

  // Returns the results of the update operation.
  STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
    // Intermediary steps should never be reported to the client.
    DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);

    *result = result_;
    return S_OK;
  }

  // Returns which version Google Update found on the server (if a more
  // recent version was found). Otherwise, this will be blank.
  STDMETHOD(GetVersionInfo)(string16* version_string) {
    *version_string = new_version_;
    return S_OK;
  }

  // Returns the Google Update supplied error string that describes the error
  // that occurred during the update check/upgrade.
  STDMETHOD(GetErrorMessage)(string16* error_message) {
    *error_message = error_message_;
    return S_OK;
  }

 private:
  // The status/result of the Google Update operation.
  GoogleUpdateUpgradeResult result_;

  // The version string Google Update found.
  string16 new_version_;

  // An error message, if any.
  string16 error_message_;

  // Allows us control the upgrade process to a small degree. After OnComplete
  // has been called, this object can not be used.
  base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
};

////////////////////////////////////////////////////////////////////////////////
// GoogleUpdate, public:

GoogleUpdate::GoogleUpdate()
    : listener_(NULL) {
}

GoogleUpdate::~GoogleUpdate() {
}

void GoogleUpdate::CheckForUpdate(bool install_if_newer,
                                  views::Widget* window) {
  // We need to shunt this request over to InitiateGoogleUpdateCheck and have
  // it run in the file thread.
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this,
                 install_if_newer, window, MessageLoop::current()));
}

////////////////////////////////////////////////////////////////////////////////
// GoogleUpdate, private:

void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
                                             views::Widget* window,
                                             MessageLoop* main_loop) {
  FilePath chrome_exe;
  if (!PathService::Get(base::DIR_EXE, &chrome_exe))
    NOTREACHED();

  GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
  if (error_code != GOOGLE_UPDATE_NO_ERROR) {
    main_loop->PostTask(
        FROM_HERE,
        base::Bind(&GoogleUpdate::ReportResults, this,
                   UPGRADE_ERROR, error_code, string16()));
    return;
  }

  CComObject<GoogleUpdateJobObserver>* job_observer;
  HRESULT hr =
      CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
  if (hr != S_OK) {
    // Most of the error messages come straight from Google Update. This one is
    // deemed worthy enough to also warrant its own error.
    string16 error_code = base::StringPrintf(L"0x%x", hr);
    ReportFailure(
        hr, GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED,
        l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_COCREATE_FAILED,
            error_code),
        main_loop);
    return;
  }

  base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);

  base::win::ScopedComPtr<IGoogleUpdate> on_demand;

  bool system_level = false;

  if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
    hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
  } else {
    // The Update operation needs Admin privileges for writing
    // to %ProgramFiles%. On Vista we need to elevate before instantiating
    // the updater instance.
    if (!install_if_newer) {
      hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
    } else {
      HWND foreground_hwnd = NULL;
      if (window != NULL) {
        foreground_hwnd = window->GetNativeWindow();
      }

      hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
          IID_IGoogleUpdate, foreground_hwnd,
          reinterpret_cast<void**>(on_demand.Receive()));
    }
    system_level = true;
  }

  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND,
                  string16(), main_loop);
    return;
  }

  string16 app_guid = installer::GetAppGuidForUpdates(system_level);
  DCHECK(!app_guid.empty());

  if (!install_if_newer)
    hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
  else
    hr = on_demand->Update(app_guid.c_str(), job_observer);

  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR,
                  string16(), main_loop);
    return;
  }

  // We need to spin the message loop while Google Update is running so that it
  // can report back to us through GoogleUpdateJobObserver. This message loop
  // will terminate once Google Update sends us the completion status
  // (success/error). See OnComplete().
  MessageLoop::current()->Run();

  GoogleUpdateUpgradeResult results;
  hr = job_observer->GetResult(&results);
  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_GET_RESULT_CALL_FAILED,
                  string16(), main_loop);
    return;
  }

  if (results == UPGRADE_ERROR) {
    string16 error_message;
    job_observer->GetErrorMessage(&error_message);
    ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop);
    return;
  }

  hr = job_observer->GetVersionInfo(&version_available_);
  if (hr != S_OK) {
    ReportFailure(hr, GOOGLE_UPDATE_GET_VERSION_INFO_FAILED,
                  string16(), main_loop);
    return;
  }

  main_loop->PostTask(
      FROM_HERE,
      base::Bind(&GoogleUpdate::ReportResults, this,
                 results, GOOGLE_UPDATE_NO_ERROR, string16()));
  job_holder = NULL;
  on_demand = NULL;
}

void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
                                 GoogleUpdateErrorCode error_code,
                                 const string16& error_message) {
  // If we get an error, then error code must not be blank, and vice versa.
  DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
                                    error_code == GOOGLE_UPDATE_NO_ERROR);
  if (listener_) {
    listener_->OnReportResults(
        results, error_code, error_message, version_available_);
  }
}

bool GoogleUpdate::ReportFailure(HRESULT hr,
                                 GoogleUpdateErrorCode error_code,
                                 const string16& error_message,
                                 MessageLoop* main_loop) {
  NOTREACHED() << "Communication with Google Update failed: " << hr
               << " error: " << error_code
               << ", message: " << error_message.c_str();
  main_loop->PostTask(
      FROM_HERE,
      base::Bind(&GoogleUpdate::ReportResults, this,
                 UPGRADE_ERROR, error_code, error_message));
  return false;
}
<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "TiffIFD.h"
#include "TiffParser.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

#ifdef CHECKSIZE
#undef CHECKSIZE
#endif

#define CHECKSIZE(A) if (A >= size) ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt")

TiffIFD::TiffIFD() {
  nextIFD = 0;
  endian = little;
}

TiffIFD::TiffIFD(FileMap* f, uint32 offset) {
  uint32 size = f->getSize();
  uint32 entries;
  endian = little;
  CHECKSIZE(offset);

  entries = *(unsigned short*)f->getData(offset);    // Directory entries in this IFD

  CHECKSIZE(offset + 2 + entries*4);
  for (uint32 i = 0; i < entries; i++) {
    TiffEntry *t = new TiffEntry(f, offset + 2 + i*12);

    if (t->tag == SUBIFDS || t->tag == EXIFIFDPOINTER || t->tag == DNGPRIVATEDATA || t->tag == MAKERNOTE || t->tag == 0x2e) {   // subIFD tag
      if (t->tag == DNGPRIVATEDATA) {
        try {
          TiffIFD *maker_ifd = parseDngPrivateData(t);
          mSubIFD.push_back(maker_ifd);
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable private data are added as entries
          mEntry[t->tag] = t;
        }
      } else if (t->tag == MAKERNOTE || t->tag == 0x2e) {
        try {
          mSubIFD.push_back(parseMakerNote(f, t->getDataOffset(), endian));
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable makernotes are added as entries
          mEntry[t->tag] = t;
        }
      } else {
        const unsigned int* sub_offsets = t->getIntArray();
        try {
          for (uint32 j = 0; j < t->count; j++) {
            mSubIFD.push_back(new TiffIFD(f, sub_offsets[j]));
          }
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable subifds are added as entries
          mEntry[t->tag] = t;
        }
      }
    } else {  // Store as entry
      mEntry[t->tag] = t;
    }
  }
  nextIFD = *(int*)f->getData(offset + 2 + entries * 12);
}

TiffIFD* TiffIFD::parseDngPrivateData(TiffEntry *t) {
  /*
  1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote),  indicating what sort of data is being stored here. Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above).
  6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification.
  */
  uint32 size = t->count;
  const uchar8 *data = t->getData();
  string id((const char*)data);
  if (id.compare("Adobe"))
    ThrowTPE("Not Adobe Private data");

  data+=6;
  if (!(data[0] == 'M' && data[1] == 'a' && data[2] == 'k' &&data[3] == 'N' ))
    ThrowTPE("Not Makernote");

  data+=4;
  uint32 count;
  if (big == getHostEndianness())
    count = *(uint32*)data;
  else
    count = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

  data+=4;
  CHECKSIZE(count);
  Endianness makernote_endian = unknown;
  if (data[0] == 0x49 && data[1] == 0x49)
    makernote_endian = little;
  else if (data[0] == 0x4D && data[1] == 0x4D)
    makernote_endian = big;
  else
    ThrowTPE("Cannot determine endianess of DNG makernote");

  data+=2;
  uint32 org_offset;

  if (big == getHostEndianness())
    org_offset = *(uint32*)data;
  else
    org_offset = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

  data+=4;
  /* Create fake tiff with original offsets */
  uchar8* maker_data = new uchar8[org_offset+count];
  memcpy(&maker_data[org_offset],data, count);
  FileMap *maker_map = new FileMap(maker_data, org_offset+count);

  TiffIFD *maker_ifd;
  try {
    maker_ifd = parseMakerNote(maker_map, org_offset, makernote_endian);
  } catch (TiffParserException e) {
    delete[] maker_data;
    delete maker_map;
    throw e;
  }
  delete[] maker_data;
  delete maker_map;
  return maker_ifd;
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffIFD* TiffIFD::parseMakerNote(FileMap *f, uint32 offset, Endianness parent_end)
{
  uint32 size = f->getSize();
  CHECKSIZE(offset + 20);
  TiffIFD *maker_ifd = NULL;
  const uchar8* data = f->getData(offset);

  // Pentax makernote starts with AOC\0 - If it's there, skip it
  if (data[0] == 0x41 && data[1] == 0x4f && data[2] == 0x43 && data[3] == 0)
  {
    data +=4;
    offset +=4;
  }

  // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
  // This TIFF is 0 offset based
  if (data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66)
  {
    parent_end = getTiffEndianness((const ushort16*)&data[12]);
    if (parent_end == unknown)
      ThrowTPE("Cannot determine Panasonic makernote endianness");
    data +=20;
    offset +=20;
  }

  // Some have MM or II to indicate endianness - read that
  if (data[0] == 0x49 && data[1] == 0x49) {
    offset +=2;
    parent_end = little;
  } else if (data[0] == 0x4D && data[1] == 0x4D) {
    parent_end = big;
    offset +=2;
  }

  // Attempt to parse the rest as an IFD
  if (parent_end == getHostEndianness())
    maker_ifd = new TiffIFD(f, offset);
  else
    maker_ifd = new TiffIFDBE(f, offset);

  // If the structure cannot be read, a TiffParserException will be thrown.
  return maker_ifd;
}

TiffIFD::~TiffIFD(void) {
  for (map<TiffTag, TiffEntry*>::iterator i = mEntry.begin(); i != mEntry.end(); ++i) {
    delete((*i).second);
  }
  mEntry.clear();
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    delete(*i);
  }
  mSubIFD.clear();
}

bool TiffIFD::hasEntryRecursive(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end())
    return TRUE;
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    if ((*i)->hasEntryRecursive(tag))
      return TRUE;
  }
  return false;
}

vector<TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) {
  vector<TiffIFD*> matchingIFDs;
  if (mEntry.find(tag) != mEntry.end()) {
    matchingIFDs.push_back(this);
  }
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    vector<TiffIFD*> t = (*i)->getIFDsWithTag(tag);
    for (uint32 j = 0; j < t.size(); j++) {
      matchingIFDs.push_back(t[j]);
    }
  }

  return matchingIFDs;
}

TiffEntry* TiffIFD::getEntryRecursive(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end()) {
    return mEntry[tag];
  }
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    TiffEntry* entry = (*i)->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return NULL;
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end()) {
    return mEntry[tag];
  }
  ThrowTPE("TiffIFD: TIFF Parser entry 0x%x not found.", tag);
  return 0;
}

bool TiffIFD::hasEntry(TiffTag tag) {
  return mEntry.find(tag) != mEntry.end();
}

} // namespace RawSpeed
<commit_msg>We don't parse original makernotes that are placed after 300MB mark in the original file.<commit_after>#include "StdAfx.h"
#include "TiffIFD.h"
#include "TiffParser.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

#ifdef CHECKSIZE
#undef CHECKSIZE
#endif

#define CHECKSIZE(A) if (A >= size) ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt")

TiffIFD::TiffIFD() {
  nextIFD = 0;
  endian = little;
}

TiffIFD::TiffIFD(FileMap* f, uint32 offset) {
  uint32 size = f->getSize();
  uint32 entries;
  endian = little;
  CHECKSIZE(offset);

  entries = *(unsigned short*)f->getData(offset);    // Directory entries in this IFD

  CHECKSIZE(offset + 2 + entries*4);
  for (uint32 i = 0; i < entries; i++) {
    TiffEntry *t = new TiffEntry(f, offset + 2 + i*12);

    if (t->tag == SUBIFDS || t->tag == EXIFIFDPOINTER || t->tag == DNGPRIVATEDATA || t->tag == MAKERNOTE || t->tag == 0x2e) {   // subIFD tag
      if (t->tag == DNGPRIVATEDATA) {
        try {
          TiffIFD *maker_ifd = parseDngPrivateData(t);
          mSubIFD.push_back(maker_ifd);
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable private data are added as entries
          mEntry[t->tag] = t;
        }
      } else if (t->tag == MAKERNOTE || t->tag == 0x2e) {
        try {
          mSubIFD.push_back(parseMakerNote(f, t->getDataOffset(), endian));
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable makernotes are added as entries
          mEntry[t->tag] = t;
        }
      } else {
        const unsigned int* sub_offsets = t->getIntArray();
        try {
          for (uint32 j = 0; j < t->count; j++) {
            mSubIFD.push_back(new TiffIFD(f, sub_offsets[j]));
          }
          delete(t);
        } catch (TiffParserException e) {
          // Unparsable subifds are added as entries
          mEntry[t->tag] = t;
        }
      }
    } else {  // Store as entry
      mEntry[t->tag] = t;
    }
  }
  nextIFD = *(int*)f->getData(offset + 2 + entries * 12);
}

TiffIFD* TiffIFD::parseDngPrivateData(TiffEntry *t) {
  /*
  1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote),  indicating what sort of data is being stored here. Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above).
  6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification.
  */
  uint32 size = t->count;
  const uchar8 *data = t->getData();
  string id((const char*)data);
  if (id.compare("Adobe"))
    ThrowTPE("Not Adobe Private data");

  data+=6;
  if (!(data[0] == 'M' && data[1] == 'a' && data[2] == 'k' &&data[3] == 'N' ))
    ThrowTPE("Not Makernote");

  data+=4;
  uint32 count;
  if (big == getHostEndianness())
    count = *(uint32*)data;
  else
    count = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

  data+=4;
  CHECKSIZE(count);
  Endianness makernote_endian = unknown;
  if (data[0] == 0x49 && data[1] == 0x49)
    makernote_endian = little;
  else if (data[0] == 0x4D && data[1] == 0x4D)
    makernote_endian = big;
  else
    ThrowTPE("Cannot determine endianess of DNG makernote");

  data+=2;
  uint32 org_offset;

  if (big == getHostEndianness())
    org_offset = *(uint32*)data;
  else
    org_offset = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

  data+=4;
  /* We don't parse original makernotes that are placed after 300MB mark in the original file */
  if (org_offset+count > 300*1024*1024)
    ThrowTPE("Adobe Private data: original offset of makernote is past 300MB offset");

  /* Create fake tiff with original offsets */
  uchar8* maker_data = new uchar8[org_offset+count];
  memcpy(&maker_data[org_offset],data, count);
  FileMap *maker_map = new FileMap(maker_data, org_offset+count);

  TiffIFD *maker_ifd;
  try {
    maker_ifd = parseMakerNote(maker_map, org_offset, makernote_endian);
  } catch (TiffParserException e) {
    delete[] maker_data;
    delete maker_map;
    throw e;
  }
  delete[] maker_data;
  delete maker_map;
  return maker_ifd;
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffIFD* TiffIFD::parseMakerNote(FileMap *f, uint32 offset, Endianness parent_end)
{
  uint32 size = f->getSize();
  CHECKSIZE(offset + 20);
  TiffIFD *maker_ifd = NULL;
  const uchar8* data = f->getData(offset);

  // Pentax makernote starts with AOC\0 - If it's there, skip it
  if (data[0] == 0x41 && data[1] == 0x4f && data[2] == 0x43 && data[3] == 0)
  {
    data +=4;
    offset +=4;
  }

  // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
  // This TIFF is 0 offset based
  if (data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66)
  {
    parent_end = getTiffEndianness((const ushort16*)&data[12]);
    if (parent_end == unknown)
      ThrowTPE("Cannot determine Panasonic makernote endianness");
    data +=20;
    offset +=20;
  }

  // Some have MM or II to indicate endianness - read that
  if (data[0] == 0x49 && data[1] == 0x49) {
    offset +=2;
    parent_end = little;
  } else if (data[0] == 0x4D && data[1] == 0x4D) {
    parent_end = big;
    offset +=2;
  }

  // Attempt to parse the rest as an IFD
  if (parent_end == getHostEndianness())
    maker_ifd = new TiffIFD(f, offset);
  else
    maker_ifd = new TiffIFDBE(f, offset);

  // If the structure cannot be read, a TiffParserException will be thrown.
  return maker_ifd;
}

TiffIFD::~TiffIFD(void) {
  for (map<TiffTag, TiffEntry*>::iterator i = mEntry.begin(); i != mEntry.end(); ++i) {
    delete((*i).second);
  }
  mEntry.clear();
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    delete(*i);
  }
  mSubIFD.clear();
}

bool TiffIFD::hasEntryRecursive(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end())
    return TRUE;
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    if ((*i)->hasEntryRecursive(tag))
      return TRUE;
  }
  return false;
}

vector<TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) {
  vector<TiffIFD*> matchingIFDs;
  if (mEntry.find(tag) != mEntry.end()) {
    matchingIFDs.push_back(this);
  }
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    vector<TiffIFD*> t = (*i)->getIFDsWithTag(tag);
    for (uint32 j = 0; j < t.size(); j++) {
      matchingIFDs.push_back(t[j]);
    }
  }

  return matchingIFDs;
}

TiffEntry* TiffIFD::getEntryRecursive(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end()) {
    return mEntry[tag];
  }
  for (vector<TiffIFD*>::iterator i = mSubIFD.begin(); i != mSubIFD.end(); ++i) {
    TiffEntry* entry = (*i)->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return NULL;
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) {
  if (mEntry.find(tag) != mEntry.end()) {
    return mEntry[tag];
  }
  ThrowTPE("TiffIFD: TIFF Parser entry 0x%x not found.", tag);
  return 0;
}

bool TiffIFD::hasEntry(TiffTag tag) {
  return mEntry.find(tag) != mEntry.end();
}

} // namespace RawSpeed
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2015 VoltDB Inc.
 *
 * This file contains original code and/or modifications of original code.
 * Any modifications made by VoltDB Inc. are licensed under the following
 * terms and conditions:
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/* Copyright (C) 2008 by H-Store Project
 * Brown University
 * Massachusetts Institute of Technology
 * Yale University
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
#include <iostream>
#include <limits.h>
#include "harness.h"

#include "expressions/abstractexpression.h"
#include "expressions/expressions.h"
#include "common/common.h"
#include "common/valuevector.h"
#include "common/ValueFactory.hpp"
#include "common/types.h"
#include "common/ValuePeeker.hpp"
#include "common/PlannerDomValue.h"
#include "common/NValue.hpp"
#include "expressions/expressions.h"
#include "expressions/expressionutil.h"
#include "expressions/functionexpression.h"
#include "expressions/constantvalueexpression.h"

using namespace voltdb;

struct FunctionTest : public Test {
        FunctionTest() :
                Test(),
                m_executorContext(new ExecutorContext(0,
                                                      0,
                                                      (UndoQuantum *)0,
                                                      (Topend *)0,
                                                      new Pool(),
                                                      (VoltDBEngine *)0,
                                                      "localhost",
                                                      0,
                                                      (DRTupleStream *)0,
                                                      (DRTupleStream *)0)) {}
        ~FunctionTest() {
                delete m_executorContext;
        }
        ExecutorContext *m_executorContext;
};

static int testBin(uint64_t input, std::string output) {
        std::vector<AbstractExpression *> *argument = new std::vector<AbstractExpression *>();
        ConstantValueExpression *const_val_exp = new ConstantValueExpression(ValueFactory::getBigIntValue(0xffULL));
        argument->push_back(const_val_exp);
        NValue expected = ValueFactory::getTempStringValue("11111111");
    AbstractExpression* bin_exp = ExpressionUtil::functionFactory(FUNC_VOLT_BIN, argument);
    NValue answer = bin_exp->eval();
    int cmpout = answer.compare(expected);
    expected.free();
    delete bin_exp;
    // std::cout << "input: " << std::hex << input << " vs. " << output << " == " << cmpout << "\n";
    return cmpout;
}

TEST_F(FunctionTest, BinTest) {
        ASSERT_EQ(testBin(0xffULL, "11111111"), 0);
        ASSERT_EQ(testBin(0ULL, "0"), 0);
        const size_t BIGINT_SIZE = sizeof(uint64_t) * CHAR_BIT;
        // Walking ones.
        std::string expected("1");
        std::string expectedz("1111111111111111111111111111111111111111111111111111111111111111");
        for (int idx = 0; idx < (BIGINT_SIZE-1); idx += 1) {
                uint64_t input = 1ULL << idx;
                ASSERT_EQ(testBin(input, expected), 0);
                expected = expected + "0";
                expectedz[idx] = '0';
                ASSERT_EQ(testBin(~input, expectedz), 0);
                expectedz[idx] = '1';
        }
}

int main() {
     return TestSuite::globalInstance()->runAll();
}
<commit_msg>Fixed a memory leak.  Apparently I didn't understand the ownership rules for temp string pools.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2015 VoltDB Inc.
 *
 * This file contains original code and/or modifications of original code.
 * Any modifications made by VoltDB Inc. are licensed under the following
 * terms and conditions:
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/* Copyright (C) 2008 by H-Store Project
 * Brown University
 * Massachusetts Institute of Technology
 * Yale University
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
#include <iostream>
#include <limits.h>
#include "harness.h"

#include "expressions/abstractexpression.h"
#include "expressions/expressions.h"
#include "common/common.h"
#include "common/valuevector.h"
#include "common/ValueFactory.hpp"
#include "common/types.h"
#include "common/ValuePeeker.hpp"
#include "common/PlannerDomValue.h"
#include "common/NValue.hpp"
#include "expressions/expressions.h"
#include "expressions/expressionutil.h"
#include "expressions/functionexpression.h"
#include "expressions/constantvalueexpression.h"

using namespace voltdb;

struct FunctionTest : public Test {
        FunctionTest() :
                Test(),
                m_pool(new Pool()),
                m_executorContext(new ExecutorContext(0,
                                                      0,
                                                      (UndoQuantum *)0,
                                                      (Topend *)0,
                                                      m_pool,
                                                      (VoltDBEngine *)0,
                                                      "localhost",
                                                      0,
                                                      (DRTupleStream *)0,
                                                      (DRTupleStream *)0)) {}
        ~FunctionTest() {
                delete m_pool;
                delete m_executorContext;
        }
        Pool            *m_pool;
        ExecutorContext *m_executorContext;
};

static int testBin(uint64_t input, std::string output) {
        std::vector<AbstractExpression *> *argument = new std::vector<AbstractExpression *>();
        ConstantValueExpression *const_val_exp = new ConstantValueExpression(ValueFactory::getBigIntValue(0xffULL));
        argument->push_back(const_val_exp);
        NValue expected = ValueFactory::getTempStringValue("11111111");
    AbstractExpression* bin_exp = ExpressionUtil::functionFactory(FUNC_VOLT_BIN, argument);
    NValue answer = bin_exp->eval();
    int cmpout = answer.compare(expected);
    expected.free();
    delete bin_exp;
    // std::cout << "input: " << std::hex << input << " vs. " << output << " == " << cmpout << "\n";
    return cmpout;
}

TEST_F(FunctionTest, BinTest) {
        ASSERT_EQ(testBin(0xffULL, "11111111"), 0);
        ASSERT_EQ(testBin(0ULL, "0"), 0);
        const size_t BIGINT_SIZE = sizeof(uint64_t) * CHAR_BIT;
        // Walking ones.
        std::string expected("1");
        std::string expectedz("1111111111111111111111111111111111111111111111111111111111111111");
        for (int idx = 0; idx < (BIGINT_SIZE-1); idx += 1) {
                uint64_t input = 1ULL << idx;
                ASSERT_EQ(testBin(input, expected), 0);
                expected = expected + "0";
                expectedz[idx] = '0';
                ASSERT_EQ(testBin(~input, expectedz), 0);
                expectedz[idx] = '1';
        }
}

int main() {
     return TestSuite::globalInstance()->runAll();
}
<|endoftext|>